前の記事の続きです。継承関係によって継承元の機能を継承先でも引き継いで使えるところまで見てきました。このほかにも継承関係のメリットはあります。継承先で実装してほしいことを継承元で決めておくことができます。継承元ではどんなメソッドが作られるべきかだけ決めておいて実際のメソッドは継承先で実装されるようにします。
抽象メソッド
この継承元で宣言する「実装されるべき」メソッドのことを抽象メソッドと呼びます。実態がない概念だけのメソッドという意味になります。
以下は動物クラスに抽象メソッドgetNameとgetSpeedを宣言した例です。
public abstract class Animal { public String getKind(){ return "動物"; } abstract String getName(); abstract int getSpeed(); }
抽象メソッドは以下のような特徴があります。
- メソッドの戻り値の前にabstractというキーワードがあること
- 通常のメソッドは処理が{ }に囲まれて描かれるところがそれがないこと
- セミコロン;でメソッドが終わっていること
また抽象メソッドを持つクラスは必然的に抽象クラスとなります。抽象クラスはインスタンスを作る事ができません。メソッドの形は決められていても処理の決まっていないので使おうにも使えないのです。インスタンスを作るにはこれらの抽象メソッドを実装した継承先クラスを使う事になります。
抽象メソッドを実装したサブクラスは以下のようになります。
public class Lion extends Animal { @Override public String getName(){ return "ライオン"; } @Override public int getSpeed(){ return 70; } }
public class Camel extends Animal { @Override public String getName(){ return "ラクダ"; } @Override public int getSpeed(){ return 40; } }
抽象メソッドを使っていない前回のコードと同じですが扱いに大きな違いがあります。
- 前回のコードではライオンクラスのgetNameメソッドgetSpeedメソッドともにライオンクラス独自のメソッドとして宣言されていた
- 前回のコードではラクダクラスのgetNameメソッドgetSpeedメソッドともにラクダクラス独自のメソッドとして宣言されていた
- 今回のコードではこの二つのメソッドは動物クラスで実装を要求しているため宣言された
メソッドの宣言の上に@Overrideという記述があります。これはアノテーション annotationと呼ばれるもので注釈という意味になります。ここでの注釈は「継承元クラスで宣言されていたものを優先させる」という意味で。英語の動詞overrideには「優先させる」「覆す」という意味があります。またこのような注釈をつけていながら継承元クラスにメソッドがない場合はコンパイルエラーが発生します。このためアノテーションをつけるのはオーバーライドを着実に実行するための担保になります。
抽象メソッドによる参照
ではライオンクラスのインスタンスとラクダクラスのインスタンスの両方を継承元の動物クラスのインスタンスとして扱うコードを書きます、この二つのインスタンスはともに動物クラスなので配列にすることができます。
public class AnimalTest { public static void main(String[] args){ Animal[] animals = new Animal[]{new Lion(), new Camel()}; for(int i = 0;i < animals.length;i++){ System.out.println("私は" + animals[i].getName() + "、" + animals[i].getKind() + "です。"); System.out.println("時速" + animals[i].getSpeed() + "kmで走ります。"); } } }
動物クラスは抽象クラスでしたがライオンクラスのコンストラクタやラクダクラスのコンストラクタで作成されたインスタンスを参照値として持つ事ができます。
また動物クラスでは抽象メソッドとして処理の宣言されていなかったgetNameメソッドやgetSpeedメソッドのサブクラスの実装を利用して処理を行う事ができます。このため同じメソッドを読んだとしてもその処理内容はサブクラスによって別なものになります。
以下が実行結果になります。動物クラスを参照していても実際の処理はライオンクラスやラクダクラスのものが利用されている事がわかるはずです。
$ javac AnimalTest.java $ java AnimalTest 私はライオン、動物です。 時速70kmで走ります。 私はラクダ、動物です。 時速40kmで走ります。