問題1

解説:
事物の「概念」をプログラム上で表現するために「クラス」を定義する。
クラスの中で定義するものを「メンバ」という。(クラスの一員(メンバ)というわけ)
「クラス」で事物の概念を表現するために「メンバ」として
・変数(「フィールド」)〜その「概念」を表すのに必要な情報を表現する
・メソッド 〜その「概念」の振る舞いを表現する
を定義する。
以下の例では,「人」という概念を表すためにPersonというクラスを作り,
そのメンバとして
・年齢を表すフィールドage,身長体重を表すフィールドheight,weight
・「話す」という振る舞いを表すためにtalk()メソッド
が定義されている。
class Person {
int age;
double height, weight;
void talk() { System.out.println( "hello!" ); }
}
|
問題2

「インスタンス」は「変数(variable)」の別の言い方と思って良い。
クラス型のインスタンスを「オブジェクト」と呼ぶ。
各オブジェクトのフィールドは異なる値を持つことができるので,
各オブジェクトは「フィールド」の値によって個性を持つことになる。
例えば,上の例に挙げたPerson型では
Person taro = new Person();
Person nahako = new Person();
taro.age = 20; taro.height = 172.0; taro.weight = 65.0;
hanako.age = 18; taro.height = 153.0; taro.weight = 50.0;
|
という場合,
・taroオブジェクトは20歳,身長体重は172cm,65kg
・hanakoオブジェクトは18歳,身長体重は153cm,50kg
というようにそれぞれ個性を持つことになる。
オブジェクトを生成するとき,いっしょにフィールドの値も初期化
すると良い。オブジェクトをnewで生成するときに呼び出すことの
出来る初期化専用のメソッドを「コンストラクタ」と呼ぶ。コンス
トラクタは返値型の指定がなく,名前がクラス名と一致する。上の
例のPerson型にコンストラクタを追加すると以下のようになる(紫字
部分)。仮引数名とフィールド名が同じなので,区別するためにフィー
ルド名の方には,「このオブジェクトの」という意味の「this.」を
つけている。コンストラクタの使用例は赤字部分。
class Person {
int age;
double height, weight;
Person( int age, double height, double weight ) {
this.age = age; this.height = height; this.weight = weight;
}
void talk() { System.out.println( "hello!" ); }
publis static void mani( String args[] ) {
Person taro = new Person( 20, 172.0, 65.0 );
taro.talk();
}
}
|
オブジェクト指向の大事な考え方に「クラスの継承」がある。たとえば
「動物」という概念を表すクラスを「スーパークラス」として,その
「サブクラス」として「猫」を表すクラスCatを定義できる。サブクラス
は,スーパークラスのメンバをすべて受け継ぐ(「継承」)。そのため,
サブクラス(のオブジェクト)はスーパクラス(のオブジェクト)としての
能力も持つことになり,
「サブクラスはスーパークラスの一種」= サブクラス is-a スーパークラス
という関係が成立する。このような関係を
is-a関係
と呼ぶ。(「is-a」には「〜は〜の一種」という意味がある)
図でサブクラスとスーパークラスの関係を描くときは,サブクラスから
スーパークラスへ向けて矢印を書く。Javaでは,すべてのクラスのスーパ
ークラスとして,「Object」という特別なクラスが用意されている。
問題3

基本的なクラス定義は出来るようにしておこう。
class MyClass {
public static void main( String args[] ) {
System.out.println( "hello!" );
}
}
|
StringとSystemの頭文字は大文字であることに注意。StringもSystemもJava
に元から用意されているクラスである。
問題4

解説:
Javaのソースファイルには,複数クラスが書けるが,そのうち一個だけがpublic指定できる。
(public指定されたクラスは他のパッケージからも利用できるようになる)
その唯一のpublicクラスの名前がファイル名と同じになる。もしソースファイルに書かれた
クラスがひとつだけならpublic指定しているかどうかにかかわらず,そのクラス名がファイル
名になる。問題の例では,
MyClass.java
がファイル名になる。
また,このファイルをコンパイルするには
javac MyClass.java
とする。このソースファイルをコンパイルすると
MyClass.class
というクラスファイルが出来上がる。このクラスファイルを実行するには
java MyClass
とすればよい。
問題5

解説:
クラスのフィールドは,他のクラスから好き勝手にいじられないように非公開(private)にしなくてはならない。
これはオブジェクト指向プログラミングの常識である。したがって,空欄Vにはprivateが入る。
どこからでも(別のパッケージからも)利用可能なメンバには,public指定をする。したがって,空欄Wにはpublicが入る。
空欄Xにthisが入るのは,先にコンストラクタで説明したとおり,コンストラクタの仮引数名とフィールド名を
区別するためである。空欄Qは System.out.println が入る。空欄OとPについては,mainメソッドを書けるように
しておけば問題はない。オブジェクトを生成するときはnewを使う。したがって,空欄Yの行の完全形は
Person taro = new Person( 21, 0 );
となる。
よく,オブジェクトをnewで生成してもいないのにオブジェクトを利用しようとする人が居るが,必ずオブジェクト
を利用する前に,オブジェクトをnewで生成しておくこと。「まだ無いもの」を使うことは出来ないのだから。クラス
はあくまでもオブジェクトの設計図であって,オブジェクトではない。
問題6

解説:
再利用可能な機能を持つ部品のことを「モジュール」という。クラスはJavaにおける最少のモジュール。
さらに関連する機能を持つクラスを集めて「パッケージ」というより大きいモジュールを作成できる。
クラス内部のフィールドはクラス外部から勝手にアクセス(利用)できないように,すべきなのは先の説明通り。
どうしてもクラスの外部からフィールドを利用したい場合は,そのクラスに「フィールドにアクセスするため
の専用のメソッド」=「アクセッサ」を用意する。
アクセッサには,フィールドの値を返す「ゲッタ」,フィールドの値を設定する「セッタ」がある。
モジュールの外部からアクセス(利用)できる部分(=そのモジュールの公開部分)は,そのモジュールの
「インタフェイス」になる。「インタフェイス」部分を勝手に変更するとその「インタフェイス」を利用
している者が困るので,インタフェイス部は好き勝手に変更できない。一方,モジュールの非公開部分は
「実装」部分となり,モジュール外部から利用されることはないので,比較的頻繁に変更してもかまわない。
問題7

解説:
A型オブジェクトは生成されるとまずフィールドnはintの標準値0で初期化される。その後,「= 0」
という初期化指定で更に0に初期化される。そして,最後にコンストラクタで初期化されるが,ここ
ではコンストラクタでnの値が1増加されている。したがって,a1.nの値が表示されるとき,a1.n
の値は1となっている。(ちなみに,a2.nも値が1になっている)
問題8

解説:
問題7と違うところは,フィールドnがstaticになっていること。つまり,nはAクラスに一個だけで存在し,
A型のオブジェクトの中には存在しない。つまり,A型のオブジェクトが生成されるごとにnが1だけ増加する。
これは,特定のクラスのオブジェクトがそれまでに何個生成されているかを調べたり,オブジェクト毎に
識別番号を付けるときなどに応用できる。問題8の例では,a1.nもa2.nも,クラスAにただひとつしか存在
しないstaticなフィールドnを表している。a1.nを表示するときまでに,A型オブジェクトは2個生成されて
いるので,nは1増加を2回繰り返し,結局2と表示される。
問題9

解説:(「Javaを学ぶ」第12回参照)
スーパークラスは,一般概念を表すことが多い。そして一般概念を表すクラスでは具体的な
振る舞いが定義できず,そのようなクラスのオブジェクトを生成することはプログラムを複雑
にしたり,正常に動作しない原因になったりする。具体的に説明していこう。
一般概念とは,例えば「動物(Animal)」とか「乗り物(Vehicle)」などで,具体的な姿や振る舞
いを決められない「ものごと一般」を広く表す概念である。あなたは例えば「動物」という種類
の生き物を具体的に想像できるだろうか。おそらく不可能であろう。なぜなら,そのような「動
物」という種類の生き物は存在しないからである。これに対し,「猫(Cat)」とか「犬(Dog)」,
「自動車(Car)」や「バイク(Motorbike)」という概念はより具体的で,実際の姿や振る舞い(動
作)を想像することができるし,そのようにプログラム上に書けばよい。
たとえば,交通シミュレーションプログラムを考えたとき,乗り物一般を表すVehicleという
スーパークラスを考えたとしよう。乗り物は移動するから,「移動する」という振る舞いを
表すmove()というメソッドを考える。しかし,そのVehicle型自身のオブジェクトの移動の仕方
をmove()メソッドに具体的に定義しようとしても無理がある。「乗り物」という具体的な乗り
物は存在しないのだから。(一方,Vehicleのサブクラスとして自動車を表すCarなどが考えられ
るが,Car型なら移動を表すmove()メソッドを『自動車らしく』移動するように具体的に定義
できるだろう。) このように,一般概念を表すクラスは具体的な振る舞いを定義できない。それ
ばかりか,一般概念を表すクラスのオブジェクトは生成しただけでプログラムの動作に支障をき
たすこともある。たとえば,Vehicle型のmove()メソッドを苦肉の策として
void move( double s ) {} // s秒間進むメソッド
というように「何もしない」ように定義しておいたとする。すると,このVehicle型オブジェク
トはいったん生成されたら,その後いくらmove()メソッドを実行してもその場に居座り続け,
交通シミュレーション世界では永遠に続く渋滞の原因になってしまうだろう。(この例につい
ては,「Javaを学ぶ」第12回に詳しい。)
問題を整理すると,
・スーパークラスは一般概念を表していることが多く,振る舞い(メソッドの具体的な動作)を定義できないことが多い
・そのような一般概念を表しているクラスのオブジェクトは,生成されるだけでプログラム世界では邪魔になってしまう
ということになる。
Javaでは,そのような一般概念を表すクラスは抽象(abstract)クラスというクラスとして定義
することで,そのオブジェクトの生成を禁止できようになっている。抽象クラスはクラス定義
の先頭にabstractと書けばよい。上の例では,2次元図形一般を表すFig2Dが抽象クラスである。
空欄nにはabstractが入る。
抽象クラスでは,動作部分({})を省いた特別なメソッド「抽象メソッド」を定義できる。抽象
クラスの振る舞のうち,具体的に動作を定義できないものは,抽象メソッドとして定義する。
抽象メソッドの仕方は以下の通り。頭にabstractとう語がつき,具体的な動作を定義する場所
である{}部分が存在しないことに注意。
abstract 返値型 メソッド名( 仮引数並び );
上の例では,抽象クラスFig2Dのdraw()メソッドが抽象メソッドになっている。draw()メソッ
ドは,自分自身を描画するメソッドだが,2次元図形一般をひろく表すFig2Dには,具体的な
姿が存在せず,描画することが出来ない。そのため,Fig2Dのdraw()メソッドは抽象メソッド
として定義すべきなのである。したがって,空欄oにはabstractが入る。
抽象メソッドを持つクラスは自動的に抽象クラスとなる。
上の例では,抽象クラスFig2DのサブクラスとしてTriangleクラスとRectangleクラスを定義し
ているので,空欄pには extends という語が入る。サブクラス定義のしかたは以下の通り。
class サブクラス名 extends スーパークラス名 {
}
サブクラスでは,スーパークラスから継承したメソッドを定義し直し,そのサブクラスらしい
振る舞いに変えることが出来る。このように,サブクラスでスーパークラスから継承したメソ
ッドを定義しなおすことを,メソッドのオーバライドと呼ぶ。
抽象クラスのサブクラスでは,抽象クラスを継承した上で,抽象メソッドをオーバライドして
やる。抽象メソッドをオーバライドする,ということは,具体的な動作の定義を持っていない
抽象メソッドに,具体的な動作を与えてやるということになる。オーバライドされて具体的な
動作を「持った」メソッドは,もう抽象メソッドではなくなり,普通のメソッドとなる。上の
例では,抽象クラスFig2Dの抽象メソッドdraw()を,Triangleでは"△"を表示するようにオー
バライドし,Rectangleでは"□"を表示するようにオーバライドしている。Triangleのdraw()
も,Rectangleのdraw()ももはや抽象メソッドではなく,普通のメソッドとなる。Triangle型
にも,Rectangle型にも抽象メソッドはひとつも残っていないことになるので,Triangle型も
Rectangle型も抽象クラスではなく,普通のクラスと言うことになる。
サブクラスのコンストラクタでは,冒頭で super() という形でスーパークラスのコンストラクタ
を呼び出せる。空欄qには super が入る。
is-a関係を用いたとき,スーパークラスおよびそのサブクラスのオブジェクトをすべて扱える
ようにするには,スーパークラスを使って処理を書く。上の例では,letItDraw()メソッドは,
Fig2Dおよびそのサブクラス(Triangle,Rectangle型など)のオブジェクトをまとめて処理す
るために,仮引数をFig2D型にしている。したがって,空欄rにはFig2D が入る。
問題10

解説:
概要は,これまでの解説を読めばわかるはずである。
is-a関係とは,「サブクラスはスーパークラスの一種である」というサブクラス(のオブジェクト)とスーパークラス
(のオブジェクト)の関係である。
問題9のプログラムでは,2次元図形一般を表すスーパークラスFig2Dを(抽象クラスとして)定義し,そのサブクラス
としてTriangleクラス(およびRectangleクラス)を定義している。
オブジェクト指向プログラミングで重要なのは,プログラムの多くの部分をスーパークラスを使って書くことである。
そうすることで,そのサブクラス型もまとめて処理できるようになる。
後半に関しては,問題9の解説を理解していれば答えられるはずである。