7.一軒家よりアパート?
~配列~

 「今日は19日だから、出席番号19番答えなさい。」先生も一々生徒の名前を覚えなくていいし、19番の子も、しょうがないなぁ、となる。 出席番号とは便利なもの。たくさんのデータはこんな感じで扱います。
 ここでは1次元配列のみやります。多次元配列はまた後ほど。

一軒家とアパート

 ある所に、田中さんと鈴木さんと佐藤さんと小川さんの家がありました。 またある所に、寿荘というアパートがあり、4世帯が住んでいました。

 さてこの全世帯に新聞を配ります。新人Aは指示されます。 「田中さんと鈴木さんと佐藤さんと小川さんに配ってくれ。」新人Bは指示されます。 「寿荘の0号室から3号室まで配ってくれ。」
 新人Aは思いました。「あーあ、アパートの方が楽だったなあ。」 そう、家が何件もあるとき、アパートの方がチャッチャと用事が済むことがあります。 指示する先輩も、一軒家ばかりの方は「あっ、星さんを忘れてた!」なんてこともあり得ますから。



 では変数tanakaとsuzukiとsatouとogawaに各家族の人数が入っているとして、その合計を求めることを考えてみましょう。



int sum;
sum = 0;
sum += tanaka;
sum += suzuki;
sum += satou;
sum += ogawa;
System.out.println(sum);

 +=は大丈夫ですね。合計を求めるための変数sumは、最初に0にしておきましょう。 そろばんの「願いましては」で払うのに相当します。 もう一度繰り返します。合計を求めるための変数は、最初0にしておくのを忘れないように。

 さて問題はここからです。新しく松井さんと土井さんの家が建ちました。 どうすればよいでしょう。そう、変数matuiとdoiを新しく追加し、計算も2行追加になります。 結構大変です。またさらに、太田さんと工藤さんと斉藤さんの家が建ちました...もうやめましょう。

 家族の人数を大量に記憶するのに、バラバラと変数を使っていたのでは埒が明かないのです。 一軒家に新聞を配るのに似ていますね。そこで配列型の登場。アパート方式です。

 では寿荘の各世帯の人数を配列kotobukiに記憶させましょう。



 一つ一つのデータは、0から始まる添字(そえじ)という通し番号で区別します。 0号室の人数はkotobuki[0]、1号室はkotobuki[1]という具合です。
 添字は0から始まるのに注意してください。1からではありません。
 各データの入っている箱を配列要素といいます。 配列要素は添字順に連続してメモリー上に並んでいます。 あとは普通の変数と同じように計算に使えます。

int sum;
sum = 0;
sum += kotobuki[0];
sum += kotobuki[1];
sum += kotobuki[2];
sum += kotobuki[3];
System.out.println(sum);

 気がつきましたでしょうか?ここではfor文を使って4行文の計算を1行で済ますことができるのです。(for文まで入れれば3行ですけどね)

int i, sum;
sum = 0;
for (i = 0; i < 4; i++) {
 sum += kotobuki[i];
}
System.out.println(sum);

 もし4号室に誰か入れば、i<4をi<5にしてkotobuki[4]まで加算するようにすればいいのです。どうです、すっきりしたでしょ。

アパートを建てる

 変数kotobukiは各要素に家族の人数というint型のデータを入れるので、各要素がint型である配列型として宣言します。
 ナニナニ、家族の人数だけでなく名字や車を持っているかどうかも知りたい...後でクラス型の配列が出てくるので待っていてください。 ここでは基本データ型の配列をまずマスターしてしまいましょう。



 まず①でkotobukiがint型の配列であること、正確にはint型の配列を参照する変数なのですよ、ということを宣言します。 これだけでは配列本体はありませんので、②で作ります。 このとき配列の長さを指定します。
 ここでは長さは4、つまりkotobuki[0]からkotobuki[3]までが連続して確保されます。
 長さは4なので、この後プログラムでkotobuki[4]などとすると、はみ出したと怒られます。

 2段階で宣言するところは、クラスの時と同じです。変数kotobukiには配列本体のある場所の情報(100番地のような)が入ります。
 宣言しておけば、配列要素は下のようにint型の変数と同じように使えます。

kotobuki[0] = 3;
kotobuki[3] = kotobuki[0] + 2;

 ②では配列要素の値がすべて0になっています。 実はnewで配列を生成するとき、配列の型により次のような初期値が各配列要素に代入されるのです。

数値型(byte、short、int、long、float、double) は 0
boolean は false
char   は \u0000(すべて0のUnicode値)
参照型  は null

 nullは特別な参照値で、どのオブジェクトも参照していないことを表します。 主にエラーチェックに使用されます。kotobukiはint型なので、各要素に0が入ります。

配列kotobukiにデータを入れてみましょう。

int[] kotobuki;
kotobuki = new int[4];
kotobuki[0] = 3;
kotobuki[1] = 2;
kotobuki[2] = 5;
kotobuki[3] = 7;

 これをいっぺんにやってしまう方法があります。{ }内の定数の数が配列の長さになります。

int[] kotobuki = { 3, 2, 5, 7 };

勝ち抜きのど自慢

 では寿荘の中で、一番大所帯の人数を調べてみましょう。 勝ち抜きのど自慢方式でやります。
 配列名は長いと説明図がめんどうなので、aにします。 また配列aの長さをnに入れておきます。 これは大事なこと!なぜならデータの量というのはよく変わるからです。 そのとき①の4を変更すれば、以降のfor文での変更は不要になるからです。

int[] a = { 3, 2, 5, 7 };
int n = 4; // ①
int max = a[0]; // ②
for (int i = 1; i < n; i++) {
 if (a[i] > max) { // ③
  max = a[i];// ④
 }
}
System.out.println(max);

 チャンピオンは変数maxです。②で最初の挑戦者a[0]は無条件にチャンピオンになります。
 for文での繰り返しで、a[1]、a[2]、と次々挑戦者がチャンピオンに挑みます。 これが③。チャンピオンmaxより大きいと勝ちです。
 勝ったら④でmaxの値は挑戦者a[i]で入れ替わります。
 maxの値の変化を図にしました。細い矢印は③の比較に対応します。 太い矢印が④の代入で、新しいチャンピオン誕生の瞬間です。答えは7になります。



 今度は何号室が一番人数が多いかを調べましょう。

先ほどは配列要素の値a[i]をmaxに入れましたが、今度は添字iを覚えておかなくてはなりません。

int imax = 0;
for (int i = 1; i < n; i++) {
 if (a[i] > a[imax]) {
  imax = i;
 }
}
System.out.println(imax);

 imaxの値は繰り返しの最初の1回(i=1)は0のままですが、次の繰り返しで2になり、最終的に3になります。図で確かめてください。



 最後に上の二つを合体させましょう。何号室が何人で一番多いのかを出力させるのです。大丈夫ですね。

int[] a = { 3, 2, 5, 7 };
int n = 4;
int imax = 0;
for (int i = 1; i < n; i++) {
 if (a[i] > a[imax]) {
  imax = i;
 }
}
System.out.println(imax + "号室が" + a[imax] + "人で一番多い");

 配列の長さは、「配列名.length」で求められます。これを利用すると変数nを使わず、少しスマートな形になります。

int[] a = { 3, 2, 5, 7 };
int imax = 0;
for (int i = 1; i < a.length; i++) {
 if (a[i] > a[imax]) {
  imax = i;
 }
}
System.out.println(imax + "号室が" + a[imax] + "人で一番多い");

クラス型の配列

 では前にやったPersonクラスの配列を作ってみましょう。


 まず①でPersonクラスの配列xの宣言をします。②で配列本体を長さを指定して作ります。 クラス型は参照型なので、各要素はnullになっています。
int型の配列は、配列要素に直接データを入れられましたが、今度はそうはいきません。 ③でx[0]にオブジェクトを作りここに④でやっているように必要なデータを放り込みます。 どうです、めんどうでしょ。
でも配列の宣言もわかった、オブジェクトの宣言もわかった、という方にはわかると思います。

 ではPerson型の配列の中から最高齢の人のデータを出力する処理です。 配列要素x[i]はPerson型のオブジェクトを表すので、x[i].ageで年齢を取り出すことができます。

Person[] x;
x = new Person[3];

x[0] = new Person();
x[0].name = "太郎";
x[0].age = 5;

x[1] = new Person();
x[1].name = "次郎";
x[1].age = 100;

x[2] = new Person();
x[2].name = "三郎";
x[2].age = 55;

int n = 3;
int imax = 0;
for (int i = 1; i < n; i++) {
 if (x[i].age > x[imax].age) {
  imax = i;
 }
}
System.out.println(x[imax].name + "さんが" + x[imax].age + "才で最高齢");

用語の整理

 int[ ]やPerson[ ]を配列型といいます。 上のxは配列型の変数ということになります。配列型は、クラス型と並んで、参照型と呼ばれます。 (他にインターフェース型もあります)
参照型は変数自体にデータを持つのでなく、オブジェクトにデータを持ち、変数にはその参照(オブジェクトのある場所の情報)が入ります。

 オブジェクトとは、今までの説明の図で、変数に参照されている先の箱、つまり→の先にある箱のことを言います。配列もオブジェクトです。

変数の型は次の二つに分類できます。
 基本データ型・・・boolean byte char short int long float double
 参照型・・・クラス型 配列型 インターフェース型

オブジェクト・・・クラスのnewでできる箱 または 配列