[雑談] 試験の役に立たないJava講座 (8)

ということで引き続きインプレス社の「徹底攻略Java SE 11 Silver問題集」の章立てに沿って、少し雑談していきたいと思います。

以前よりお話ししているとおり問題集の内容に沿ったものではなく抜けているところも多々ありますので、認定資格を取得しようというのであれば問題集を購入して、そちらをしっかり勉強してください。

こちらは章立てに沿って適当に書き散らかしているものですので、試験の役には立ちません。

ということで今回は第5章、配列と前回書き忘れた拡張for文について少し考えてみたいと思います。

配列

これまでプログラム例の中で適当に配列を使ってきましたが、ここで一度配列についてまとめておきたいと思います。

配列は長さが固定された値の列で、Javaでは値が一列に並んだ1次元配列が基本になっています。

感覚的には特定の型の値を保持する箱が一列に並んだものと考えてもいいと思います。

配列変数の宣言

配列変数の宣言は以下のように型名の後に「[]」を書くことで行います。

int[] a;

上の例では整数型 (int) の配列変数aを宣言しています。

Javaでは配列変数を宣言しただけでは変数は初期化されないので、配列オブジェクトを生成する必要があります。

また、C言語などのようにint[3] a;といった形で配列のサイズを変数宣言時に行うこともできません。

配列オブジェクトの生成

配列オブジェクトはnewを使用して以下のように生成します。

int[] a;
a = new int[3];

もちろん、以下のように配列変数宣言時に変数の初期化として書くことも可能です。

int[] a = new int[3];

このように初期化を行うと配列の各要素は既定の値、上の例のように整数型であれば0に初期化されます。

他の値で初期化を行いたい場合は以下のように中かっこ「{}」でくくり、カンマ「,」で区切った値の列で初期化を行います。

int[] a = {1, 2, 3};

当然ですが、初期化する値は配列の要素型と互換性のある値でなければなりません。

また、以下のようにnewと組み合わせて初期化することもできます。

int[] a = new int[]{1, 2, 3};

プリミティブ型ではこの書き方をする必要はほぼありませんが、そのうち出てくるオブジェクトの継承やインタフェースの実装と関連してこういった書き方が必要となる場合があります。

オブジェクトとしての配列

配列は単に値を入れる容器の列ではなく、オブジェクトとして定義されており、いくつかの特別なふるまいが提供されています。

まず、配列はサイズ (要素数) を変更することができません。

配列のサイズを取得するにはlengthというインスタンス変数を使用して、size = a.lengthという形で読み取ります。

配列のコピーを取得するにはcloneというインスタンスメソッドを使用し、int[] a2 = a.clone();のように実行します。

int[] a2 = aのように変数の代入を行った場合にはaa2は同じ配列オブジェクトを参照するため、配列aに対する変更が配列a2にも反映されたように見えてしまいます。

同じ値で初期化された別の配列を生成する際には必ずcloneメソッドを使用してください。

配列はオブジェクトですのでtoStringメソッドやequalsメソッドを使用できますが、必ずしも期待する結果になるとは限りません。

配列要素へのアクセス

配列要素からの値の読み出しはint i = a[2];のように角カッコ「[]」で要素位置を指定します。

要素位置は0はじまりですので、配列のサイズ以上の要素位置、あるいはマイナスの要素位置を指定した場合には例外 (ArrayIndexOutOfBoundsException) が発生します。

配列要素への値の書き込みも同様にa[1] = 3;のように角カッコ「[]」で要素位置を指定します。

こちらも同様に不正な要素位置指定がされると例外が発生します。

多次元配列

Javaの配列は基本的には要素が1列に並んだ1次元配列だけで、縦横に要素が並ぶ2次元配列などの多次元配列は配列の配列として実現されます。

int[][] a;

上のような配列変数の宣言を行った場合、aint型の配列の配列となります。

例えば3×3の配列での初期化をステップごとに行うと以下のようになります。

int[][] a;
a = new int[3][];
a[0] = new int[3];

a[1] = new int[3];

a[2] = new int[3];

最初の配列生成a = new int[3][];は原理主義的にはちょっと気持ち悪くて、int[]型の配列を生成するのだからa = new int[][3];の方が論理的にはすんなり受け入れられます。

が、こうすると配列へのアクセス時の要素指定と指定の順序が変わってしまうという問題があるので、気持ち悪いけれども現在の形になっているのではないかと私は考えています。

それはそれとして、これでは面倒なので以下のような簡略記法が提供されています。

int[][] a = new int[3][3];

また、値で初期化する際にも簡略記法があります。

int[][] a = {{1,2,3}, {4,5,6}, {7,8,9}};

しかし、簡略記法を使っても多次元配列になるわけではなくあくまで配列の配列であることに注意してください。

拡張for文

配列要素を順番に処理する場合、普通はfor文が使われます。

String a[] = {"A", "B", "C"};
for (int i = 0; i < a.length; ++i) {
  System.out.println(a[i] + " ");

}

この例をよく見ると、ループ変数iは配列の要素にアクセスするためにしか使用されていません。

もしも配列要素を直接取り出せたらもうちょっと便利になるのではということで導入されたのが拡張for文です。

String[] a = {"A" + "B" + "C"};
for (String s: a) {
  System.out.println(s + " ");

}

forのカッコ「()」の中にコロン「:」で区切って左側に要素を受け取る変数、右側に配列など読み取られるオブジェクトを書くと、オブジェクト内の要素が順次変数に代入されてループ本体が実行されます。

多少の制約がありますがループ変数を使用するより簡潔に書ける場合が多いので、配列などの要素を順番に処理する場合にはこちらも検討してください。

拡張for文は別の機会でも触れていくことがあると思います。

今回は簡単に配列と拡張for文について考えてみました。

0コメント

  • 1000 / 1000