スーパークラスについて
たとえば、下の図のような関係を考えます。

三角形、四角形はともに「図形」であり、図形の基本的な性質「辺がある」「頂点がある」を
受け継いでます。実世界ではこのような「親子関係」をもつものがたくさんあります。
たとえば人間やサルなどはいずれも「動物」であり、動物の性質を受け継ぎます。
これをプログラムで適用することで、わかりやすく再設計しやすいプログラムを作ることが
出来ます。三角形や四角形(子)が図形(親)の性質を受け継ぐことをオブジェクト指向の
世界では「継承」と呼んでいます。
継承について
では前回の復習をかねて、次の2つのクラスを作成してみましょう。
なお、各栄養成分の値は「コンストラクタ」で指定するものとする。
問1 「りんご」を表現したクラスApple
炭水化物(tansui) 0.146
たんぱく質(tanpaku) 0.002
脂肪(sibou) 0.001
炭水化物を返すメソッドgetTansui
たんぱく質を返すメソッドgetTanpaku
脂肪を返すメソッドgetSibou
問2 「オレンジ」を表現したクラスOrange
炭水化物(tansui) 0.098
たんぱく質(tanpaku) 0.01
脂肪(sibou) 0.001
炭水化物を返すメソッドgetTansui
たんぱく質を返すメソッドgetTanpaku
脂肪を返すメソッドgetSibou
解答
どうでしたか?なんか面倒くさいなぁとおもいませんでしたか?
そうです。AppleクラスとOrangeクラスの内容がほとんど一緒なのです。
異なるのは炭水化物等の値だけなのです。今回は果物2つの設計だけに
しましたが、これが10個、20個となると、同じ記述を書くのは面倒ですよね?
それを目をつぶったとして次の変更点を加えてみましょう。
種類が果物であることを示すフラグ(kind)がある。果物の場合は2を代入する。
種類を返すメソッドgetKindがある。
どうでしょうか?たぶん皆さんは先ほど作成した2つのクラスにそれぞれ
フラグとメソッドを代入したと思います。実はこれは作業効率を悪化させる
原因となります。今回の場合、AppleクラスとOrangeクラスを作成していた人は
同一でした。しかし実際の現場では別々の人が作る事だってあるわけです。
そのときに、一方が聞き忘れなどでフラグとメソッドを変更し忘れたりしたら
どうでしょう?そのバグ取りのために無駄な時間を費やすことになります。
また今回のように2つの変更点&変更対象のクラスが2種類の場合ならよいのですが、
これが10個のクラス・・あるいは10個の変更点・・・と考えると、ミスする確率は
高くなります。これをどうにかすることは出来ないでしょうか?
これを解決したのが「継承」という考え方です。
まず、今まで作成したクラスのほかにまた別のクラスFruitを作成します。
このFruitクラスにはAppleクラスとOrangeクラスの共通部分を記述します。
この場合は全てのフィールド・メソッドが共通部分です。
そして、AppleクラスとOrangeクラスのpublic class ***の後にextends Fruitと
追加します。これは「Fruitクラスのフィールドとメソッド」を全て受け継いだ
ということを示しています。ここでAppleクラスのような「受け継いでいるクラス」を
「サブクラス」と呼び、Fruitクラスのような「親」クラスをスーパークラスと呼びます。
なおコンストラクタは受け継ぎません。ここで難しいのはコンストラクタの内容だと思います。
ここではサブクラスごとに栄養成分として設定する値が異なるので、各栄養成分の値を引数として
スーパークラス(ここではFruit)のコンストラクタに引渡します。そしてスーパークラスの
コンストラクタで各栄養成分の値を設定するようにしましょう。
解答
解答どおり、スーパークラスのコンストラクタは(double,double,double)となります。
これは左から炭水化物、たんぱく質、脂肪の順に値を受け取るからです。
そしてthis.・・・の部分でそれぞれ栄養成分の値をセットします
一方、サブクラスではスーパークラスのコンストラクタを呼び出すため、
super(double,double,double)とします。括弧内はdouble型の数値3つを指定します。
これも左から炭水化物、たんぱく質、脂肪の順に値を指定します。
実はサブクラス(ここではAppleクラス)のコンストラクタで何も定義をしないと、
自動的にsuper()というスーパークラスの引数なしのコンストラクタが実行されます。
このときに、スーパークラスで引数なしのコンストラクタを記述していないと、
コンパイルの際、エラーではねられますのでご注意ください。
ここはかなり難しい話だと思います。これは実際やってみないと身につかないので
練習問題をたくさん用意しましたのでやって慣れてください。
finalクラスと拡張の禁止
finalというのは日本語で「最後の」という意味があります。実はサブクラスは
スーパークラスのメソッド、フィールドを受け継ぐだけでなく、サブクラス側で
上書きできる機能を持っています。これをオーバーライドと呼んだり、
拡張定義と呼んだりします。しかし、継承するフィールドの中でも上書きされると困る
フィールドも存在します。そのようなものにはfinalという修飾子をつけることで
拡張できないようにすることが出来ます。これも人間側がミスしないように考え出された
手法です。
抽象メソッド
抽象メソッドというものも存在します。この考え方は後述するインタフェースと似ています。
抽象メソッドにするには修飾子abstractをつけます。抽象メソッドを継承した場合、
必ずサブクラス側で拡張定義をしなければなりません。それは「抽象メソッドは設計のみし、
具体的な処理はサブクラス側に記述する」という精神のもと、考え出された方法だからです。
なぜ抽象メソッドのような考え方が必要かは次の章で説明します。
練習問題
問1
「クラスBはクラスAのサブクラスである」と明示するプログラムコードを書け。
ヒント:extends
問2
1)次の2つのクラスを設計せよ
クラスTriangle
頂点の数(t_su)が3つ。
辺の数(h_su)が3つ。
底辺(teihen)がある。コンストラクタで引数として与えられた値をセットする。
高さ(takasa)がある。コンストラクタで引数として与えられた値をセットする。
面積を返すメソッドgetArea()がある。(面積=底辺*高さ/2)
頂点の数を返すメソッドgetT_su()がある。
辺の数を返すメソッドgetH_su()がある。
クラスRectangle
頂点の数(t_su)が4つ。
辺の数(h_su)が4つ。
縦の長さ(tate_length)がある。コンストラクタで引数として与えられた値をセットする。
横の長さ(yoko_length)がある。コンストラクタで引数として与えられた値をセットする。
面積を返すメソッドgetArea()がある。(面積=縦*横)
頂点の数を返すメソッドgetT_su()がある。
辺の数を返すメソッドgetH_su()がある。
2)1)で作成した2つのクラスの共通部分を抜き出したスーパークラスFigureを
作成せよ。なお、1)で作成したクラスはFigureのサブクラスとして取り扱うこと。
頂点の数と辺の数はスーパークラスのコンストラクタで指定するものとする。
解答 問1:public class B extends A
解答 問2:1)変更前Triangle.java 変更前Rectangle.java
解答 問2:2)変更後Triangle.java 変更後Rectangle.java Figure.java