データ集合を扱うのに便利なJavaの配列と拡張for文【改訂版】Eclipseではじめるプログラミング(5)(3/3 ページ)

» 2009年03月30日 00時00分 公開
[小山博史株式会社ガリレオ]
前のページへ 1|2|3       

配列をコピーするには?

 次に、配列のコピーについて考えてみましょう。同じデータを持つ配列を別々に利用したい場合はどうすればいいでしょうか。すぐに思い付くのは、「代入」を使う方法です。配列変数を別に宣言して、あらかじめ用意した配列変数の値を代入すれば、同じデータを利用できます。リスト1のときと同様に新しくクラス「Sample54」を作成しましょう。出来上がったSample54クラスをリスト5のように編集してください。

リスト5 
public class Sample54 {
    public static void main(String[] args) {

        long[] bd = new long[] {
            19700101,19750101,19800101,19850101,19900101,0
        };


        for (long v : bd) {
            if (v != 0) {
                System.out.println(v);
            }
        }

        System.out.println("----");

        long[] bd2 = bd;

        for (long v : bd2) {
            if (v != 0) {
                System.out.println(v);
            }
        }
    }
}

コラム 「配列の各要素を初期化しつつ配列を作成(new)するには?」

最初に、配列の各要素を初期化しつつ配列を作成(new)する方法があるので、それを使っています。

ただし、この方法を使った場合は、「長さを指定できない」という点に注意しましょう。

指定方法は単純で「 [ ] 」内に要素数を指定せずに、「 [ ] 」に続く「 { } 」内で要素となる値を「 , 」で区切って指定するだけです。「 { } 」の後に「 ; 」を付けるのを忘れないようにしてください


 肝心のコピー先の配列の宣言と初期化は「long[] bd2 = bd;」でしています。単にbdをbd2へ代入しているだけですから、これでbd2とbdが同一の「6個のlong型の要素を持つ入れ物」を参照することになります。

 リスト5のプログラムを保存して実行すると、下記のように、生年月日の一覧が2回画面へ出力されます。確かに、bdとbd2は同じ要素を持った配列だということが分かるはずです。

リスト5の実行結果
19700101
19750101
19800101
19850101
19900101
----
19700101
19750101
19800101
19850101
19900101

コピーした配列は、片方を“更新”するともう一方まで…

 ただし、このように配列を使う場合は注意が必要です。Sample54.javaのように配列の要素の値を参照しているだけならいいのですが、これらを“更新”すると問題になることがあります。

 片方で要素の値を更新すると、もう片方でも要素の値が更新されてしまうのです。

本当にそんなことが起こるのか確認してみよう

 確認してみましょう。リスト4のときと同様に、Sample54.javaをコピーしてSample55.javaを作成してください。それからSample55クラスをリスト6のように編集してください。「bd2[0] = 20000101;」を追加し、bdの各要素を表示する処理を最後に追加してあります。

リスト6 
public class Sample55 {
    public static void main(String[] args) {

        long[] bd = new long[] {
            19700101, 19750101, 19800101, 19850101, 19900101 ,0
        };

        for (long v : bd) {
            if (v != 0) {
                System.out.println(v);
            }
        }

        System.out.println("----");

        long[] bd2 = bd;

        bd2[0] = 20000101;

        for (long v : bd2) {
            if (v != 0) {
                System.out.println(v);
            }
        }

        System.out.println("----");

       for (long v : bd) {
           if (v != 0) {
               System.out.println(v);
           }
       }

    }
}

 リスト6のプログラムを実行すると、下記のように、生年月日の一覧が、配列bd、配列bd2、配列bdの順で合計3回画面へ出力されます。bd2[0]の値を20000101としたことで、bd[0]の値が19700101から20000101に変わった点に注目してください。配列bd2の要素の値を変更したのに、配列bdの要素の値まで変更されてしまっているのです。

リスト6の実行結果
19700101
19750101
19800101
19850101
19900101
----
20000101
19750101
19800101
19850101
19900101
----
20000101
19750101
19800101
19850101
19900101

勝手な更新を防ぐには?

 このように動作させたくない、つまり、bdの値を完全にコピーした別ものとしてbd2を利用したい場合もあります。そんなときはどうすればよいでしょうか。

 答えは簡単です。同じ入れ物をもう1つ用意して、値を全部コピーすればいいのです。値を全部コピーするにはいろいろな方法がありますが、ここでは基本を理解するということでfor文を使った例を紹介します。

 リスト4のときと同様に、Sample55.javaをコピーしてSample56.javaを作成してください。それからSample56クラスをリスト7のように編集してください。

リスト7 
public class Sample56 {
    public static void main(String[] args) {

        long[] bd = new long[] {
            19700101, 19750101, 19800101, 19850101, 19900101 ,0
        };

        for (long v : bd) {
            if (v != 0) {
                System.out.println(v);
            }
        }

        System.out.println("----");

// copy
        long[] bd2 = new long[bd.length];

       for (int i=0 ; i<bd2.length ; i++) {
           bd2[i] = bd[i];
       }

// copy

        bd2[0] = 20000101;

        for (long v : bd2) {
            if (v != 0) {
                System.out.println(v);
            }
        }

        System.out.println("----");

        for (long v : bd) {
            if (v != 0) {
                System.out.println(v);
            }
        }
    }
}

 「//copy」ではさまれた部分で、配列bd2の宣言を行い、作成(new)した入れ物への参照を代入してから、bdの各要素をbd2の各要素へコピーしています。ですから、「bd2[0] = 20000101;」のように配列bd2の要素の値を変更しても、今度は配列bdの要素の値はそのままで変更されません。

 リスト7のプログラムを実行すると、画面5のように、生年月日の一覧が、配列bd、配列bd2、配列bdの順で合計3回画面へ出力されます。想定通りになっていることが分かります。

リスト7の実行結果
19700101
19750101
19800101
19850101
19900101
----
20000101
19750101
19800101
19850101
19900101
----
19700101
19750101
19800101
19850101
19900101

 以上のことから分かるように、配列の要素のコピーまでする必要があるのかないのかによって、必要な処理の内容が変わります。プログラムの作成に当たっては、しっかり意識するようにしましょう。

配列はデータを扱うプログラミングにかなり重要

 さて、今回は生年月日を一覧表示するというプログラムについて考えてみました。配列を使うと、値の集合を簡単に処理できることが分かったでしょうか。実際のアドレス機能では、氏名や住所、生年月日、電話番号などいろいろなデータを一覧表示できるようになっています。氏名用の配列、住所用の配列といったものを用意すれば、こういう機能を実現できます。

 new演算子やインデックスといった用語もありましたが、配列を使う際には必ず出てきますから、よく覚えておくようにしましょう。配列が使えるようになると、複数のデータを扱うプログラミングが簡単に作れるようになります

 また、配列以外にも「スタック」「キュー」などのデータ構造がありますが、配列の知識を使って、それらを実現することもできます。そういう点からも、配列は基本的なデータ構造の1つとして、とても重要です。「スタック」「キュー」などのデータ構造について知りたい読者は下記記事を参照してください。扱っているプログラミング言語はJavaScriptですが、概念は一緒です。

 さて、生年月日の一覧表示をするだけなら、今回のようなプログラムでもよいのですが、住所録のデータを編集するときのことを考えてみるとどうでしょうか。

 ある人のデータを編集したいという場合は、ある人の氏名や住所、生年月日、電話番号を編集したいはずです。そういった場合に、氏名用の配列や住所用の配列、といった各データ用の配列を使ったプログラムでは、各配列の要素を参照したり代入し直したりする必要が出てくるため、処理が複雑になってしまいます。氏名、住所、生年月日、電話番号をひとかたまりにしたデータ型を自分で用意して、そのデータ型の配列にできたら便利そうだと思いませんか?

 そういったプログラムを簡単に作成できるようになるためには、「クラス」という概念について理解することが必要になってきます。次回は、この「クラス」を中心にして解説する予定です。

筆者紹介

小山博史(こやま ひろし)

情報家電、コンピュータと教育の研究に従事する傍ら、オープンソースソフトウェア、Java技術の普及のための活動を行っている。長野県の地域コミュニティである、SSS(G)bugs(J)の活動へも参加している。

著書に「基礎Java」(インプレス)、共著に「Javaコレクションフレームワーク」(ソフトバンククリエイティブ)、そのほかに雑誌執筆多数。



「【改訂版】Eclipseではじめるプログラミング」バックナンバー
前のページへ 1|2|3       

Copyright © ITmedia, Inc. All Rights Reserved.

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。