[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

コンピュータIIB(Javaプログラミング入門)第13回

目次
13.1 レコードとしてのインスタンス
13.1.1 レコードとは
13.1.2 インスタンスの使い方
13.1.3 コンストラクタ
13.1.4 インスタンスの引数
13.1.5 インスタンスの使用例
13.2 来週の予定
13.3 試験について
13.4 演習13
13.5 レポート課題
13.6 参考文献
索引
インスタンス   コンストラクタ   フィールド   レコード  

13.1 レコードとしてのインスタンス

13.1.1 レコードとは

レコードrecord ) とは、(関連性のある)いくつかのデータをひとまとめにしたものです。 次の図はレコードのイメージを表しています。

レコードのイメージ
図 13.1  レコードのイメージ

レコードの構成要素を フィールドfield ) とよびます。

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

ここで、レコード型とは、レコードを表すデータ型です。

レコード型は、データ型としての名前、フィールドの名前、およびそれぞれのフィールドのデータ型で定義されます。 上記のイメージの場合は、データ型としての名前をTime, フィールドの名前を hourminute , フィールドのデータ型を整数型( int 型)と定義します。

実は、Javaにはレコードはありません。 しかし、 インスタンスinstance ) というものがレコードの機能を持っています。 レコードとインスタンスの対応は次の通りです。

表 13.1  レコードとインスタンスの対応
一般 Java
レコード インスタンス
フィールド インスタンス変数
レコード型 クラス

この授業では、インスタンス、フィールド、およびクラスという用語を用います。

ちなみに、プログラミング言語によっては、レコードのことを構造体とよびます。

13.1.2 インスタンスの使い方

レコードとしてのインスタンスを使うには、まず、クラスを定義します。 フィールドのデータ型が整数型( int 型)なら、クラスの定義は次のようになります。

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

ここで、 classname はクラス名、 fieldname はフィールド名です。 上記の例なら、次の通りです。

/*  1*/ class Time { // クラス名
/*  2*/     int hour, minute; // フィールド名
/*  3*/ }

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

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

/*  1*/ class TimeTest { // Timeクラスのテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         Time x; // 宣言
/*  4*/         x = new Time(); // 生成
/*  5*/         x.hour = 9; // hourフィールドに格納
/*  6*/         x.minute = 30; // minuteフィールドに格納
/*  7*/         System.out.println(x.hour + ":" + x.minute); // フィールドの値を出力
/*  8*/     }
/*  9*/ }
asiaa1:~/comp2b b08a001$ java TimeTest
9:30
asiaa1:~/comp2b b08a001$

変数に整数( 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行目で、インスタンス xhour フィールドに9が格納され、6行目で、 minute フィールドに30が格納されます。

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

variable.fieldname

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

13.1.3 コンストラクタ

クラスのインスタンスを扱う場合、これまでは、インスタンスを生成してからフィールドに値を格納しました。 例えば次のように書きました。

Time x = new Time();
x.hour = 13;
x.minute = 15;

配列では、初期化を使ってプログラムを短くしました。 インスタンスでも、 コンストラクタconstructor ) というものを用いると、初期化に相当することができます。 上記の例なら、例えば次のように書けます。

Time x = new Time(13, 15);

もし、クラスが

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

と定義されていたら、次のように定義し直すと、コンストラクタが使えるようになります。

class classname {
    int fieldname1, ..., fieldnamen;
    classname (int fieldname1, ..., int fieldnamen) {
        this.fieldname1 = fieldname1;
        ...
        this.fieldnamen = fieldnamen;
    }
}

これで、式

new classname(argument1, ..., argumentn)

を呼び出すと、フィールド fieldname 1 に値 argument 1 を格納し、…、フィールド fieldname n に値 argument n を格納したインスタンスになります。

コンストラクタはメソッドに似ています。 どちらも、あらかじめ定義しておき、呼出しによってその機能が働きます。 メソッドとコンストラクタは以下の点が異なります。

次のプログラムでは、チャイムの時刻を表すクラスChimeを定義しています。 Chime.java の3行目から6行目までが、コンストラクタ定義です。 このコンストラクタは、第1引数を hour フィールドに格納し、第2引数を minute フィールドに格納します。 ChimeTest.java の3行目で、このコンストラクタが呼び出され、 hour フィールドに10が格納され、 minute フィールドに30が格納されます。

Chime.java
/*  1*/ class Chime { // チャイムの時刻
/*  2*/     int hour, minute;
/*  3*/     Chime (int hour, int minute) { // コンストラクタ定義
/*  4*/         this.hour = hour;
/*  5*/         this.minute = minute;
/*  6*/     }
/*  7*/ }
ChimeTest.java
/*  1*/ class ChimeTest { // Chimeクラスのテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         Chime c = new Chime(10, 30); // コンストラクタ呼出し
/*  4*/         System.out.println(c.hour + ":" + c.minute);
/*  5*/     }
/*  6*/ }
asiaa1:~/comp2b b08a001$ java ChimeTest
10:30
asiaa1:~/comp2b b08a001$

注意1. 上記のコンストラクタは、「典型的なコンストラクタ」と呼ぶべきものです。 一般的には、コンストラクタはより複雑な機能を持ちます。

注意2. 上記のようにコンストラクタを定義すると、 new Chime() ではインスタンスが生成できなくなります。 実は、コンストラクタを定義しなければ引数なしのコンストラクタが自動的に用意され、コンストラクタを定義すると定義したものだけが使えるという規則になっています。 引数ありと引数なしの両方のコンストラクタを使うには、次のように両方定義します。

class Chime {
    int hour, minute;
    Chime () {
    }
    Chime (int hour, int minute) {
        this.hour = hour;
        this.minute = minute;
    }
}

13.1.4 インスタンスの引数

前回、引数が配列であるメソッドを定義しました。 引数がインスタンスであるメソッドも、同じように定義できます。 これによって、インスタンスに関する処理にも名前を付けることができます。

引数がインスタンスであるメソッドを定義するには、整数のときの int の代わりに、クラス名を書きます。 値を返さないメソッドならば、

static void methodname (classname argument, ...) {
    statement; ...
}

と書き、整数( int 型)を返すメソッドならば、

static int methodname (classname argument, ...) {
    statement; ...
}

と書きます。

メソッドを呼び出すには、引数にインスタンスを表す変数名を書きます。 値を返さないメソッドを呼び出すには、文として

methodname(argument, ...);

と書きます。 値を返すメソッドを呼び出すには、式として

methodname(argument, ...)

と書きます。

ここで、例として、1:30 = 90(1時間30分は90分間)という計算をするプログラムを考えます。

ファイルPeriod.javaでは、期間を格納するために、Periodというクラスを定義します。 hour というフィールドには時間を、 minute というフィールドには分を格納します。 コンストラクタは、引数が時間、分の順になるように定義します。

Period.java
/*  1*/ class Period { // 期間
/*  2*/     int hour, minute;
/*  3*/     Period (int hour, int minute) {
/*  4*/         this.hour = hour;
/*  5*/         this.minute = minute;
/*  6*/     }
/*  7*/ }

メソッドを使わないプログラムは以下の通りです。

/*  1*/ class PeriodTest { // Periodクラスのテスト
/*  2*/     public static void main (String[] args) {
/*  3*/         Period period = new Period(1, 30); // 期間は1時間30分
/*  4*/         System.out.print(period.hour + ":" + period.minute); // 期間を出力
/*  5*/         System.out.println(" = " + (period.hour * 60 + period.minute)); // 通算の分を計算
/*  6*/     }
/*  7*/ }
asiaa1:~/comp2b b08a001$ java PeriodTest
1:30 = 90
asiaa1:~/comp2b b08a001$

このプログラムを、メソッドを使って書き直します。

期間を出力するメソッドの名前は printPeriod とします。 このメソッドの引数は、Periodクラスの p です。 このメソッドは値を返さないので、 static void と指定します。

通算の分を計算するメソッドの名前は getTotal とします。 このメソッドの引数は、Periodクラスの p です。 このメソッドは整数( int 型)を返すので、 static int と指定します。

/*  1*/ class PeriodTest2 { // Periodクラスのテスト2
/*  2*/     public static void main (String[] args) {
/*  3*/         Period period = new Period(1, 30);
/*  4*/         printPeriod(period);
/*  5*/         System.out.println(" = " + getTotal(period));
/*  6*/     }
/*  7*/     static void printPeriod (Period p) {
/*  8*/         System.out.print(p.hour + ":" + p.minute);
/*  9*/     }
/* 10*/     static int getTotal (Period p) {
/* 11*/         return p.hour * 60 + p.minute;
/* 12*/     }
/* 13*/ }

13.1.5 インスタンスの使用例

インスタンスの例として、次のように長方形を格納して面積を計算するプログラムを作成します。

Rectangle rect1 = new Rectangle(10, 50);
Rectangle rect2 = new Rectangle(20, 40);
Rectangle rect3 = new Rectangle(30, 30);

ファイルRectangle.javaでは、長方形を格納するために、Rectangleというクラスを定義します。 width というフィールドには幅を、 height というフィールドには高さを格納します。 コンストラクタは、引数が幅、高さの順になるように定義します。

Rectangle.java
/*  1*/ class Rectangle { // 長方形
/*  2*/     int width, height; // 幅と高さ
/*  3*/     Rectangle (int width, int height) {
/*  4*/         this.width = width;
/*  5*/         this.height = height;
/*  6*/     }
/*  7*/ }

ファイルRectangleMain.javaでは、メソッドを定義します。

長方形の大きさを出力するメソッドの名前は printRectangle とします。 このメソッドの引数は、Rectangleクラスの r です。 このメソッドは値を返しませんので、 static void と指定します。

面積を計算するメソッドの名前は getArea とします。 このメソッドの引数は、Rectangleクラスの r です。 このメソッドは整数( int 型)を返すので、 static int と指定します。

プログラムは次の通りです。

RectangleMain.java
/*  1*/ class RectangleMain { // 長方形のメイン
/*  2*/     public static void main (String[] args) {
/*  3*/         Rectangle rect1 = new Rectangle(10, 50);
/*  4*/         Rectangle rect2 = new Rectangle(20, 40);
/*  5*/         Rectangle rect3 = new Rectangle(30, 30);
/*  6*/         printRectangle(rect1);
/*  7*/         System.out.println("の面積は" + getArea(rect1));
/*  8*/         printRectangle(rect2);
/*  9*/         System.out.println("の面積は" + getArea(rect2));
/* 10*/         printRectangle(rect3);
/* 11*/         System.out.println("の面積は" + getArea(rect3));
/* 12*/     }
/* 13*/     static void printRectangle (Rectangle r) {
/* 14*/         System.out.print("幅" + r.width + "高さ" + r.height);
/* 15*/     }
/* 16*/     static int getArea (Rectangle r) {
/* 17*/         return r.width * r.height;
/* 18*/     }
/* 19*/ }
asiaa1:~/comp2b b08a001$ java RectangleMain
幅10高さ50の面積は500
幅20高さ40の面積は800
幅30高さ30の面積は900
asiaa1:~/comp2b b08a001$

13.2 来週の予定

シラバスに書いた通り、来週の授業中に試験を行います。 来週は欠席しないようにしてください。

また、来週の授業中に、授業評価のアンケートを実施します。 アンケートはマークシート方式なので、鉛筆かシャープペンシルを持参してください。


13.3 試験について

来週の試験は、授業の教室で、授業の後半の30分間で実施します。 試験の方法は筆記試験で、資料の持ち込みやパソコンの利用は不可とします。 以下に練習問題(全20問)を載せますので、試験勉強の参考にしてください。 この問題はレポート課題ではないので、回答を提出する必要はありません。

問1. Javaで、整数100を表すにはどう書けばよいか。 以下の中から最も適切なものを選びなさい。

A. 100.0
B. 100
C. "100.0"
D. "100"

問2. Javaで、文 System.out.println(1 + 2 * 3); を実行すると何が出力されるか。 以下の中から最も適切なものを選びなさい。

A. 7
B. 9
C. 1 + 2 * 3
D. 2 * 4

問3. Javaで、整数を格納できる変数 x を宣言するにはどう書けばよいか。 以下の中から最も適切なものを選びなさい。

A. int x;
B. integer x;
C. double x;
D. double precision x;

問4. Javaで、 x が整数型の変数のとき、文 x = x + 1; は何を意味するか。 以下の中から最も適切なものを選びなさい。

A. x の値を1増加させる。
B. xx + 1 は等しい。
C. x の値を1減少させる。
D. x - 1x は等しい。

問5. Javaで、 x が整数型の変数のとき、文 x++; は何を意味するか。 以下の中から最も適切なものを選びなさい。

A. x の値を2増加させる。
B. x の値を1増加させる。
C. x の値を2減少させる。
D. x の値を1減少させる。

問6. Javaで、実数(浮動小数点数) 1.0E-3 はどの値を表すか。 以下の中から最も適切なものを選びなさい。

A. 0.01
B. 0.001
C. 0.0001
D. 0.00001

問7. Javaで、文 if (0 > 10) { System.out.println("*"); } を実行すると(論理的に)どうなるか。 以下の中から最も適切なものを選びなさい。

A. 記号 * が1回出力される。
B. 記号 * が2回出力される。
C. 記号 * が無限回出力される。
D. 何も出力されない。

問8. Javaで、整数型の変数 xy に対して「 xy は等しい」という条件を書くにはどうすればよいか。 以下の中から最も適切なものを選びなさい。

A. x = y
B. x == y
C. x <> y
D. x >< y

問9. Javaで、整数型の変数 x に対して「 x は20以上60未満」という条件を書くにはどうすればよいか。 以下の中から最も適切なものを選びなさい。

A. 20 <= x && x < 60
B. 20 <= x < 60
C. 20 <= x || x < 60
D. 20 <= x, x < 60

問10. Javaで、 if 文の中に else と書いていたら、これは何を意味するか。 以下の中から最も適切なものを選びなさい。

A. 必ず実行される。
B. 決して実行されない。
C. 条件が成り立つ場合に実行される。
D. 条件が成り立たない場合に実行される。

問11. Javaで、 switch 文の中に default と書いていたら、これは何を意味するか。 以下の中から最も適切なものを選びなさい。

A. ある case の定数と等しい場合に実行される。
B. どの case の定数とも異なる場合に実行される。
C. 必ず実行される。
D. 決して実行されない。

問12. Javaで、文 while (0 > 10) { System.out.println("*"); } を実行すると(論理的に)どうなるか。 以下の中から最も適切なものを選びなさい。

A. 記号 * が1回出力される。
B. 記号 * が2回出力される。
C. 記号 * が無限回出力される。
D. 何も出力されない。

問13. Javaで、 i が整数型の変数のとき、文 for (i = 0; i < 10; i++) { System.out.println("*"); } を実行するとどうなるか。 以下の中から最も適切なものを選びなさい。

A. 記号 * が9回出力される。
B. 記号 * が10回出力される。
C. 記号 * が11回出力される。
D. 記号 * が12回出力される。

問14. Javaで、繰返しを途中で終了するにはどの文を使うとよいか。 以下の中から最も適切なものを選びなさい。

A. while
B. break
C. for
D. switch

問15. Javaで、文 int[] a = new int[10]; を実行すると、どの範囲の配列要素が生成されるか。 以下の中から最も適切なものを選びなさい。

A. a[0] から a[9] までの10要素。
B. a[0] から a[10] までの11要素。
C. a[1] から a[9] までの9要素。
D. a[1] から a[10] までの10要素。

問16. Javaで、要素数10の整数の配列 a を生成してから文 a[20] = 0; を実行するとどうなるか。 以下の中から最も適切なものを選びなさい。

A. この文は無視される。
B. この文でエラーが発生する。
C. この文で a[20] だけが新たに生成される。
D. この文で a[20] を含む複数の配列要素が新たに生成される。

問17. Javaで、配列 a の要素数を表す式は何か。 以下の中から最も適切なものを選びなさい。

A. a.size
B. a.count
C. a.length
D. a.number

問18. Javaで、メソッド printNumberstatic void printNumber (int n) { System.out.println(n); } と定義した。 この int n は何を意味しているか。 以下の中から最も適切なものを選びなさい。

A. このメソッドは整数の値を返す。
B. このメソッドは整数の引数を取る。
C. このメソッドは実数(浮動小数点数)を整数に変換する。
D. このメソッドは整数を実数(浮動小数点数)に変換する。

問19. Javaで、メソッド printNumberstatic void printNumber (int n) { System.out.println(n); } と定義した。 この void は何を意味しているか。 以下の中から最も適切なものを選びなさい。

A. このメソッドは値を返さない。
B. このメソッドは引数を取らない。
C. このメソッドは何もしない。
D. このメソッドは呼出しができない。

問20. Javaで、メソッド定義から呼び出し側に値を返すにはどの文を使うとよいか。 以下の中から最も適切なものを選びなさい。

A. if
B. return
C. while
D. for

13.4 演習13

ある小学校で国語と算数の試験を行ったと想定し、次の出力が得られるようなプログラムを作成してください。

asiaa1:~/comp2b b08a001$ java ExaminationMain
国語80算数70の合計は150
国語90算数80の合計は170
国語100算数90の合計は190
asiaa1:~/comp2b b08a001$

試験の得点は次のように格納します。

Examination exam1 = new Examination(80, 70);
Examination exam2 = new Examination(90, 80);
Examination exam3 = new Examination(100, 90);

ファイルExamination.javaでは、試験の得点を格納するために、クラスExaminationを定義します。 フィールド japanese には国語の得点を、フィールド arithmetic には算数の得点を格納します。 コンストラクタは、引数が国語、算数の順になるように定義します。

ファイルExaminationMain.javaでは、メソッドを定義します

試験の得点を出力するメソッドの名前は printExamination とします。 このメソッドの引数は、Examinationクラスの e です。 このメソッドは値を返さないので、 static void と指定します。

合計を計算するメソッドの名前は getTotal とします。 このメソッドの引数は、Examinationクラスの e です。 このメソッドは整数( int 型)を返すので、 static int と指定します。

余力のある人は、平均を計算するメソッド getAverage も定義し、それを呼び出して、出力してください。

asiaa1:~/comp2b b08a001$ java ExaminationMain2
国語80算数70の合計は150で平均は75
国語90算数80の合計は170で平均は85
国語100算数90の合計は190で平均は95
asiaa1:~/comp2b b08a001$

13.5 レポート課題

今日の演習13の答案(Javaプログラム)をメールで提出してください。 差出人は学内のメール・アドレス(b08a001@cis.twcu.ac.jpなど)とし、宛先はkonishi@cis.twcu.ac.jpとします。 メールの本文には、学生番号、氏名、科目名、授業日(7月16日)を明記してください。


13.6 参考文献


[小西ホームページ]   [目次・索引]   [前の授業]   [次の授業]

2010年7月16日更新
小西 善二郎 <konishi@cis.twcu.ac.jp>
Copyright (C) 2010 Zenjiro Konishi. All rights reserved.