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

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

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

クラスとメソッド(2)

レコードとは

レコードrecord)とは、複数のデータをひとまとめにしたものです。 次の図はレコードのイメージを表しています。

An image of a record
図8.1 レコードのイメージ

データをまとめたものとして、以前に配列を取り上げました。 レコードと配列には次のような違いがあります。

ここでレコード型とは、どのフィールドにどの種類(型)のデータが格納できるかを指定したものです。 ここでは、フィールド hourminute に整数(int 型)が格納できるレコード型に Time と名付けることにします。

実は、Javaにはレコードはありません。 しかし、クラスclass)というものがレコードの機能を持っています。 この授業では、クラスを用いてレコードを実現します。 レコードとクラスの対応関係は次の通りです。

インスタンスの使い方

レコードとしてのインスタンスを使うには、まずクラスを定義する必要があります。 フィールドに格納するデータが整数(int 型)でしたら、次のように書きます。

class classname {
   int fieldname1, ..., fieldnamen;
}

ここで、classname はクラス名、fieldname はフィールド名です。 上記の例ですと、次のようになります。

 1: class Time {
 2:    int hour, minute;
 3: }

これをファイル(Time.java)に保存します。 (このファイルがありませんと、以下のプログラムは動きません。)

クラスが定義できましたら、プログラムを作成します。 次のプログラムは、変数を宣言し、インスタンスを生成してそこに格納し、インスタンスのフィールドにデータを格納し、その値を表示するものです。

 1: class TimeTest1 {
 2:    public static void main (String[] args) {
 3:       Time x;
 4:       x = new Time();
 5:       x.hour = 9;
 6:       x.minute = 30;
 7:       System.out.println(x.hour + ":" + x.minute);
 8:    }
 9: }
b00a001@Ampere:~/java% java TimeTest1
9:30
b00a001@Ampere:~/java%

変数に整数(int 型)を格納するには変数の宣言が必要でした。 変数にインスタンスを格納するにも、同様に変数の宣言が必要です。 これは次のように書きます。

classname variable;

今まで int と書いていた部分をクラス名に変えます。 3行目で、変数 xTime クラスと宣言します。

クラスのインスタンスは、明示的に生成してはじめて使えます。 インスタンスを生成するにはキーワード new を用います。 classname クラスのインスタンスを生成して、変数 variable に格納するには、

variable = new classname();

と書きます。 4行目で、Time クラスのインスタンスを生成して、変数 x に格納します。

なお、次のように書きますと、変数の宣言とインスタンスの生成、そしてその変数への格納が同時に行えます。

classname variable = new classname();

インスタンスのフィールドにデータを格納するには、次のような文を用います。

variable.fieldname = expression;

これで、変数 variable に格納されているインスタンスのフィールド fieldname に、式 expression の値が格納されます。 5行目で、インスタンス xhour フィールドに9が格納され、6行目で、minute フィールドに30が格納されます。

インスタンスのフィールドに格納されたデータを取り出すには、式

variable.fieldname

を用います。 この式の値は、変数 variable に格納されているインスタンスのフィールド fieldname に格納されているデータです。 7行目で、インスタンス xhour フィールドと minute フィールドからデータを取り出して、出力します。

インスタンスと参照

上記のプログラムで、変数 x には何が格納されるでしょうか。 変数にはデータが一つしか格納できませんので、インスタンスそのものは入りません。 実は、x には参照reference)とよばれるデータが格納されます。 参照とは、メモリの中でデータが配置されている場所のことです。 変数 x には、インスタンスが置かれている「場所データ」が格納されるのです。 参照は、しばしば矢印で書き表わされます。

An image of a reference
図8.2 参照のイメージ

参照をポインタやアドレスのようなものだと思っても差し支えありません。

参照が格納される変数の値を変えることは、参照先を変更することになります。 次のプログラムでは、まず10時45分を表すインスタンスへの参照が変数 x に格納されます。 そして x の値は、11時15分を表すインスタンスへの参照に置き換わります。

 1: class TimeTest2 {
 2:    public static void main (String[] args) {
 3:       Time x;
 4:       x = new Time();
 5:       x.hour = 10;
 6:       x.minute = 45;
 7:       System.out.println(x.hour + ":" + x.minute);
 8:       x = new Time();
 9:       x.hour = 11;
10:       x.minute = 15;
11:       System.out.println(x.hour + ":" + x.minute);
12:    }
13: }
b00a001@Ampere:~/java% java TimeTest2
10:45
11:15
b00a001@Ampere:~/java%
Changing references
図8.3 参照の変更

インスタンスの代入と比較

整数(int 型)が格納される変数に数を代入しますと、その変数にはその数が格納されます。 詳しく言いますと、その数のコピーが格納されます。 インスタンス(への参照)が格納される変数にインスタンスを代入しますと、その変数にはそのインスタンスへの参照のコピーが格納されます。 インスタンスはコピーされません。

整数(int 型)どうしでは、関係演算子として >== などが使えました。 インスタンスどうしでは == が使えます。 これは参照先が一致していることを意味します。 成分が等しくても置かれている場所が異なれば、インスタンスは(== の意味で)等しくありません。

次のプログラムは、まず変数 x に12時30分を表すインスタンス(への参照)を格納します。 そして、変数 y にはそのインスタンスを直接代入し、変数 z には成分ごとに代入します。 xy は等しいインスタンスだと判定されますが、xz は等しくないと判定されます。

 1: class TimeTest3 {
 2:    public static void main (String[] args) {
 3:       Time x, y, z;
 4:       x = new Time();
 5:       x.hour = 12;
 6:       x.minute = 30;
 7:       System.out.println("x is " + x.hour + ":" + x.minute);
 8:       y = x;
 9:       System.out.println("y is " + y.hour + ":" + y.minute);
10:       z = new Time();
11:       z.hour = x.hour;
12:       z.minute = x.minute;
13:       System.out.println("z is " + z.hour + ":" + z.minute);
14:       if (x == y) {
15:          System.out.println("x == y is true.");
16:       } else {
17:          System.out.println("x == y is false.");
18:       }
19:       if (x == z) {
20:          System.out.println("x == z is true.");
21:       } else {
22:          System.out.println("x == z is false.");
23:       }
24:    }
25: }
b00a001@Ampere:~/java% java TimeTest3
x is 12:30
y is 12:30
z is 12:30
x == y is true.
x == z is false.
b00a001@Ampere:~/java%
Equality of instance
図8.4 インスタンスの同等性

インスタンスの共有

次のプログラムにおいて、7行目の代入で変数 xy は同じインスタンスを参照します。 この状態を、xy はインスタンスを共有share)しているといいます。 インスタンスを共有している場合、一方からインスタンスを変更しますと、他方からも変更されたことになります。 9行目で、インスタンス xminute フィールドを変更しますと、インスタンス y も変更されるのです。

 1: class TimeTest4 {
 2:    public static void main (String[] args) {
 3:       Time x = new Time();
 4:       Time y;
 5:       x.hour = 13;
 6:       x.minute = 15;
 7:       y = x;
 8:       System.out.println(y.hour + ":" + y.minute);
 9:       x.minute = 45;
10:       System.out.println(y.hour + ":" + y.minute);
11:    }
12: }
b00a001@Ampere:~/java% java TimeTest4
13:15
13:45
b00a001@Ampere:~/java%
Sharing an instance
図8.5 インスタンスの共有

インスタンスを用いるメソッド

これまで定義したメソッドは、引数や返り値が整数(int 型)のものだけでした。 (引数や返り値がないものもありました。) これまで int と書いていた部分にクラス名を書くことによって、引数や返り値がインスタンスであるメソッドが定義できます。 例えば、引数が Time クラスのインスタンスで値を返さない(クラス)メソッドは、

static void methodname (Time argument) {
   ...
}

と定義します。 また、引数が Time クラスのインスタンスと整数(int 型)で、返り値が整数(int 型)である(クラス)メソッドは、

static int methodname (Time argument1, int argument2) {
   ...
}

と定義します。

次のプログラムでは、メソッドをいくつか定義しています。 getTimeHour は、Time クラスのインスタンスを引数にとり、その hour フィールドの値を返します。 getTimeMinute は、同様に minute フィールドの値を返します。 6行目で、メソッド getTimeHour が呼び出されますと、仮引数 t に実引数 x の値が代入され、x.hour の値が返されます。

setTimeMinute は、Time クラスのインスタンスと整数(int 型)を引数にとり、値を返さないメソッドです。 7行目で、メソッド setTimeMinute が呼び出されますと、同様に tx の値が代入されます。 詳しく言いますと、x に格納されているデータ(すなわち参照)のコピーが t に格納されます。 これで、xt は同じインスタンスを共有します。 メソッドの定義内容にしたがい、この共有しているインスタンスは変更されます。 したがって、インスタンス x は、6行目で14時45分を表していましたが、8行目で14時30分を表すように変更されるわけです。

 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: }
b00a001@Ampere:~/java% java TimeTest5
14:45
14:30
b00a001@Ampere:~/java%
Method call with instance arguments
図8.6 インスタンス引数のメソッド呼び出し

演習8

画用紙の大きさに関するクラスとメソッドを定義します。

はじめに、クラス DrawingPaper を定義して、画用紙の横の長さ widthint 型)と縦の長さ heightint 型)が格納できるようにしてください。 このクラス定義でひとつファイルを作成します。

次に、画用紙の大きさを表示するメソッド printPaperSize と、横の長さと縦の長さを交換するメソッド turnPaper を定義してください。 これらのメソッド定義は、次のプログラムの中に書いてください。 このプログラムでもうひとつファイルを作成します。

class DrawingPaperTest {
   public static void main (String[] args) {
      DrawingPaper x = new DrawingPaper();
      x.width = 257;
      x.height = 364;
      printPaperSize(x);
      turnPaper(x);
      printPaperSize(x);
   }
   static void printPaperSize (DrawingPaper p) {

      ???

   }
   static void turnPaper (DrawingPaper p) {

      ???

   }
}
b00a001@Ampere:~/java% java DrawingPaperTest
width: 257mm, height: 364mm.
width: 364mm, height: 257mm.
b00a001@Ampere:~/java%

レポート課題

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


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

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