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

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

目次 索引
8.1 レコードとしてのインスタンス
8.1.1 レコードとは
8.1.2 インスタンスの使い方
8.2 参照
8.2.1 参照とは
8.2.2 インスタンスの代入
8.2.3 インスタンスの比較
8.2.4 インスタンスの共有
8.3 演習8
8.4 レポート課題

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

8.1.1 レコードとは

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

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

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

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

ここでレコード型とは、レコードを表すデータ型です。 レコード型の定義は、データ型としての名前、フィールドの名前、およびどのフィールドにどのデータ型が格納できるかの指定で成り立ちます。 ここで、フィールド hourminute に整数( int 型)が格納できるレコード型 Time を定義します。 上記のレコードは Time 型と考えることができます。

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

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

この授業では、インスタンス、フィールド、およびクラスという用語を用います。 ちなみに、プログラミング言語によっては、レコードのことを構造体とよびます。

8.1.2 インスタンスの使い方

レコードとしてのインスタンスを使うには、まずクラスを定義する必要があります。 フィールドに格納するデータが整数( 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 フィールドからデータを取り出して、出力します。


8.2 参照

8.2.1 参照とは

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

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

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

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

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

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

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

以下ではインスタンスへの参照について説明します。 配列への参照についても同じことが言えます。

8.2.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.4  参照の変更

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

8.2.3 インスタンスの比較

整数( 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 instances
図 8.5  インスタンスの同等性

8.2.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.6  インスタンスの共有

8.3 演習8

都道府県別の産業構造を計算するJavaアプリケーションを作成してください。 ここで産業構造とは、就業者総数に対する第1次産業、第2次産業、および第3次産業の割合とします。 47都道府県のデータを入力するのは大変ですので、ここでは北海道、東京都、および石川県を選びます。 (他の都道府県でもかまいませんが、少なくとも3つ選んでください。) データは、1995年の国勢調査

http://www.stat.go.jp/data/kokusei/1995/07.htm

に基づきます。

表 8.2  3都道府県の産業別人口(単位:千人)
都道府県 就業者総数 第1次産業 第2次産業 第3次産業
北海道 2806 251 659 1881
東京都 6310 31 1615 4547
石川県 631 34 212 384

出力結果は以下の通りです。 北海道の第1次産業の就業者は8%などという意味です。 合計が100%にならないのは、端数の切り捨てなどが原因です。

b00a001@Ampere:~/java% java PrefectureTest
Hokkaido: 8%, 23%, 67%.
Tokyo: 0%, 25%, 72%.
Ishikawa: 5%, 33%, 60%.
b00a001@Ampere:~/java% 

プログラムは穴埋めとします。 コメントを参考にして、2つのファイル(Prefecture.javaとPrefectureTest.java)を完成させてください。 都道府県ごとのデータを Prefecture クラスにまとめることがポイントです。

Prefecture.java
class Prefecture {
    ??? // 就業者人口(workers)、第1次産業(primary)、
    ??? // 第2次産業(secondary)、第3次産業(tertiary)の
    ??? // 4つのフィールドを定義する。
}
PrefectureTest.java
class PrefectureTest {
    public static void main (String[] args) {
        ??? // インスタンスを生成し、それぞれのフィールドに
        ??? // データを格納する。
        System.out.print("Hokkaido: ");
        printRatios(hokkaido.workers, hokkaido.primary,
                    hokkaido.secondary, hokkaido.tertiary);
        System.out.println();
        System.out.print("Tokyo: ");
        printRatios(tokyo.workers, tokyo.primary,
                    tokyo.secondary, tokyo.tertiary);
        System.out.println();
        System.out.print("Ishikawa: ");
        printRatios(ishikawa.workers, ishikawa.primary,
                    ishikawa.secondary, ishikawa.tertiary);
        System.out.println();
    }
    static void printRatios (int workers, int primary,
                             int secondary, int tertiary) {
        ??? // 3つの百分率を計算し出力する。
    }
}

8.4 レポート課題

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


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

2001年11月8日更新
konishi@twcu.ac.jp
Copyright (C) 2001 Zenjiro Konishi. All rights reserved.