レコード(record)とは、複数のデータをひとまとめにしたものです。 次の図はレコードのイメージを表しています。
データをまとめたものとして、以前に配列を取り上げました。 レコードと配列には次のような違いがあります。
int[]
などと規則的な名前がつきますが、レコード型には個別に名前がつきます。
ここでレコード型とは、どのフィールドにどの種類(型)のデータが格納できるかを指定したものです。
ここでは、フィールド hour
と minute
に整数(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行目で、変数 x
を Time
クラスと宣言します。
クラスのインスタンスは、明示的に生成してはじめて使えます。
インスタンスを生成するにはキーワード new
を用います。
classname クラスのインスタンスを生成して、変数 variable に格納するには、
variable = new classname();
と書きます。
4行目で、Time
クラスのインスタンスを生成して、変数 x
に格納します。
なお、次のように書きますと、変数の宣言とインスタンスの生成、そしてその変数への格納が同時に行えます。
classname variable = new classname();
インスタンスのフィールドにデータを格納するには、次のような文を用います。
variable.fieldname = expression;
これで、変数 variable に格納されているインスタンスのフィールド fieldname に、式 expression の値が格納されます。
5行目で、インスタンス x
の hour
フィールドに9が格納され、6行目で、minute
フィールドに30が格納されます。
インスタンスのフィールドに格納されたデータを取り出すには、式
variable.fieldname
を用います。
この式の値は、変数 variable に格納されているインスタンスのフィールド fieldname に格納されているデータです。
7行目で、インスタンス x
の hour
フィールドと minute
フィールドからデータを取り出して、出力します。
上記のプログラムで、変数 x
には何が格納されるでしょうか。
変数にはデータが一つしか格納できませんので、インスタンスそのものは入りません。
実は、x
には参照(reference)とよばれるデータが格納されます。
参照とは、メモリの中でデータが配置されている場所のことです。
変数 x
には、インスタンスが置かれている「場所データ」が格納されるのです。
参照は、しばしば矢印で書き表わされます。
参照をポインタやアドレスのようなものだと思っても差し支えありません。
参照が格納される変数の値を変えることは、参照先を変更することになります。
次のプログラムでは、まず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%
整数(int
型)が格納される変数に数を代入しますと、その変数にはその数が格納されます。
詳しく言いますと、その数のコピーが格納されます。
インスタンス(への参照)が格納される変数にインスタンスを代入しますと、その変数にはそのインスタンスへの参照のコピーが格納されます。
インスタンスはコピーされません。
整数(int
型)どうしでは、関係演算子として >
や ==
などが使えました。
インスタンスどうしでは ==
が使えます。
これは参照先が一致していることを意味します。
成分が等しくても置かれている場所が異なれば、インスタンスは(==
の意味で)等しくありません。
次のプログラムは、まず変数 x
に12時30分を表すインスタンス(への参照)を格納します。
そして、変数 y
にはそのインスタンスを直接代入し、変数 z
には成分ごとに代入します。
x
と y
は等しいインスタンスだと判定されますが、x
と z
は等しくないと判定されます。
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%
次のプログラムにおいて、7行目の代入で変数 x
と y
は同じインスタンスを参照します。
この状態を、x
と y
はインスタンスを共有(share)しているといいます。
インスタンスを共有している場合、一方からインスタンスを変更しますと、他方からも変更されたことになります。
9行目で、インスタンス x
の minute
フィールドを変更しますと、インスタンス 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%
これまで定義したメソッドは、引数や返り値が整数(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
が呼び出されますと、同様に t
に x
の値が代入されます。
詳しく言いますと、x
に格納されているデータ(すなわち参照)のコピーが t
に格納されます。
これで、x
と t
は同じインスタンスを共有します。
メソッドの定義内容にしたがい、この共有しているインスタンスは変更されます。
したがって、インスタンス 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%
画用紙の大きさに関するクラスとメソッドを定義します。
はじめに、クラス DrawingPaper
を定義して、画用紙の横の長さ width
(int
型)と縦の長さ height
(int
型)が格納できるようにしてください。
このクラス定義でひとつファイルを作成します。
次に、画用紙の大きさを表示するメソッド 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あてにメールでそのプログラムを提出してください。 メールには、学生番号、氏名、科目名、授業の日付けを明記してください。