継承

継承とは

Javaをはじめとするオブジェクト指向言語に備わっている重要な特性の1つに継承(インヘリタンス)が あります。これは、あるクラスのメンバを、他のクラスに引継ぐ(継承させる)という効果があります。

では、実際に継承とはどういうものか、さらに詳しく説明しましょう。すでに述べたように、クラスは、インスタンス、およびオブジェクトの「設計図」です。自動車の例を出すのならば、自動車の設計図がクラス、実際に工場で生産された自動車本体が、インスタンス、およびオブジェクトということになります。

親クラスと子クラス

さて、自動車といえば、普通は乗用車を想像してしまうかもしれませんが、実際、自動車と呼ばれるものは実に多くの種類が存在します。たとえば、警察車両であるパトロールカー、荷物を運ぶトラック、さらには救急救命活度を行う救急車…など、実に多種多様な種類が存在します。それらは、「自動車」でありながら、それぞれ機能に応じた独自の機能の拡張がなされています。

このように、基本となるクラスの性質を受け継ぎ、独自の拡張をすることを、オブジェクト指向では、継承(けいしょう)と呼びます。継承のもととなるクラスのことを、親クラス,スーパークラスなどと呼びます。それにたいし、親クラスの機能を継承し、独自の機能を実装したクラスのことを、子クラス、もしくは、サブクラスと呼びます。前述の自動車の例で言うのならば、車クラスが親クラス、トラックや救急車などが、サブクラスということになります。(図2-1.参照)

図2-1:継承のイメージ
継承のイメージ

Javaでの継承の実相

サンプルプログラム

は実際に、継承のサンプルを入力して、試してみましょう。以下のプログラムを入力・実行してみてください。

SampleEx201.java
package exday2;

public class SampleEx201 {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
	    Car c = new Car();
	    c.supply(10);   //  燃料補給
	    c.move();   //  移動
	    c.move();   //  移動
	    Ambulance a = new Ambulance();
	    a.supply(10);
	    a.move();
	    a.sevePeople();
	}

}
Car.java
package exday2;

public class Car {
    private int fuel = 0;         //  燃料
    private int migration = 0;    //  移動距離
    //  コンストラクタ
    public Car()
    {
    	System.out.println("Carオブジェクト生成");
    }
    //  移動メソッド
    public void move()
    {
        //  燃料があるなら移動
        if(fuel >= 0){
            migration++;  //  距離移動
            fuel--;       //  燃料消費
        }
        System.out.println("移動距離 : "+migration);
        System.out.println("燃料 : "+fuel);
    }
    //  燃料補給メソッド
    public void supply(int fuel)
    {
    	 if(fuel > 0){
    	        this.fuel += fuel; //  燃料補給
    	 }
    	 System.out.println("燃料 : "+fuel);
    }

}
Ambulance.java
package exday2;

public class Ambulance extends Car{
	//	番号
	private int number = 119;
	//	コンストラクタ
	public Ambulance()
	{
		System.out.println("Ambulanceオブジェクト生成");
	}
	//  救急救命活動
	public void sevePeople()
	{
		System.out.println("救急救命活動");
		System.out.println( "呼び出しは"+number+"番");
	}
}
実行結果
Carオブジェクト生成
燃料 : 10
移動距離 : 1
燃料 : 9
移動距離 : 2
燃料 : 8
Carオブジェクト生成
Ambulanceオブジェクト生成
燃料 : 10
移動距離 : 1
燃料 : 9
救急救命活動
呼び出しは119番

プログラムを見てわかるとおり、Ambulanceクラスは、Carクラスのメソッドを使うことができます。つまり、継承とは、サブクラスがスーパークラスの機能を受け継ぐということなのです。その上、このクラスの独自のメソッドである、savePeopleも使えます。

つまり、サブクラスはスーパークラスの機能を受け継ぎ、さらに機能を拡張したもんだということが分かります。(図2-2.参照)

図2-2:CarクラスとAmbulanceクラスの関係性
CarクラスとAmbulanceクラスの関係性

継承の実装

あるクラスが、別のクラスを親クラスとするときの定義は、

親クラスを継承した、子クラスの定義の方法
class 子クラス名 extends public 親クラス名

のように定義します。

つまり、Ambulanceクラスは、Carクラスを継承したクラスです。そのため、Carクラスが親クラス(スーパークラス・ベースクラス)Ambulanceクラスが、子クラス(サブクラス)という組み合わせになります。なお、ambulanceとは、英語で救急車を表す言葉であり、このクラスは、「救急車クラス」ということになります。

このことから、publicメンバである、move()メソッド、および、supply()メソッドを利用することができます。ただ、Carクラスのprivateなフィールドである、fuelおよび、migrationには、直接アクセスすることはできません。

また、Ambulanceクラスは、さらに独自のメンバである、フィールドのnumber、および、savePeopleメソッドは、Ambulanceクラスで利用することができますが、Carクラスでは利用することはできません。

サブクラスのコンストラクタ

次に、子クラスと親クラスのコンストラクタの関係性について注目してみましょう。プログラムをみてもわかるとおり、この子クラスにも、親クラスと同様に、コンストラクタ(Ambulance)定義されています。

実行結果からもわかるとおり、実はサブクラスが生成される際、子クラスのコンストラクタが実行される前に、親クラスのコンストラクタが実行されることがわかります。このように、継承が利用された場合、親クラスのコンストラクタ・デストラクタも利用されることがわかります。

単一継承と多重継承

Javaは単一継承

ここまで、Javaの継承について説明してきました。基本的に、一つのクラスのサブクラスはいくらでもできますが、サブクラス一つに対し、スーパークラスは一つしか存在しません。このように、親クラスが一つしかないような継承の仕方を、単一継承(たんいつけいしょう)と言います。

ただ、言語によってはひとつのクラスに複数の親クラスを設定することができます。これを、多重継承(たじゅうけいしょう)と言います。

図2-3:単一継承と多重継承
単一継承と多重継承

Objectクラス

サンプルプログラム

ただ、Javaのすべてのクラスは、Objectオブジェクトを暗黙の内に継承しています。以下のプログラムを実行してみてください。

SampleEx202.java
package exday2;

public class SampleEx202 {

	public static void main(String[] args) {
		// TODO 自動生成されたメソッド・スタブ
		Car c = new Car();
		System.out.println(c.toString());
		System.out.println(c.getClass());
		Object o = (Object)c;
		System.out.println(o.toString());
		System.out.println(o.getClass());
	}

}
実行結果
Carオブジェクト生成
exday2.Car@1690726
class exday2.Car
exday2.Car@1690726
class exday2.Car

Carクラスには、定義していない、toStringメソッドや、getClass()といったメソッドが存在ます。これは、暗黙の親クラスである、Objectクラスのメソッドです。(8~9行目)

このクラスを、9行目でObjectクラスに変換しています。このような処理のことを、キャストと言います。キャストは、あるクラスのインスタンスの前に、()で親クラスのクラス名を記述することにより、そのクラスのようにふるまわせることで、この場合、cをObjectクラスのインスタンスに変換して、oに代入しています。

クラスのキャスト
Object o = (Object)c;

このoで同様のメソッドを呼び出しても(11行目~12行目)、同じ結果が得られることがわかります。つまり、cは、親クラスである、Objectクラスのメソッドを呼び出していることがわかります。

Objectクラスの主要なメソッド

なお、Obectクラスの主なメソッドには、以下のようなものがあります。処理によっては、ベースクラスであるObjectと、サブクラスでは結果が違うものも存在します。(表2-1)

表2-1.Objectクラスの主要なメソッド
メソッド 働き
toString オブジェクトの文字表現を返します。デフォルトでは「java.lang.Object@1690726」のようにオブジェクトのクラスとそのオブジェクト番号(ハンドル)が返ります。

get 指定した番号の要素を取り出します。

equals 同じ値を保持しているかどうか判定すします。オブジェクトの同一比較は、== 演算子でできます。


練習問題 : 問題2.