配列変数と配列本体

配列変数の代入

配列変数を他の配列変数に代入することができます。 配列変数の代入は、配列本体のコピーと勘違いされがちですが、その本当の意味を説明したいと思います。

では早速、サンプルプログラムArraySample05を見てください。

ArraySample05.java
class ArraySample05 {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4, 5};
        int[] b = {6, 7, 8, 9};

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();

        b = a;
        System.out.println("aをbに代入しました。");
        b[0] = 10;
        System.out.println("b[0]に10を代入しました。");

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();
    }
}

配列a, bの内容が最終的にどのようになっているかを予想してから、ArraySample05を実行してみてください。

それでは、実行結果をスクリーンショットで見てみましょう。

図 8-6 : ArraySample05の実行結果

いかかでしょう。予想は当たりましたか。 ArraySample05では、まず

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

と配列a, bを初期化しています。そして

        b = a;
        b[0] = 10;

のように、aをbに代入してからb[0]に10を代入しています。 したがって、配列aは{1, 2, 3, 4, 5}のままで、配列bだけが{10, 2, 3, 4, 5}になると予想されたかもしれません。 しかし、結果はaとbの両方とも{10, 2, 3, 4, 5}となっています。

aをbに代入しても、aが参照する配列本体と同じ内容のコピーが作られ、bがそのコピーを参照するようになるわけではないのです。 実際には、aの参照先がbに代入されます。 つまり、aが参照している配列本体をbも参照するようになるだけなのです。 従って、aをbに代入した後でb[0]に10を代入すると、a[0]も10になってしまいます。 この様子を表すのが図 8-7です。

図 8-7 : 配列変数の代入

配列変数を別の配列変数に代入しても、配列本体のコピーにはならない。

配列本体のコピー

それでは、配列本体をコピーするためにはどうすればいいのでしょうか。 何のことはありません。 コピー元の配列本体と同じ長さの新しい配列本体を生成して、for文等を使って、各要素を一つずつコピーしていくだけのことです。

ArraySample06は、配列aを配列bにコピーするプログラムです。

ArraySample06.java
class ArraySample06 {
    public static void main(String[] args) {
        int[] a = {1, 2, 3, 4, 5};
        int[] b = {6, 7, 8, 9};

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();

        b = new int[a.length];    //配列bの配列本体を生成し直す。
        for(int i = 0; i < a.length; i++)    //配列aの各要素を配列bへコピーする。
            b[i] = a[i];
        System.out.println("配列aを配列bにコピーしました。");
        b[0] = 10;
        System.out.println("b[0]に10を代入しました。");

        System.out.print("aが指す配列本体は");
        for(int i = 0; i < a.length; i++)
            System.out.printf(" %2d", a[i]);
        System.out.println();
        System.out.print("bが指す配列本体は");
        for(int i = 0; i < b.length; i++)
            System.out.printf(" %2d", b[i]);
        System.out.println();
    }
}

ArraySample06の実行結果は次のようになります。

図 8-8 : ArraySample06の実行結果

ArraySample06でも、ArraySample05同様、配列a, bをそれぞれ初期化しています。

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

そして、次の部分では、まず配列aと同じ長さの配列本体を生成して、その参照をbに代入しています。 続くfor文では、配列aの各要素を、同じインデックスを持つ配列bの要素に代入していきます。

        b = new int[a.length];    //配列bの配列本体を生成し直す。
        for(int i = 0; i < a.length; i++)    //配列aの各要素を配列bへコピーする。
            b[i] = a[i];

この段階で、配列aから配列bへのコピーは完了しています。 したがって、ここで

        b[0] = 10;

が実行されると、b[0]だけが10となり、a[0]は1のままとなります。

この流れを図 8-9にまとめておきます。

図 8-9 : 配列本体のコピー

配列本体をコピーするためには、コピー元の配列本体と同じ長さの配列本体を生成してから、各要素を一つ一つコピーしていく。

ArraySample05やArraySample06では、配列本体{6, 7, 8, 9}が、どの配列変数からも参照されなくなってしまいました。 この後、この配列本体はどうなってしまうのでしょうか。 これについては次の節で詳しく解説します。