この章では、オブジェクト指向の重要な概念の一つである継承
について説明をします
継承
あるクラスをベースとしてメンバ変数・関数を追加し、新しいクラスを定義することを継承
と呼びます
あるクラスを継承したクラスを宣言するときextends
キーワードを使用し、以下のように記述します
class B extends A {
追加する新しいフィールドとメソッド;
}
class A
がベースとなるクラスの宣言だとすると、新しく作成するclass Bの宣言の後に、extends A
と記述することでクラスBはクラスAを継承します
そのとき、クラスAはクラスBのスーパークラス(親クラス)
であり、クラスBはクラスAのサブクラス(子クラス)
です
また、クラスBはクラスAから派生
したクラスともいいます

フィールドとメソッドの継承
スーパークラスには共通の機能を集約し、サブクラスはサブクラス独自の機能や特性を追加していくことになります
継承したクラスのフィールドとメソッドには次の性質があります
- サブクラスではスーパークラスのフィールドとメソッドを引き継ぐ
- サブクラスではスーパークラスと同じ名前の変数やメソッドを宣言することができる
※このことをオーバーライド
という - コンストラクタは継承されない
- サブクラスのインスタンスを生成するときには、スーパークラスの引数のないコンストラクタも自動的に呼び出される
また、サブクラス is-a スーパークラス
という「is-aの関係」に則って継承を行います
これは、サブクラスはスーパークラスの一種、またはサブクラスはスーパークラスの部分集合という意味です
言い換えれば、is-aの原則が成立しない場合は、継承してはいけません
では、Shapeクラスを作成し、Shapeクラスを継承するRectangleクラスを作成するサンプルプログラムを以下に示します

この図は、作成するクラスの概要を表しています
スーパークラスのShapeクラスは、線の色と幅の機能を持つ図形を表すクラスです
Rectangleクラスは、Shapeクラスの機能を受け継ぎつつ、幅と高さという新しい機能を追加した四角形を表しています
Shapeクラスを以下のように記述します
class Shape {
int color;
int dot;
Shape(){}
Shape(int color,int dot){
this.color=color;
this.dot=dot;
}
double calcArea(){
return 0;
}
}
続いて、Rectangleクラスを以下のように記述します
class Rectangle extends Shape{
double width;
double height;
Rectangle(){}
Rectangle(int color,int dot,double width,double height){
super(color,dot);
this.width=width;
this.height=height;
}
double calcArea(){
return width * height;
}
double calcAround(){
return (width + height)*2;
}
}
double width;
double height;
Rectangleクラスで追加したフィールドです
double calcArea(){
return width * height;
}
Shapeクラスにも含まれるcalcArea()を定義しています
Rectangleクラスでは、ShapeクラスのcalcArea()をオーバーライド
しています
Rectangle(int color,int dot,double width,double height){
super(color,dot);
this.width=width;
this.height=height;
}
Rectangleクラス独自のコンストラクタを定義していますsuper(color, dot);
はスーパークラスの引数があるコンストラクタを呼び出しています
double calcAround(){
return (width+height)*2;
}
Rectangleクラスで追加した関数です
main関数内から、ShapeクラスとRectangleクラスを呼び出したソースです
public class Sample{
public static void main(String []args){
Shape sh = new Shape(0x000001,1);
double area = sh.calcArea();
System.out.println("shape area="+area);
Rectangle rect = new Rectangle(0xffffff,1,10,20);
area = rect.calcArea();
System.out.println("rectangle area="+area);
double round = rect.calcAround();
System.out.println("rectangle round="+round);
}
}
実行結果
shape area=0.0
rectangle area=200.0
rectangle round=60.0
double area = sh.calcArea();
ShapeクラスのcalcArea()を呼び出しています
area = rect.calcArea();
RectangleクラスのcalcArea()を呼び出しています
double round = rect.calcAround();
RectangleクラスのcalcAround()を呼び出しています
しかし、以下のように記述するとエラーが発生します
sh.calcAround()
実行結果
Sample.java:38: error: cannot find symbol
double round = sh.calcAround();
^
symbol: method calcAround()
location: variable sh of type Shape
Shapeクラスには、calcAround()は存在しないからです
継承のメリットは以下の点が挙げられます
- コードの再利用性
既存のクラスの機能を継承することで、新たにコードを書く手間を省き、開発効率を向上させることができます - 保守性の向上
既存のスーパークラスを変更した場合、その変更は継承したクラスにも自動的に反映されます
そのため、コードの修正が容易になり、保守性を向上させることができます - 柔軟性の向上
継承を用いることで、プログラムの構造を柔軟に変更することができます
例えば、新しい機能を追加したい場合でも、既存のクラスを継承して新しいクラスを作成することで、既存のコードに影響を与えることなく機能を追加することができます
【演習問題】
- 次の要件を満たすプログラムを作成してみましょう
Personクラス(スーパークラス)
フィールド
名前(⽂字列)
性別(⽂字) ’m’→男性、’f’→⼥性を表す
⽣年⽉⽇(⽂字列) YYYY/MM/DD形式)
メソッド
Introduction()を⽤意 名前、性別、⽣年⽉⽇、年齢を表⽰
Patientクラス(Personクラスから派⽣する)
フィールド
⾝⻑(cm)
体重(kg)
メソッド
Introductionを⽤意 名前、性別、⽣年⽉⽇、年齢、⾝⻑、体重を表⽰
適正体重を表⽰する関数
※適正体重=⾝⻑(m)×⾝⻑(m)×22 適正体重より⼤きいか⼩さいかを表⽰する関数
mainの処理
Patientクラスを実装し、表⽰関数、適正体重を表⽰する関数、適正体重より⼤きいか⼩さいかを表⽰する関数をそれぞれ呼び出す
コメント