目次 | 索引 |
---|---|
レコード ( record )とは、いくつかのデータをひとまとめにしたものです。 次の図はレコードのイメージを表しています。
レコードの構成要素を フィールド ( field )とよびます。
データをまとめたものとして、以前に配列を取り上げました。 レコードと配列には次のような違いがあります。
int[]
などと規則的な名前がつきますが、レコード型には個別に名前がつきます。
ここでレコード型とは、レコードを表すデータ型です。
レコード型の定義は、データ型としての名前、フィールドの名前、およびどのフィールドにどのデータ型が格納できるかの指定で成り立ちます。
ここで、フィールド
hour
と
minute
に整数(
int
型)が格納できるレコード型
Time
を定義します。
上記のレコードは
Time
型と考えることができます。
実は、Javaにはレコードはありません。 しかし、 インスタンス ( instance )というものがレコードの機能を持っています。 レコードとインスタンスの対応は次の通りです。
一般 | Java |
---|---|
レコード | インスタンス |
フィールド | インスタンス変数 |
レコード型 | クラス |
この授業では、インスタンス、フィールド、およびクラスという用語を用います。 ちなみに、プログラミング言語によっては、レコードのことを構造体とよびます。
レコードとしてのインスタンスを使うには、まずクラスを定義する必要があります。
フィールドに格納するデータが整数(
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
には、インスタンスが置かれている「場所データ」が格納されるのです。
参照は、しばしば矢印で書き表わされます。
参照をポインタやアドレスのようなものだと思っても差し支えありません。
インスタンスと同様、変数に配列を代入しましても、その変数にはその配列への参照が格納されます。 例えば、
int[] a = {91, 74, 57, 40, 23};
のように配列を初期化しますと、次の図のようになります。
以下ではインスタンスへの参照について説明します。 配列への参照についても同じことが言えます。
参照が格納される変数の値を変えることは、参照先を変更することになります。
次のプログラムでは、まず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
型)が格納される変数に数を代入しますと、その変数にはその数が格納されます。
詳しく言いますと、その数のコピーが格納されます。
インスタンス(への参照)が格納される変数にインスタンスを代入しますと、その変数にはそのインスタンスへの参照のコピーが格納されます。
インスタンスはコピーされません(次の例の8行目)。
整数(
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%
都道府県別の産業構造を計算するJavaアプリケーションを作成してください。 ここで産業構造とは、就業者総数に対する第1次産業、第2次産業、および第3次産業の割合とします。 47都道府県のデータを入力するのは大変ですので、ここでは北海道、東京都、および石川県を選びます。 (他の都道府県でもかまいませんが、少なくとも3つ選んでください。) データは、1995年の国勢調査
http://www.stat.go.jp/data/kokusei/1995/07.htm
に基づきます。
都道府県 | 就業者総数 | 第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
クラスにまとめることがポイントです。
class Prefecture { ??? // 就業者人口(workers)、第1次産業(primary)、 ??? // 第2次産業(secondary)、第3次産業(tertiary)の ??? // 4つのフィールドを定義する。 }
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に従ってJavaプログラムを作成し、そのプログラムをkonishi@twcu.ac.jpあてにメールで提出してください。 メールには、学生番号、氏名、科目名、授業日(11/8)を明記してください。