Javaの継承の例を示します。
Javaにおける継承は、オブジェクト指向プログラミングの中核概念の一つです。Javaの継承は、オブジェクト間に「is-a」の関係がある場合に使用されます。Javaにおける継承は、extendsキーワードを使用して実装されます。
Javaにおける継承
Javaにおける継承とは、他のクラスからの継承によってクラス間の階層を作成する方法です。
Javaの継承は推移的です -したがって、もしSedanがCarを拡張し、CarがVehicleを拡張するなら、SedanはVehicleクラスからも継承されています。VehicleはCarとSedanのスーパークラスとなります。
継承はJavaアプリケーションで広く使用されており、例えばExceptionクラスを拡張してエラーコードなどの追加情報を含むアプリケーション固有のExceptionクラスを作成する際に利用されます。例えば、NullPointerExceptionです。
Javaの継承の例
Javaのすべてのクラスは、暗黙的にjava.lang.Objectクラスを拡張しています。したがって、Objectクラスはjavaにおける継承階層の最上位に位置しています。
簡単な例を使って、Javaで継承を実装する方法を見てみましょう。
上位クラス:動物 (Jōi kurasu: Dōbutsu)
package com.scdev.inheritance;
public class Animal {
private boolean vegetarian;
private String eats;
private int noOfLegs;
public Animal(){}
public Animal(boolean veg, String food, int legs){
this.vegetarian = veg;
this.eats = food;
this.noOfLegs = legs;
}
public boolean isVegetarian() {
return vegetarian;
}
public void setVegetarian(boolean vegetarian) {
this.vegetarian = vegetarian;
}
public String getEats() {
return eats;
}
public void setEats(String eats) {
this.eats = eats;
}
public int getNoOfLegs() {
return noOfLegs;
}
public void setNoOfLegs(int noOfLegs) {
this.noOfLegs = noOfLegs;
}
}
ここで、動物はベースクラスです。動物クラスから継承する猫クラスを作成しましょう。
サブクラス:猫
package com.scdev.inheritance;
public class Cat extends Animal{
private String color;
public Cat(boolean veg, String food, int legs) {
super(veg, food, legs);
this.color="White";
}
public Cat(boolean veg, String food, int legs, String color){
super(veg, food, legs);
this.color=color;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
}
Javaでは、継承を実装するためにextendsキーワードを使用していることに注意してください。
Javaの継承テストプログラム
簡単なテストクラスを作成し、Catオブジェクトを作成して、いくつかのメソッドを使用してみましょう。
package com.scdev.inheritance;
public class AnimalInheritanceTest {
public static void main(String[] args) {
Cat cat = new Cat(false, "milk", 4, "black");
System.out.println("Cat is Vegetarian?" + cat.isVegetarian());
System.out.println("Cat eats " + cat.getEats());
System.out.println("Cat has " + cat.getNoOfLegs() + " legs.");
System.out.println("Cat color is " + cat.getColor());
}
}
出力:
「Cat(ネコ)クラスにはgetEats()メソッドはないが、それでもプログラムは動作します。なぜなら、このメソッドはAnimal(動物)クラスから継承されているからです。」
重要なポイント
-
- コードの再利用は、サブクラスがスーパークラスの変数とメソッドを継承するため、継承の最も重要な利点です。
スーパークラスのプライベートメンバーはサブクラスから直接アクセスすることはできません。この例では、Animalの変数noOfLegsはCatクラスからはアクセスできませんが、getterおよびsetterメソッドを介して間接的にアクセスすることができます。
デフォルトでアクセス可能なスーパークラスメンバーは、同じパッケージ内にある場合にのみサブクラスからアクセス可能です。
スーパークラスのコンストラクタはサブクラスで継承されません。
スーパークラスにデフォルトコンストラクタがない場合、サブクラスも明示的なコンストラクタを定義する必要があります。そうでない場合、コンパイル時に例外がスローされます。サブクラスのコンストラクタでは、スーパークラスのコンストラクタを呼び出すことがこの場合は必須であり、サブクラスのコンストラクタの最初のステートメントである必要があります。
Javaは多重継承をサポートしていませんので、サブクラスは1つのクラスのみを拡張できます。Animalクラスはオブジェクトクラスを暗黙的に拡張しており、CatクラスもAnimalクラスを拡張していますが、Javaの継承の推移性のため、CatクラスはまたObjectクラスを拡張しています。
サブクラスのインスタンスを作成してから、それをスーパークラスの変数に代入することができます。これをアップキャストと呼びます。以下はアップキャストの簡単な例です:
Cat c = new Cat(); //サブクラスのインスタンス
Animal a = c; //アップキャスト、CatはAnimalでも問題ありません
スーパークラスのインスタンスがサブクラスの変数に代入される場合、ダウンキャストと呼ばれます。これをサブクラスに明示的にキャストする必要があります。例えば;
Cat c = new Cat();
Animal a = c;
Cat c1 = (Cat) a; //明示的なキャスト、実際には”c”はCatのタイプですので、問題ありません
注意:コンパイラは間違っている場合でも文句を言いませんが、明示的なキャストのためです。以下に、実行時にClassCastExceptionがスローされるいくつかのケースを示します。
Dog d = new Dog();
Animal a = d;
Cat c1 = (Cat) a; //実行時にClassCastExceptionがスローされます
Animal a1 = new Animal();
Cat c2 = (Cat) a1; //実行時にa1は実際にはAnimalのタイプなので、ClassCastExceptionがスローされます
スーパークラスのメソッドをサブクラスでオーバーライドすることができます。ただし、常にオーバーライドされたメソッドには@ Override注釈を付けるべきです。コンパイラはメソッドをオーバーライドしていることを知ることができ、スーパークラスのメソッドに何か変更があった場合、ランタイムで望ましくない結果を得る代わりに、コンパイル時エラーが発生します。
superキーワードを使用すると、スーパークラスのメソッドを呼び出したり、スーパークラスの変数にアクセスしたりすることができます。これは、サブクラスに同じ名前の変数/メソッドがあるが、スーパークラスの変数/メソッドにアクセスしたい場合に便利です。これはスーパークラスとサブクラスの両方でコンストラクタが定義されている場合や、スーパークラスのコンストラクタを明示的に呼び出す必要がある場合にも使用されます。
isinstanceof命令を使用してオブジェクト間の継承関係をチェックすることができます。以下の例で確認しましょう。
```
Cat c = new Cat();
Dog d = new Dog();
Animal an = c;
boolean flag = c instanceof Cat; //normal case, returns true
flag = c instanceof Animal; // returns true since c is-an Animal too
flag = an instanceof Cat; //returns true because a is of type Cat at runtime
flag = an instanceof Dog; //returns false for obvious reasons.
```
-
- Javaでは、Finalクラスを拡張することはできません。
- もしコードでスーパークラスを使わない場合、つまりスーパークラスは再利用可能なコードを保持するためのベースだけである場合、クライアントクラスによる不必要なインスタンス化を避けるために、それらを抽象クラスとして保持することができます。それによってベースクラスのインスタンスの生成も制限されます。
Javaの継承に関するビデオチュートリアル
最近、私はYouTubeで継承について詳しく説明した2つのビデオを公開しました。サンプルプログラムも含まれていますので、こちらでご覧いただけます。
弊社のGitHubリポジトリから、さらに多くの継承の例をご覧いただけます。
参照:オラクルのドキュメンテーション