私のホームページへ - 前の授業へ - 次の授業へ

情報処理IIIA(Javaプログラミング入門)第9回

目次
  1. 配列(2)
  2. クラスとメソッド(3)
  3. 演習9
  4. レポート課題

配列(2)

配列と参照

変数にクラスのインスタンスを代入しますと、その変数にはそのインスタンスへの参照が格納されます。 実は、変数に配列を代入しましても、同様にその変数にはその配列への参照が格納されます。 例えば、

int[] a = {91, 74, 57, 40, 23};

のように配列を初期化しますと、次の図のようになります。

A reference to an array
図9.1 配列への参照

配列の代入や配列どうしの比較、配列引数のメソッドなどについては、インスタンスのときと同じように考えてください。

これまで扱った配列は、要素が整数(int 型)のものだけでした。 次のようにしますと、要素がクラスのインスタンスである配列が使えます。 これまで int と書いていた部分に、クラス名 classname を書きます。

まず、変数の宣言は

classname[] arrayname;

と書きます。 大きさが size である配列を生成して変数 arrayname に格納するには次のようにします。

arrayname = new classname[size];

このふたつは次のようにまとめられます。

classname[] arrayname = new classname[size];

この段階では、まだ配列の要素には何も格納されていません。 インスタンスを生成して、変数の各要素に格納する必要があります。 これは、例えば次のようにします。

int i;
...
for (i = 0; i < arrayname.length; i++) {
   arrayname[i] = new classname();
}

配列の要素に格納されたインスタンスのフィールドへの代入は、文

arrayname[expression].fieldname = expression2;

によって行います。 式

arrayname[expression].fieldname

によってこの値が取り出せます。

次のプログラムは、配列に3つの時刻データを格納し、それを画面に出力するものです。 4行目で、Time クラスの配列の変数 a を宣言します。 5行目で配列を生成して a に代入し、7行目でインスタンスを生成して配列の各要素 a[i] に代入します。 これで、インスタンスのフィールドに整数が代入できます。 8行目と9行目でそこに式の値を格納し、12行目でそれを取り出します。

Time.java
/* 1*/ class Time {
/* 2*/    int hour, minute;
/* 3*/ }
TimeArray.java
/* 1*/ class TimeArray {
/* 2*/    public static void main (String[] args) {
/* 3*/       int i;
/* 4*/       Time[] a;
/* 5*/       a = new Time[3];
/* 6*/       for (i = 0; i < a.length; i++) {
/* 7*/          a[i] = new Time();
/* 8*/          a[i].hour   = (13 * 60 + 15 + 100 * i) / 60;
/* 9*/          a[i].minute = (13 * 60 + 15 + 100 * i) % 60;
/*10*/       }
/*11*/       for (i = 0; i < a.length; i++) {
/*12*/          System.out.println(a[i].hour + ":" + a[i].minute);
/*13*/       }
/*14*/    }
/*15*/ }
b00a001@Ampere:~/java% java TimeArray
13:15
14:55
16:35
b00a001@Ampere:~/java%
An array of instances
図9.2 インスタンスの配列

2次元配列

配列は、データの「入れ物」を一列に並べたものでした。 一列ではなく、縦横に並べたものを、2次元配列two-dimensional array)とよびます。 2次元配列のイメージは次のようになります。

An image of a two-dimensional array
図9.3 2次元配列のイメージ

2次元配列の要素の、横の並びをrow)、縦の並びをcolumn)とよびます。 上記の例は3行4列の2次元配列です。 2次元配列は、表の形にデータをまとめる場合や、数学の行列を扱うときに用いられます。

整数(int 型)要素の2次元配列を格納する変数は、

int[][] arrayname;

と宣言します。 文

arrayname = new int[row][col];

によって、rowcol 列の2次元配列を生成し、arrayname に格納します。

2次元配列の要素にデータを格納するには、文

arrayname[expression1][expression2] = expression3;

を用います。 2次元配列 arrayname の(0番目から数えまして)上から expression1 番目、左から expression2 番目に、式 expression3 の値を格納します。 このデータは、式

arrayname[expression1][expression2]

によって取り出せます。

次のプログラムは2次元配列の使用例です。 4行目で、変数 a を整数要素の2次元配列と宣言し、3行4列の2次元配列を生成して、a に格納します。 5行目から7行目までで、配列の要素に数を代入します。 10行目で、代入された数を取り出して、それを画面に出力します。

/* 1*/ class TwoDimensional {
/* 2*/    public static void main (String[] args) {
/* 3*/       int i, j;
/* 4*/       int[][] a = new int[3][4];
/* 5*/       a[0][0] = 98; a[0][1] = 91; a[0][2] = 84; a[0][3] = 77;
/* 6*/       a[1][0] = 70; a[1][1] = 63; a[1][2] = 56; a[1][3] = 49;
/* 7*/       a[2][0] = 42; a[2][1] = 35; a[2][2] = 28; a[2][3] = 21;
/* 8*/       for (i = 0; i < 3; i++) {
/* 9*/          for (j = 0; j < 4; j++) {
/*10*/             System.out.print(" " + a[i][j]);
/*11*/          }
/*12*/          System.out.println();
/*13*/       }
/*14*/    }
/*15*/ }
b00a001@Ampere:~/java% java TwoDimensional
 98 91 84 77
 70 63 56 49
 42 35 28 21
b00a001@Ampere:~/java%

配列のときと同様に、2次元配列でも初期化ができます。 上記のプログラムの4行目から7行目までを、次のようにまとめることができます。

int[][] a = {{98, 91, 84, 77},
             {70, 63, 56, 49},
             {42, 35, 28, 21}};

変数に配列を代入しますと、実際には変数に配列への参照が格納されました。 2次元配列の場合、2次元配列への参照が格納されるわけではありません。 やはり配列への参照が格納されます。 ただしその配列は、要素が配列であるものです。 2次元配列は、本当は配列の配列なのです。 次の図が、2次元配列のより正確なイメージです。

An array of arrays
図9.4 配列の配列

クラスとメソッド(3)

クラスとは

前回、Javaでレコードを使うにはクラスで代用すると言いました。 Javaにおけるクラスは、データのまとまり(フィールド)とそれに対する操作(メソッド)を定義するものです。 Javaプログラムとクラス、フィールド、メソッドの関係は次の通りです。

プログラムがメソッド定義の集まりではないことに注意してください。 オブジェクト指向プログラミングでは、操作よりデータに注目します。 Javaにおけるプログラミングとは、操作(メソッド)を記述することではなく、データと操作の組み合わせ(クラス)を設計することなのです。

また、Javaにおけるメソッド呼び出しは、メッセージ受け渡しモデルmessage-passing model)に基づいています。 これは、データ(インスタンス)がメッセージを受け取ると、それに応じて操作(メソッド)が引き起こされるという考え方です。 Javaでのメッセージは、メソッド名のことだと思ってください。 インスタンスにメッセージを送りますと、そのインスタンスのクラスで定義されたメソッドが起動されるということです。

インスタンスメソッド

以前、メソッドにはインスタンスメソッドとクラスメソッドがあると言いました。 これまではクラスメソッドのみを使ってきましたが、Javaらしいプログラムではインスタンスメソッドのほうがよく用いられます。 クラスメソッドと比較しながら、インスタンスメソッドについて説明します。

前回、次のプログラムを動かしました。

Time.java
/* 1*/ class Time {
/* 2*/    int hour, minute;
/* 3*/ }
TimeTest5.java
/* 1*/ class TimeTest5 {
/* 2*/    public static void main (String[] args) {
/* 3*/       Time x = new Time();
/* 4*/       x.hour = 14;
/* 5*/       x.minute = 45;
/* 6*/       System.out.println(getTimeHour(x) + ":" + getTimeMinute(x));
/* 7*/       setTimeMinute(x, 30);
/* 8*/       System.out.println(getTimeHour(x) + ":" + getTimeMinute(x));
/* 9*/    }
/*10*/    static int getTimeHour (Time t) {
/*11*/       return t.hour;
/*12*/    }
/*13*/    static int getTimeMinute (Time t) {
/*14*/       return t.minute;
/*15*/    }
/*16*/    static void setTimeHour (Time t, int h) {
/*17*/       t.hour = h;
/*18*/    }
/*19*/    static void setTimeMinute (Time t, int m) {
/*20*/       t.minute = m;
/*21*/    }
/*22*/ }

このプログラムをインスタンスメソッドを用いて書きなおしますと、次のようになります。

AltTime.java
/* 1*/ class AltTime {
/* 2*/    int hour, minute;
/* 3*/    int getHour () {
/* 4*/       return this.hour;
/* 5*/    }
/* 6*/    int getMinute () {
/* 7*/       return this.minute;
/* 8*/    }
/* 9*/    void setHour (int h) {
/*10*/       this.hour = h;
/*11*/    }
/*12*/    void setMinute (int m) {
/*13*/       this.minute = m;
/*14*/    }
/*15*/ }
AltTimeTest.java
/* 1*/ class AltTimeTest {
/* 2*/    public static void main (String[] args) {
/* 3*/       AltTime x = new AltTime();
/* 4*/       x.hour = 14;
/* 5*/       x.minute = 45;
/* 6*/       System.out.println(x.getHour() + ":" + x.getMinute());
/* 7*/       x.setMinute(30);
/* 8*/       System.out.println(x.getHour() + ":" + x.getMinute());
/* 9*/    }
/*10*/ }
b00a001@Ampere:~/java% java AltTimeTest
14:45
14:30
b00a001@Ampere:~/java%

まず、メソッド定義を実行プログラム(main)には並べて書かず、フィールド定義に並べて書きます。 レコード型としてのクラスはフィールドのみ定義しますが、一般のクラスはさらにメソッドも定義します。 メソッドは、実行プログラムよりもデータ(インスタンス)により強く結び付くと考えます。

次に、キーワード static を取り除きます。 メソッド定義で static と書くとクラスメソッド、書かないとインスタンスメソッドになります。

メソッド呼び出しの形も変えます。 値を返さないインスタンスメソッドを呼び出すには、文

instance.methodname(argument, ...);

を用います。 ここで instance は、インスタンスを値とする式です。 例えば、インスタンス(への参照)が格納された変数などです。 値を返すインスタンスメソッドを呼び出すには、式

instance.methodname(argument, ...)

を用います。 なお、括弧がなければインスタンスのフィールドからデータを取り出す形になります。

この式 instance は、メソッド呼び出しの実引数としての役割を果たします。 この実引数に対応する仮引数は、メソッド定義でのキーワード this です。 メソッド呼び出しの際、this にはインスタンス instance への参照がコピーされます。

メッセージ受け渡しモデルに従いますと、このメソッド呼び出しは、インスタンス instance にメッセージ methodname(argument, ...) を送ることに相当します。

インスタンスメソッドにできて、クラスメソッドにできないことのひとつに、メソッド定義で this 参照を用いることがあげられます。 this 参照は、インスタンスメソッドの呼び出しのときにメッセージを受け取ったインスタンスを指します。 クラスメソッドでは、メッセージを受け取るインスタンスが存在しませんので、this 参照が使えないのです。


演習9

次のプログラムのクラスメソッドをインスタンスメソッドに書き換えてください。 クラス名、メソッド名などは適宜変更してください。

Score3.java
class Score3 {
   int english, mathematics, japanese;
}
Score3Test.java
class Score3Test {
   public static void main (String[] args) {
      Score3 x = new Score3();
      x.english = 80;
      x.mathematics = 70;
      x.japanese = 90;
      System.out.println("Total: " + totalScore3(x));
      addScore3(x, 10);
      System.out.println("English: " + x.english);
      System.out.println("Mathematics: " + x.mathematics);
      System.out.println("Japanese: " + x.japanese);
   }
   static int totalScore3 (Score3 s) {
      return s.english + s.mathematics + s.japanese;
   }
   static void addScore3 (Score3 s, int d) {
      s.english = s.english + d;
      s.mathematics = s.mathematics + d;
      s.japanese = s.japanese + d;
   }
}
b00a001@Ampere:~/java% java Score3Test
Total: 240
English: 90
Mathematics: 80
Japanese: 100
b00a001@Ampere:~/java%

レポート課題

今日の演習9にしたがってJavaプログラムを作成し、konishi@twcu.ac.jpあてにメールでそのプログラムを提出してください。 メールには、学生番号、氏名、科目名、授業の日付けを明記してください。


私のホームページへ - 前の授業へ - 次の授業へ

このページの複製は、東京女子大学学内に限り許可します。 このページへのリンクを許可します。
2000年11月21日更新
製作・著作:小西善二郎<konishi@twcu.ac.jp>