先の章で、Dogクラスや Catクラスを自作しました。これらのクラスから、さらに機能を増加させたり内容を充実したり変更したりする場合に、継承という枠組みを利用することができます。Javaでは「あるクラスを継承して別のクラスを作る」ことができます。なお、後述する Objectクラスの存在を考えれば、Javaでは、(Objectクラス以外のクラスでは)「常に何かのクラスを継承しなければならない」と言うこともできます。
この章では、継承の理論的なところや概要を解説していきます。具体的な例については次の節で解説します。
継承関係を表すための予約語はextendsです。この予約語の使い方については、この章で解説していきます。
継承の関係は継承される側と継承する側の 2つのクラスの関係になります。継承される側をスーパークラス、継承する側をサブクラスと言います。継承する側のほうが一般的に機能はより豊富になり充実します。言い換えれば、一般的にスーパークラスよりもサブクラスのほうが機能がより豊富であることに注意してください。名称が紛らわしいですが、一般的にサブクラスのほうが機能は豊富です。
また、スーパークラスとサブクラスの関係は相対的な関係なので、あるクラス(A)は、別のクラス(B)のスーパークラスであると同時に、さらに別のクラス(C)のサブクラスである…ということも可能です。絶対的な基準ではなく、2つのクラス間の相対的な関係である点にも留意してください。
なお、Javaでは(C++や perlのような)多重継承はできません。あるクラスのスーパークラスは 1つに限られます(ただし、次の節で解説する Objectクラスだけは例外で、スーパークラスは存在しません)。また、多重継承のような仕組みは、後の章で解説するインターフェイスを利用します。
大まかに言えば、フィールドとメソッドは原則的に継承されます(ただし、private修飾子がつくものは特別扱いとなる)。
一方で、コンストラクタは継承されません。
今は理論しか伝えていないので理解するのは難しいのですが、継承とはIS-A関係とも言えます。次の節以降でいろいろ具体的な例が登場しますが、「賢い犬とは犬である(Wise dog is a dog.)」、「犬とは動物である」、「動物とはオブジェクトである」というような IS-Aの関係が継承の関係の基本です。
なお、インスタンスとそのインスタンスが保有するインスタンスフィールドの関係を、HAS-A関係と呼ぶことがあります。例えば、「Point型インスタンスはインスタンスフィールド x, yを持っている」という関係です。
Javaでは多重継承は認められないので、あるクラスにとってスーパークラスはひとつしかありません。そのスーパークラスのさらにスーパークラスを…と順に辿っていくと、必ず辿りつく原点となるクラスがあります。それがObjectクラスになります。Objectクラスは原点なので、そのスーパークラスは存在しません。
Java SE 7(Java 1.7)の Objectクラスの説明書(API)を改めて掲示しておきます→Objectクラス。なお、このページに書かれていることは特段に理解する必要はありません。
Objectクラスのインスタンスを実際に用いて何かをする例は稀で、本ウェブサイトにおいても、ずっと後で解説する「スレッド」以外では特にありません。ただし、Javaでは、「すべてのクラスの根源は Objectクラスになる」になるということはとても重要なことなので覚えておいてください。
Dogクラスや Catクラスを自作した際に、特段 Objectクラスのことは気にも留めずに自作しました。クラスの宣言は以下のような感じでした。
public class Dog { … }
実はクラス宣言の文に予約語 extendsが存在しない場合には、「extends Object」が補完されます。言い換えれば、「extends Object」が省略されている…とも言えます。具体的には以下の感じです。
public class Dog extends Object { … }
つまり、クラスを自作する際にスーパークラスを指定しなかった場合には、自動的に Objectクラスがスーパークラスになるということになります。
本ウェブサイトでは、「extends Object」については、すべて省略して記述することとします。
改めて Pointクラスを見てみましょう。Java SE 7(Java 1.7)の Pointクラスの説明書(API)を改めて掲示しておきます→Pointクラス。
以下の記述を見つけることができるでしょうか。
java.lang.Object └ java.awt.geom.Point2D └ java.awt.Point
また、以下の記述を見つけることができるでしょうか(implementsについての詳細は後の章で解説します)。
public class Point extends Point2D implements Serializable
これらの記述から以下のことが分かります。
Pointクラスの説明書(API)内の「メソッドの概要」の下には、「クラス java.awt.geom.Point2D から継承されたメソッド」という項目と、「クラス java.lang.Object から継承されたメソッド」という項目があり、それぞれ幾つかのメソッドが記述されています。Pointクラスには Pointクラスで宣言したメソッドやフィールドの他に、Point2Dクラスと Objectクラスで宣言されたメソッドやフィールドを利用できるということになります。
具体的に言えば、Pointクラスでは 10個のメソッドが宣言されています。それに加えて、Point2Dクラスで宣言された 9個のメソッドを継承し、Objectクラスで宣言された 7個のメソッドを継承しているので、Pointクラスには合計で 26個のメソッドが存在するということになります。
なお、メソッドの重複(オーバーライド)がありますので、個々のクラスのメソッド宣言の合計は 26になるとは限りません。例えば、equalsメソッドは、Objectクラスで宣言したものを、Point2Dクラスでオーバーライドし、さらに Pointクラスでもオーバーライドしていることが分かります。
先の章の K302プロジェクトと K304プロジェクトで、Dogクラスの equalsメソッドと toStringメソッドをそれぞれオーバーライドする例を挙げました。
Objectクラスの説明書(API)を参照すれば、equalsメソッドも、toStringメソッドも Objectクラスで宣言されているメソッドであることが分かります。それらを Dogクラスを自作した際にオーバーライドしていたのでした。Objectクラスで宣言されているメソッドの内容ではいまいち Dogクラスの現状に対応し切れていないので、それらをオーバーライドして内容を書き換えていたのでした。
既に保有しているメソッドをオーバーライドしたため、「@Override」というアノテーションを記述しても問題なかったのでした。