9. 1 復習(1) 9. 2 オブジェクト 9. 3 インスタンス変数 9. 4 練習問題 9. 5 インスタンスを作る 9. 6 練習問題 9. 7 インスタンスのメソッド 9. 8 練習問題 9. 9 クラス変数とクラスメソッド 9.10 宿題 9.11 おまけ
| プログラミングの基本的な概念を第8週までで一通り説明しました。これまで に出てきた概念は、Java 言語だけに限らず、他の言語でプログラムを書く場 合にも必要になるものです。今週以降は、復習の節を設けますので、ここまで のところに不安がある人は、習ったことを確認して完全に理解するようにして ください。 |
Java 言語のプログラムはクラスとメソッドで出来ています。メソッドの中で は普通上から下に順に実行していきますが、実行の流れを変える文がいくつか あります。
[問]1から100までの数字のうち、偶数だけの合計を求めるにはどうすればよ
いでしょう?for文を使う方法、while文を使う方法、
for文とif文を使う方法など、何種類もの解き方がありま
す。いくつ考えつきますか?
プログラミング言語にはいろいろな種類がありますが、その中にオブジェ
クト指向プログラミング言語(object oriented programming language)
と呼ばれるものがあり、Java 言語もその一つです。これは、計算の単位とし
てオブジェクトと呼ばれるものを使います。
オブジェクト(object)とは、いくつかのデータやメソッドをまと
めて一塊にしたものです。小さなプログラムを作るときはそれほど便利さを感
じませんが、大きなプログラムを作るときは、オブジェクトに分割することに
よって見通しが良くなるので重要です。
オブジェクトは、直接ソースファイルの中に書くものではありません。ソース
ファイルの中に書くのはクラスです。オブジェクトは、クラスを基にして作り
ます。例えば、タコ焼の鉄板をクラスとすると、それで焼いたタコ焼がオブジェ
クトになります。クラス A を基にして作ったオブジェクトを、クラ
スA のインスタンス(instance)と呼びます。一つのクラ
スから、いくつでもインスタンスを作ることができます。
それぞれのインスタンスは、データを覚えておくための変数をいくつか持つこ
とができます。これをインスタンス変数(instance variable)と呼
びます。同じクラスのインスタンスは、同じ名前のインスタンス変数を持ちま
すが、変数が記憶しているデータはインスタンスごとに違います。
インスタンス変数の変数宣言は、クラス宣言の本体の中で、どのメソッド宣言
にも入らない場所で行います。例えば、第1週の例題
9.2 オブジェクト
9.3 インスタンス変数
class Count extends SfcDoNothing {
int x = 0;
void sfcProcess () {
x = x + 1;
sfcOutput(Integer.toString(x));
}
}
|
class Precision extends SfcDoNothing {
void sfcProcess () {
double x = 0.0;
for (int i = 1000000; i >= 1; i = i - 1) {
x = x + 1.0 / i;
}
sfcOutput(Double.toString(x));
}
}
|
| インスタンス変数 | ローカル変数 | 仮引数 | |
|---|---|---|---|
| 変数宣言 | クラス宣言の中でメソッド宣言の外 | メソッ ド宣言の中 | メソッド名の直後の括弧の中 |
| 有効範囲 | プログラム全体(注1) | 変数宣言を含む最も内側 のブロックだけ(注2) | そのメソッドだけ |
| 初期値 | インスタンスが作られた時に初期値が代入される | 変数宣言が実行されるときに初期値が代入される | メソッド 呼び出しの時に実引数が代入される |
| 存続期間 | ずっと存在する | ブロックの実行が終了す ると消えてしまう(注2) | メソッドの実行が終了すると消えてしまう |
(注1)そのインスタンス自身が使うときは変数名だけを書きますが、他のイン スタンスで使うときは、
インスタンス.変数名
と書きます。
(注2)for の直後の括弧の中で宣言された変数は、有効範囲がその
for 文全体で、存続期間はその for 文が終了するまでで
す。
9.4 練習問題
上の第1週の例題で、変数宣言の位置を次のように変えるとどうなるでしょう
か。ボタンをクリックしたときの動作を予想し、実際にそうなるか確かめなさ
い。
class Count extends SfcDoNothing {
void sfcProcess () {
int x = 0;
x = x + 1;
sfcOutput(Integer.toString(x));
}
}
|
今まで練習で書いてきたクラスは、SfcExample1 または SfcExample2 がインスタンスを一つだけ作って、その中のメソッド を呼び出してくれていました。今度は自分でインスタンスを作る練習をしましょう。
クラス A のインスタンスを新しく作るには、
new A(引数)
と書きます。引数のところには、そのインスタンスに与えるデータを書きます。
同じ鉄板を使って焼くタコ焼でも、中にはタコを入れたり、イカを入れたりで
きます。
作ったインスタンスを記憶しておくには、そのクラスに対応する型の変数に代 入しなければなりません。クラス A のインスタンスを作って、変数 x に覚えておくには、次のようにします。
A x = new A(引数);
違うクラスの型の変数に代入することはできません。お好み焼きの皿にタコ焼
を盛り付けてはいけません。
![]()
ただし、二つのクラスが継承関係にある場合は、スーパークラスの型の変数に
サブクラスのインスタンスを代入することができます。
|
先週の国別の人口と GDP のデータを考えてみましょう。
| Country | Total Population (in thousands, 1997 est.) | GDP (million US$, 1995) |
| United Kingdom | 58201 | 1102658 |
| Egypt | 64466 | 60436 |
| India | 960178 | 338785 |
| Japan | 125638 | 5217573 |
| Australia | 18250 | 358147 |
| United States of America | 271648 | 6954787 |
| Brazil | 163132 | 717187 |
class Nation {
String name;
int population;
int gdp;
}
これだけでも、new Nation() とすれば、インスタンスを作ることが
できます。しかし、そのインスタンスの変数の中身は空っぽなので、役に立ち
ません。後から変数それぞれに代入していくこともできますが、それではかえっ
て面倒です。そこで、クラスの中にコンストラクタ(constructor)
を宣言して、インスタンスを作るときにその中身も作るようにします。
1 2 3 4 5 6 7 8 9 10 11 |
class Nation {
String name;
int population;
int gdp;
Nation(String n, int p, int g) {
name = n;
population = p;
gdp = g;
}
}
|
クラス Nation を使って、グラフを描くクラス Nations を書いてみましょう。ファイル NationGraph.java の内容を次のように 書いてください。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 |
import java.awt.*;
class Nation {
String name;
int population;
int gdp;
Nation(String n, int p, int g) {
name = n;
population = p;
gdp = g;
}
}
class NationGraph extends SfcDoNothing {
void sfcDraw(Graphics g) {
Nation data[] = new Nation[7];
data[0] = new Nation("UK", 58201, 1102658);
data[1] = new Nation("Egypt", 64466, 60436);
data[2] = new Nation("India", 960178, 338785);
data[3] = new Nation("Japan", 125638, 5217573);
data[4] = new Nation("Australia", 18250, 358147);
data[5] = new Nation("USA", 271648, 6954787);
data[6] = new Nation("Brazil", 163132, 717187);
for (int i = 0; i < data.length; i = i + 1) {
g.setColor(Color.black);
g.drawString(data[i].name, 10, i*30+30);
g.setColor(Color.blue);
g.fillRect(80, i*30+15, data[i].population*200/1000000, 10);
g.setColor(Color.green);
g.fillRect(80, i*30+25, data[i].gdp*200/7000000, 10);
}
}
}
|
これを
% javac NationGraph.java
でコンパイルすると、NationGraph.class と
Nation.class という二つのクラスファイルができます。実行すると
きは、SfcDoNothing を拡張したクラスを指定するので、
% java sfcExample2 NationGraph
とします。
Nation クラスのデータをソートするプログラムを作りましょう。
Boolean CompareNation(Nation x, Nation y, String key) {
if (key.equals("name")) {
......
int findHead(Nation a[], int n, String key) {
Nation head = a[n];
int index = n;
for (int i = .....
void swap(Nation a[], int n, int m) {
Nation tmp = a[n];
........
![]() ![]()
メソッド呼び出しの時、仮引数には、実引数の値がコピーされます。この値を
変更しても、オリジナルの実引数は影響を受けません。ただし、配列やインス
タンスの場合、実体は一つだけで、コピーされるのはその実体を指し示す矢印
です。したがって、メソッドの中で配列のデータを入れ替えると、実体の内容
が変更され、これはメソッドを呼び出した方にも影響します。
|
インスタンスは、変数の中にデータを記憶するだけでなく、メソッドを実行す ることで計算も行います。これまではインスタンスが1個しかなかったので、 どのインスタンスのメソッドかということは考えませんでしたが、メソッドを 実行するときは、必ずそれを実行しているインスタンスが存在します。
国別の、一人当たり GDP を計算するメソッドを追加しましょう。
class Nation {
String name;
int population;
int gdp;
Nation(String n, int p, int g) {
name = n;
population = p;
gdp = g;
}
int gdpPerPerson() {
return gdp/population;
}
}
gdpPerPerson を呼び出すときは、実行するインスタンスを指定して、
インスタンス.gdpPerPerson()
とします。引数がないことに注意してください。計算に必要な人口と GDP の
値は、インスタンスの中にある変数の値を使います。先ほどのグラフの、GDP
の代わりに一人当たり GDP を表示するプログラムは次のようになります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 |
import java.awt.*;
class Nation {
String name;
int population;
int gdp;
Nation(String n, int p, int g) {
name = n;
population = p;
gdp = g;
}
int gdpPerPerson() {
return gdp/population;
}
}
class NationGraph extends SfcDoNothing {
void sfcDraw(Graphics g) {
Nation data[] = new Nation[7];
data[0] = new Nation("UK", 58201, 1102658);
data[1] = new Nation("Egypt", 64466, 60436);
data[2] = new Nation("India", 960178, 338785);
data[3] = new Nation("Japan", 125638, 5217573);
data[4] = new Nation("Australia", 18250, 358147);
data[5] = new Nation("USA", 271648, 6954787);
data[6] = new Nation("Brazil", 163132, 717187);
for (int i = 0; i < data.length; i = i + 1) {
g.setColor(Color.black);
g.drawString(data[i].name, 10, i*30+30);
g.setColor(Color.blue);
g.fillRect(80, i*30+15, data[i].population*200/1000000, 10);
g.setColor(Color.orange);
g.fillRect(80, i*30+25, data[i].gdpPerPerson()*200/80, 10);
}
}
}
|

変数宣言やメソッド宣言の前に static と書くと、その変数やメソッ ドはインスタンスにではなく、クラスに属することになります。そのような変 数、メソッドを使うときは、
クラス名.変数名
および
クラス名.メソッド名(引数)
と書きます。例えば、Integer.parseInt() は、Integer
クラスに属する parseInt メソッドです。クラスに属する変数、メ
ソッドは、インスタンスを作らなくても使えます。
次のような入試結果があるとします。
| 受験番号 | 英語 | 数学 | 小論文 |
|---|---|---|---|
| 1001 | 61 | 75 | 50 |
| 1002 | 80 | 52 | 70 |
| 1003 | 73 | 68 | 80 |
| 1004 | 40 | 52 | 40 |
| 1005 | 56 | 82 | 60 |
各受験生の得点は、英語と数学のどちらか良い方と小論文の合計点であるとし
ます。各受験生を表すクラスと、得点を計算するメソッドを作り、そのインス
タンスを使って得点の高い順にソートするプログラムを作りなさい。
9.11 おまけ
StringTokenizer クラスを使うと、文字列をコンマなどの区切りで
分解して取り出すことができます。使い方は次の通りです。
これを使って、X 座標、Y 座標、半径を入力し、その位置に円を描くプログラ
ムを作りなさい。
import java.util.StringTokenizer;
を書きます。
new StringTokenizer(String s, String separator);
s は分解したい文字列、separator は区切り文字です。例
えば、"100,200,40" という文字列をコンマで区切って分解したいと
きは、
StringTokenizer st = new StringTokenizer("100,200,40", ",");
とします。
String nextToken()
上の例では、最初に st.nextToken() を実行すると、
"100" が、2回目に実行すると "200" が、3回目に実行す
ると "40" が返ってきます。
慶應義塾大学の授業以外での無断利用、複製はご遠慮下さい。
Copyright (c) 1999 慶應義塾大学