梅組にかわいい転校生がやってきました。さてはて梅組にうまくなじめるのでしょうか?まずは配列でやってみて、その後ArrayListを使ってみましょう。
では配列umeにまずは在校生、次に転校生を入れて、一覧を出力してみましょう。若井さんが転校生です。
public class Main0 {
public static void main(String[] args) {
Student[] ume = new Student[5];
ume[0] = new Student(2, "木下 保美", 141.5);
ume[1] = new Student(5, "湯水 敦", 145.0);
ume[2] = new Student(1, "相田 徹", 152.5);
ume[3] = new Student(4, "目加田 重三", 136.0);
ume[4] = new Student(3, "橋 航", 145.0);
ume[5] = new Student(6, "若井 可奈", 143.0); // 転校生
for (int i = 0; i < ume.length; i++) {
ume[i].printStudent();
}
}
} |
実行してみると次のようなエラーになってしまいました。
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException:
5
at Main0.main(Main0.java:10)
これは配列の範囲をはみ出したところにデータを入れようとしているよ、というエラーです。配列umeの長さは5ですね。添え字は0から始まるので、ume[0]〜ume[4]は使用可ですが、ume[5]は配列umeの範囲外になってしまうのです。これは大変、どうしたらいいでしょうか?
一番簡単なのは、あらかじめ配列umeの宣言でその長さを大きめにしておくことです。ただプログラムを実行してみなければ、何人転校生が出現してくるかわからない、という場合、かなり大きめにしておく必要があります。
Student[ ] ume = new Student[50];
これなら45人の転校生が来ても大丈夫ですね。でもそんなに転校してくるかしら、なんだかもったいない感じがします。
例えば、あるスーパーの全商品のデータが入った商品マスターから、1000円以上の商品のデータを取り出して配列にしまいたい、などというとき、配列の長さはいくつにしておけばいいのでしょうか?全商品分の長さが本当に必要でしょうか?うーん、難しい問題ですね。
では、大きさが足りなくなった時点で、大きめの配列を作って乗り換える、というのはどうでしょう?こんなかんじです。System.arraycopyは配列のコピーを行うメソッドです。APIを調べてみましょう。クラスjava.lang.Systemですよ。
Student[] umeBackup = ume; //@
ume = new Student[6]; //A
System.arraycopy(umeBackup, 0, ume, 0, umeBackup.length); //B
umeBackup = null; //C
ume[5] = new Student(6, "若井 可奈", 143.0); |
図のようなイメージの操作になります。
Cは、もう元の配列は不要になったので、umeBackupにnullを入れて、参照を切り離しておきます。そうすれば、元の配列のエリアはガベージコレクションの対象になります。
これでめでたく転校生が入る余地ができました。それにしてもめんどうくさいですね。そんなときに便利なのが、自動的に伸びる配列ArrayListです。
java.util.ArrayListは、標準ライブラリにあるクラスです。単によく使われるだろうからと親切にあらかじめ作っておいてくれてあるだけで、その使い方は普通のクラスと同じです。JDKをダウンロードすると、ソースファイルも入っているので、覗いてみると面白いです。
一方配列はJavaの中で特別扱いされています。使い方も特別な文法があります。[ ]で添字の指定をしたり、長さを配列名.lenghtで求めたり。このへんに注意しながら、配列とArrayListを使った場合を対応させて見ていきましょう。
配列では
Student[ ] ume = new Student[5]; //a-1
としたところを、ArrayListでは
ArrayList<Student> ume = new ArrayList<Student>(); //b-1
となります。伸び縮みするので、特に大きさの指定は不要ですが、大体わかっている場合はこんな風に指定することもできます。
ArrayList<Student> ume = new ArrayList<Student>(5);
そう、ArrayListは、
基礎編23章で出てきたGenerics型なのです。ここではStudent型のオブジェクトを格納するので、型の指定はStudentになります。
a-1、b-1実行後のイメージを図にしておきます。
a-1実行後
b-1実行後
配列では、newで指定された長さの連続したエリアが確保されます。ArrayListでは内部的には同じ感じなのですが、使う側のイメージとしてはさしあたり変数だけが確保されている、と考えてください。
ではデータを入れていきましょう。配列では添字を指定して、
ume[0] = new Student(2, "木下 保美", 141.5); //a-2
でしたが、ArrayListではメソッドaddを呼び出します。引数に追加したいデータを指定します。
ume.add(new Student(2, "木下 保美", 141.5)); //b-2
添字の指定はありませんが、addする順に先頭から格納されます。配列のように追加できるデータの個数に制限はありません。どんどん追加してください。またumeはArrayList<Student>型なので、Student型以外のオブジェクトを追加しようとすると、コンパイルエラーになります。(ただしnullは例外です)
a-2実行後
b-2実行後
さらに
ume.add(new Student(5, "湯水 敦", 145.0));
と追加すると
となります。
では各データを順に出力してみましょう。配列では
for (int i = 0; i < ume.length; i++) {
ume[i].printStudent();
}
でしたが、ArrayListではデータの取り出しはメソッドgetで行います。
for (int i = 0; i < ume.size(); i++) {
ume.get(i).printStudent();
}
どちらの場合も、基礎編7章(追加)の新しいfor文で書き換えることができます。
配列もArrayListも次のようになります。
for(Student student:ume) {
student.printStudent();
}
変数studentは対応が取れていればどんな名前でもいいです。
ArrayListは標準ライブラリのパッケージjava.utilにあるので、import文で次の指定をしておくと、プログラム中でフルネームjava.util.ArrayListで呼ばずにすむので楽です。
import java.util.ArrayList;
以上をまとめると、ArrayListで先ほどの配列の処理を書き換えると次のようになります。出力は新しいfor文を使いました。もちろん転校生の若井さんを追加してもエラーにはなりません。
import java.util.ArrayList;
public class Main1 {
public static void main(String[] args) {
ArrayList<Student> ume = new ArrayList<Student>();
ume.add(new Student(2, "木下 保美", 141.5));
ume.add(new Student(5, "湯水 敦", 145.0));
ume.add(new Student(1, "相田 徹", 152.5));
ume.add(new Student(4, "目加田 重三", 136.0));
ume.add(new Student(3, "橋 航", 145.0));
ume.add(new Student(6, "若井 可奈", 143.0));
for(Student student:ume) {
student.printStudent();
}
}
}
|
ArrayListのAPIを見てみましょう。removeやconteins、size、trimToSizeといったメソッドがあります。また配列にデータをすべてコピーするtoArrayもあります。続きは次章で。