[索引]
Mathクラス |
Stringクラス |
Integerクラス |
その他のラッパークラス |
ArrayListクラス |
その他のコレクションフレームワーク
Javaには多くのクラスライブラリが用意されています。 もとより、クラスライブラリをすべて覚える必要はありません。 必要に応じて仕様書(注)を参照すれば良いのです。 しかしどんなものがあるかくらいは知っている必要があります。 ライブラリに用意されているメソッドを自分で作ってしまうほど、つまらないことはありません。 ここでは、特に重要なクラスに限り、そのまたさらに一部の仕様だけ説明します。
(注)インターネットが使えれば、Javaの仕様書は容易に参照できます。 例えば Google で「Math java」などとキーワードを入力し、「日本語のページを検索」を選択してI'm feeling Luckyをクリックすると、Mathクラスの仕様書(javadoc)が表示されます。 この仕様書にはMathクラスで使えるメソッドの一覧と使い方(パラメーター群)が記述されています。
Mathクラスは、指数関数、対数関数、平方根、および三角関数といった基本的な数値処理を実行するためのメソッドを含んでいます。 Mathクラスのメソッドはすべてstaticメソッドなので、new文でインスタンスを生成すること無しに使用できます。
double a = Math.sqrt(2); // aには2の平方根の値が入ります
以下の例では、y と z がint型なら x もint型となり、double型なら x もdouble型になります。 int型とdouble型とでは、異なるプログラムが実行されますが、オーバーロードの機能によって実行するプログラムが選択されるわけです。 maxにはこの他にlong型とfloat型の演算もあります。
x = Math.max(y, z);
Stringクラスはこれまで何度も出てきました。 Stringクラスには多数のメソッドがありますが、それらのうち、ごく一部の良く使われるメソッドを示します。
String substring(int start)
文字列のstartの位置(先頭0)から最後までの文字列を切り出して返します。
★String substring(int start, int end)
文字列のstartの位置(先頭0)からend-1までの文字列を切り出して返します。
int indexOf(String str)
文字列の中でstrと一致する文字列が(最初に)存在する位置を返します。
文字列が存在しない場合は-1を返します。
int length()
文字列の長さを返します。
Javaでは全文字が16ビットなので半角/全角の区別はありません。
使用例
String s = "ABCDEF";
s = s.substring(2,5) // sは"CDE"
Stringクラスでは一度作成した文字列の中身を変更することができません。 前述の使用例の s は"ABCDEF"から"CDE"に変更していると思われるかもしれませんが、これは一度作った"ABCDEF"を捨て、新たな領域を確保して、そこに"CDE"をセットし、そのアドレスを s にセットしているのです。 捨てられた"ABCDEF"はガベージコレクションの機能により、自動的にメモリ領域に返却されます。
また内容が同じ場合は値を共有します。 例えば以下の場合は、"ABC"の実体は1つしか作らず、s1とs2が(アドレスとして)同じ値になります。
String s1 = "ABC";
String s2 = "ABC";
2章で説明したようにStringは参照型で変数には文字列ではなく、文字列へのアドレスが格納されているのでした。 このような参照型の変数には以下の 01: のようにnullを代入することができます。 nullはtrueやfalseとともに、Java言語で定義されている特別な値で(1章の予約語リスト参照)、nullリテラルと呼ばれることがあります。
01: String s = null; 02: System.out.println(s); // nullと出力される 03: s = s.substring(1,3);
01: のようにすると s はメモリ上に場所だけは確保されるのですが、その場所には実効的なアドレスは格納されず、どこもポイントしていない状態になります。 この状態で 02: のように s を出力するとnullと出力されます。 s に文字列"null"が代入されているときと、出力結果は同じですが、状況は違うので注意してください。
またこの状態で 03: のようにStringクラスのメソッドを実行しようとすると、NullPointerExceptionという例外が発生します。 実際のプログラムではこの例外がよく発生し、初心者のJavaプログラマーを悩ませます。 nullリテラルは参照型に代入できるので、String型だけでなく、配列やその他のすべてのクラスから作成したインスタンスに代入できます。 これらにnullリテラルを代入すると、インスタンスの利用終了とみなされ、ガベージコレクションの対象になります。 したがって、使い終わったインスタンスに積極的にnullを代入すると、メモリの効果的な利用が図れます。
Stringクラスでは一度作成した文字列の中身の変更ができないので、文字列を変更するような場合には、StringBufferクラスを使う方が良いでしょう。 StringBufferクラスでは初めから値の変更を見越して、初期化された値より大きな値がメモリ領域に確保されてしまいます。 したがって値の変更がないのであればStringBufferクラスを使用すべきではありません。
StringBufferクラスには、文字列の追加(append)、削除(delete)、指定位置への挿入(insert)、置き換え(replace)など、多数のメソッドが用意されています。
strの内容が"dog cat rabbit"のとき、以下のプログラムを実行するとstr1とstr2はそれぞれどうなりますか。
String str1 = str.substring(0, str.indexOf(" "));
String str2 = str.substring(str.indexOf(" ")+1);
※ このような文字列操作に威力を発揮するStringTokenizerクラスがあります。
Javaには32ビット整数を扱うデータ型としてint型の他にIntegerという型(クラス)があります。 Integerクラスはint型の数値を1つだけ変数として持つとともに、int型の計算に役立つメソッドを備えています。 これはint型のデータをラップ(wrap:包み込む)していると言う意味でラッパークラスと呼ばれます。 以下にIntegerクラスの主要なコンストラクタとメソッドを示します。 Integerクラスのメソッドにはstaticメソッドとインスタンスメソッドとがあります。
コンストラクタ
Integer(int i)
整数値iをInteger型に変換する。
メソッド
static Integer valueOf(String s)
文字列sを10進数と見なしてInteger型に変換する。
数字に変換できないとNumberFormatExceptionという例外を発行する。
★static int parseInt(String s)
文字列sを10進数と見なしてint型に変換する。
数字に変換できないとNumberFormatExceptionという例外を発行する。
int intValue()
Integer型の数値をint型に変換する。
以下に使用例を示します。 staticメソッドはInteger.xxxと書き、インスタンスメソッドはインスタンス名.yyyと書くことに注意してください。 01: はコンストラクタの例です。 02: をまとめて 03: のように書けます。 またparseIntメソッドを使えば、02: や 03: のような処理が 04: のように一度で書けます。 parseとは構文解析をすると言う意味です。
01: Integer obj = New Integer(123);
02: String s ="123";
Integer obj = Integer.valueOf(s);
int i = obj.intValue();
03: String s ="123";
int i = Integer.valueOf(s).intValue();
04: String s ="123";
int i = Integer.parseInt(s);
※ 最新のJ2SE5.0ではAutoboxing/Unboxingと言う機能が導入され、01: のコンストラクタや、02: のintValueを書かなくてもよくなりました。 実際、01: はInteger obj = 123;と書け、02: の3行目はint i = obj;と書けるのです。 しかし当面はまだ多くの方が旧版を使う機会の方が多いと考え、ここでは、旧版の仕様で説明しています。
コマンドラインから2つの数字を受け取り、その和を表示するプログラムを作成してください。
(ヒント) コマンドラインからのパラメーターはargsで受け取るのでした。
ここではargsで受け取ったString型のパラメーターを数字(int型)に変換するのがポイントです。
ラッパークラスはint型だけでなく、すべての基本データ型に対するものがあります。 それを全部挙げると、Boolean、Byte、Character、Double、Float、Long、Shortとなります。 CharacterとIntegerはフルスペルになります。 その他は先頭が大文字になっただけでつづりは同じです。 これらにもそれぞれの数値の処理に役立つメソッド群が用意されています。
次項に述べるArrayListなどのコレクションクラスは、基本データ型のデータを格納できません。 参照型のデータしか格納できないのです。 そこで整数値をこれらに格納するときは、ラッパークラスにして格納します。 またラッパークラスは10進→16進変換など基数の変換などのメソッドも備えています。
複数のデータを扱う時には配列が便利でした。 しかし配列は初期化時に指定したサイズを変更することができません。 また、配列の並びの途中に新たなデータを挿入するのはかなり大変です。 このような問題を解決するためにJavaではコレクションフレームワークと言う便利なクラス群が用意されています。 これを使うとデータを様々な構成でグルーピングすることができます。
ArrayListは代表的なコレクションフレームワークです。 ArrayListはサイズが変更できる配列といえます。 生成時に一定サイズを確保し、その後、要素の追加に応じてサイズを自動的に拡張します。 ArrayListでは、データの追加(add)、取得(get)、検索(indexOf)、削除(remove)、置換(set)などの操作が可能です。
ArrayListクラスではObject型のデータを格納します。 すべてのクラスはObject型(のサブクラス)ですから、ArrayListにはString型や独自に作ったクラスなど、すべての参照型のデータが格納できます。 しかし、int型など基本データ型のデータは直接は格納できません。 基本データ型はラッパークラスして格納します(後述の例 03: や 04: を参照)。
また、ArrayListに格納するとすべてObject型になってしまうので、取り出すときには、元の型へのキャストが必要です(後述の例 06: 参照)。 ★
※ 最新のJ2SE5.0ではGeneric Typesを使って格納する型を宣言しておくと、いちいちキャストしなくてよくなりました。 しかし、まだ旧版の利用も多いという理由で、ここでは旧版の仕様で説明しています。
ArrayListの使い方を例で示します。 ArrayListクラスはjava.utilパッケージ内にあるのでjava.util.*;をimportしておく必要があります。
01: ArrayList ar = new ArrayList(); // ArrayListクラスのオブジェクトar生成
02: ar.add("aaa"); // addメソッドでarの末尾に追加して行く
03: ar.add(new Integer(5)); // 数値5は格納でないなのでラップする
04: ar.add(new Double(-2.3)); // これもラップする
05: System.out.println(ar); // [aaa, 5, -2.3]が出力される
06: String s = (String)ar.get(0); // 読み出す時はキャストが必須。sはaaa
数値はラッパークラスにして格納していること(03: と 04:)、および読み出し時にキャストしていること(06:)に注目してください。 またString型はnewしなくてもよい(2章の参照型の項参照)ことを思い出してください(02:)。
※ この例は異なる型のデータをaddしていますが、これはArrayListの機能の説明のための例であり、実用上は同じ型のデータを格納することが多いでしょう。 この例のように様々な型を格納したら、別途それぞれの型を覚えておく必要があります。
ArrayListとほぼ同じ機能を果たすクラスにVectorクラスがあります。 VectorクラスはJavaの旧版から存在しているクラスです。 ArrayListとの違いはVectorが同期化の処理を行うことです。 同期化の処理が行われると、複数のスレッド(多重処理のこと:10章で説明)から同時に操作されても、データの整合性を保つことができます。 これは一見良いことのように思えますが、不要な場合でも必ず同期化を行うため、性能が低下します。 必要に応じて選択してください。
コレクションフレームワークにはArrayListやVectorの他にも多くのクラスがあります。 ここではその中で主なものを紹介します。
LinkedListはArrayListと同じように、順序データを管理しますが、次のような違いがあります。 すなわち、ArrayListはデータの追加や削除が列の末尾を除いて得意でないのに対し、LinkedListは列の先頭へのデータの挿入、削除も得意です。
逆にArrayListは位置(index)を指定してのデータの取り出しが高速なのに対し、LinkedListは、これが苦手です。 それは、LinkedListはその名の通りLink構造になっているからです。 LinkedListでは、データの登録(add、addFirst、addLast)、取得(get、getFirst、getLast)、登録確認(contains)、検索(indexOf)、削除(remove)、置換(set)などの操作が可能です。
LinkedListの使い方を例で示します。 LinkedListクラスもjava.utilパッケージ内にあるのでjava.util.*;をimportしておく必要があります。 LinkedListでも格納できるのはObject型だけです。
01: LinkedList lk = new LinkedList();
02: lk.add("aaa");
03: lk.add("bbb");
04: lk.addFirst("ccc");
05: lk.addFirst("ddd");
06: String sf = (String)lk.getFirst(); // sfはdddになる
07: String sl = (String)lk.getLast(); // slはbbbになる
HashMapクラスにはキー(key)と値(value)とがペアで格納できます。 HashMapでは、データの登録(put)、値の取得(get)、登録確認(containsKey)、削除(remove)などの操作が可能です。 HashMapでも格納できるのは(キー、値ともに)Object型だけです。
hashにはごちゃ混ぜにするという意味があります。 mapは地図ですが、その他に数学でいう写像とか関数の意味があります。 すなわち、HashMapという名は、データを登録順序にこだわらずに並べ、キーから値への関数として管理する方式を表わしています。
HashMapの使い方を例で示します。 HashMapクラスもjava.utilパッケージ内にあるのでjava.util.*;をimportしておく必要があります。 すでに登録されているキーが再度登録されると、新しい値(value)が古い値に上書きされます。
01: HashMap hm = new HashMap();
02: hm.put("one", "onett");
03: hm.put("two", "twoson");
04: hm.put("one", "threek"); // 当初のonettは上書きされ消えてしまう
05: String s = (String)hm.get("two"); // sはtwosonになる
コレクションフレームワークは、データの基本的な構成法に対応したインターフェースを定め、それを実装する形でクラスが提供されています。 例えばArrayListとLinkedListは同じListインターフェースを実装しています。 したがって、これらにはListインターフェースが規定したadd、get、remove、setなどのメソッドを備えていることが保証されています。 主なコレクションインターフェースとそれを実装したクラスは次の通りです。
List 順序のある要素を扱う。(ArrayList,LinkedList,Vectorなど)
Map キーと値のペアで管理。順序は保証されない。(HashMapなど)
Set 重複を許さない要素を扱う。(HashSet,TreeSetなど)
以下の説明のうち正しいものを全部選択してください。
(1)HashMapクラスに格納できるのは文字列型のみである。
(2)LinkedListはArrayListに比べてデータの更新が得意である。
(3)ArrayListは同期化を行うのでVectorに比して性能がでない。
(4)Mapインターフェースではデータの登録の順序は保証されない。