Revised: Sep./11th/2002: Since: Dec./30th/2001
オーバーライドは「上書き」のことです。継承時に、スーパークラスで定義されたメソッドと同じ名前、引数を持つメソッドを、サブクラスでもう一度定義することです。
一つのクラス内で、同じ名前のメソッドを複数定義することをオーバーロードと言いました。言葉が似ているので間違えやすいのですが、全くの別物です。
次の例は、OverrideKo
クラスが OverrideOya
クラスを継承し、メソッド retMsg()
がオーバーライドされています。
OverrideDemo.java
:
class OverrideOya { public void retMsg() { System.out.println("親のメッセージ"); } } class OverrideKo extends OverrideOya { public void retMsg() { System.out.println("子供のメッセージ"); } } class OverrideDemo { public static void main(String[] args) { OverrideKo objKo = new OverrideKo(); objKo.retMsg(); } }
C:\java>javac OverrideDemo.java C:\java>java OverrideDemo 子供のメッセージ C:\java>
アクセス修飾子は、アクセス制限を弱める方向でオーバーライドできます。即ち、protected
メソッドは public
に変更できますが、アクセス修飾子のないメソッドを private
宣言することはできません。
アクセス修飾子の規則の例外として、private 修飾されたメソッドはオーバーライドできません。private 修飾されたメンバーは、同じパッケージ内のサブクラスからも見えない/継承されないので、オーバーライドではなく、まったく別のメソッドとして実装されることになるからです。フィールドについて言えば、private なフィールドは本質的に final です。private メソッドは、サブクラスにおいて、同じシグネチャで実装しても、別のものと解釈されるので、オーバーライドにまつわる一切の制限を受けません。
従って、 private メソッドを abstract 修飾することはできません。コンパイル・エラーとなります。
static
修飾子が宣言されたメソッドは、オーバーライド時にも static
修飾子が必須です。static 修飾されたメソッドをクラス・メソッドと呼びます。
staticなメソッドをオーバーライドによって非staticメソッドにすることはできません。その逆に、非 static なメソッドを static なメソッドにオーバーライドすることもできません。static -> 非static は言語仕様で禁止されています。逆の、非static -> static の場合は、言語仕様で禁止されているわけではないのですが、スーパークラスへの型適合時に矛盾をきたすものと思われます。
尚、private メソッドと同様に、 static 修飾されたクラスメソッドを abstract 修飾するとコンパイル・エラーとなります。
スーパークラスとサブクラスでの、非static <-> static 間の再定義や private メンバーの再定義は、言語仕様上許されません。しかしながら、static <-> static や private なメンバーはサブクラスで再定義可能です。これは、オーバーライドとは区別され、隠蔽と呼ばれています。
final
修飾子が宣言されたメソッドはオーバーライドできません。final
修飾子は自身がオーバーライドされないようにするための修飾子です。
従って、abstract, private と final 修飾子は同居できません。同じメソッドに同時に指定するとコンパイル・エラーとなります。尚、先に説明したとおり、abstract と private、abstract と static を同時に指定してもコンパイル・エラーとなります。
オーバーライドメソッドでは、スーパークラスのオーバーライド対象メソッドがスローできる例外以外をスローすることはできません。
メソッドの呼び出しは、クラスの完全限定名とメソッド名と引数の組で決定します。これをメソッドのシグネチャと呼びます。メソッドに指定するものには、シグネチャのほかにも、戻り値型、修飾子、例外のスローがあります。この中で、引数の組が異なり、戻り値型とメソッド名が同じメソッドを定義することをオーバーロードといい、引数が同じメソッドをサブクラスで定義するとオーバーライドと呼ばれることを説明しました。
オーバーライドにおいて、修飾子が異なってもよい条件については、すでに説明しました。残るはチェック対処例外のスローです。
例外は、java.lang.Throwable クラスのサブクラスであり、大きく分けると三つに分かれます。
java.lang.Object | +--java.lang.Throwable | +--java.lang.Error | +--java.lang.Exception | +--java.lang.RuntimeException
例外の三つのグループのうち、チェック対象例外は、アプリケーション側で例外処理のロジックを組み込む必要があります。例外処理方法は、try {} catch () {} 構文で内部的に処理するものと、メソッドの throws リストに宣言して呼び出し元に処理を委譲するものに分けられます。
throws リストが記述されているメソッドをオーバーライドするときは、オーバーライド対象がスローしうる例外以外は指定できません。たとえば、オーバーライド対象メソッドが Exception クラスを throws リストに記述していれば、オーバーライドメソッドでは Exception のすべてのサブクラスを throws リストに記述できます。一方、 オーバーライド対象メソッドでは IOException だけが throws リストに記述されていたら、 IOException のサブクラス以外の例外は throws リストに記述できません。
例外については、後続の章で詳細に説明します。