Javaでは、あるクラスを基にして新しいクラス (サブクラスと言われる) を作り、クラスに機能を付け加えたり減らしたり変更を加えたりすることができる。これをクラスの継承という。継承はオブジェクト指向の重要な概念である。
あるクラス A を基にして、機能を付け加えたり減らしたり変更を加えたりして、新しいクラス B を作ることができる。これをクラスの 継承 (inheritance) と言う。Java では 拡張 (extension) という言い方もする。
新しく定義されたクラス B は基となったクラス A の サブクラス (subclass) と言う (派生クラス とも言う)。
また、基となったクラス A は新しく定義されたクラス B の スーパークラス (superclass) と言う (基底クラスとも言う)。
なお C++ などでは複数のクラスを継承した新しいクラスを定義すること (多重継承と言う) ができるが、Java では許されない。
クラス A を基にクラス B を作るとき、
class B extends A { ‥‥‥ }
のように、extends というキーワードを使ってスーパークラスを指定する。
※※※※※ 補足 ※※※※※
なお、スーパークラスの指定のないクラス定義では暗黙で java.lang.Object がスーパークラスとなる。例えば、
class C { ‥‥‥ }
は以下のコードと同等となる。
class C extends java.lang.Object { ‥‥‥ }
java.lang パッケージは暗黙でimportされているので、java.lang.Object は単に Object としてもよい。
※※※※※ ※※※※※
サブクラスでは、基のクラスの public または protected 指定の変数・メソッドが継承され使用可能である。
基のクラスとサブクラスが同じパッケージに属していれば、無指定(パッケージ公開)の変数・メソッドも継承され使用可能である。
サブクラスのインスタンスは、基のクラスのインスタンスとしても利用することができるが、実体であるサブクラスのインスタンスとして振る舞う。これを 多態、多相 (ポリモーフィズム polymorphism) と言い、オブジェクト指向プログラムの基本機能である。
サブクラスのインスタンスを new によって生成するとき、
スーパークラス内の各インスタンス変数が宣言順に初期化される。
スーパークラスのコンストラクタが呼ばれる。
super( );
super( パラメータリスト );
super( );
サブクラスでは、基のクラスで定義されているインスタンスメソッドを書き換えることができる。これをインスタンスメソッドのオーバーライド (上書き) と言う。
オーバーライドするインスタンスメソッドは基のものと同一の戻り値型および同一の「名前・引数の数・全引数の型」を持つ必要がある。
※ メソッドの名前・引数の数・全引数の型をメソッドの シグネチャ (signature) と言う。また一つのクラスの中に同一のシグネチャのメソッドが複数あってはいけない。
つまり、オーバーライドするメソッドは同一の戻り値型かつ同一のシグネチャでなければならない。
アクセス修飾子については以下の決まりがある。
アノテーションの利用
Java 5 以降では、メソッドのオーバーライドの際に
@Override
というアノテーション (注釈) を入れることが推奨されている。
メソッドを間違えて、オーバーライドできないメソッドに @Override を入れるとエラーになるので、プログラムの保守性が良くなる。
(例)
class A { private String s = "Class A"; protected void method1() { System.out.println( s ); } } class B extends A { private String s = "Class B"; @Override public void method1() { System.out.print( "Super " ); super.method1(); System.out.println( s ); } }
クラス A のメソッド method1 をサブクラス B でオーバーライドしている。
メソッド名は同一・パラメータは無しで戻り値型は void である必要がある。
アクセス修飾子は基が protected であるため、オーバーライドする方は protected または public でなければならない。
上のコードと共に以下のクラスの main メソッドで実行すると
public class OverrideTest { public static void main(String[] args) { A a = new B(); a.method1(); } }
Aクラスの型を持つ変数 a に実際にセットされるのはサブクラス B のインスタンスであるため、a.method1() の呼び出しによりサブクラス B のメソッドが呼び出され実行される。
サブクラス B のメソッド method1 では super.method1(); によってスーパークラスのメソッドが呼び出されている。
表示は
Super Class A Class B
オブジェクト指向プログラミングでは「何通りかの似たような処理をさせたい」ときに、基となるクラスを作り、その基クラスを継承した複数のクラスでそれぞれ実際の具体的な処理を記述することがよく行われる。
その場合、基クラスは処理の雛型を作っておくだけでよく、雛形としての処理の内容は空でよいことが多い。
そういうときは、基クラスを 抽象メソッド (abstract method) を持つ 抽象クラス (abstract class) として定義する。
抽象メソッドとは、メソッドの本体が記述されていないもので、
abstract 型 メソッド名( パラメータ );
のように定義する。上に public あるいは protected が付いてもよい。
実際の処理はサブクラス上でオーバーライドされたメソッドの中に記述される。これを抽象メソッドの 実装 と言う。
なお抽象メソッドはインスタンスメソッドでなければならない。(クラスメソッドはオーバーライドできない)
抽象クラスは class に abstract を付加することによって定義される。
abstract class クラス名 { abstract 型1 メソッド1( パラメータ1 ); 型2 メソッド2( パラメータ2 ) { ‥‥‥ 処理 ‥‥‥ } abstract 型3 メソッド3( パラメータ3 ); }
のように、抽象クラスの中には抽象メソッドを含むことができる。上の例では メソッド1 と メソッド3 が抽象メソッドであり、メソッド2 は抽象でないメソッドである。
逆に、抽象メソッドを一つでも含むクラスは抽象クラスでなければならない。
抽象クラスはインスタンス化することができない。 抽象クラスのサブクラスは「すべての抽象メソッドを実装しない限り」やはり抽象クラスとなる。 「すべての抽象メソッドを実装した」抽象クラスのサブクラスは、抽象クラスではなくなり、具象クラス と言われ、インスタンス化することができる。
Javaでは、究極の抽象クラスとも言うべき、インタフェース (interface) というものも利用される。
詳しくはリンクを参照のこと。