next up previous
: 継承の問題点(2) : オブジェクト指向言語 Java : オーバーライド

継承の問題点(1)

以上で紹介した「継承」,「多重定義」,「オーバーライド」,「サブシュー ム」の各性質を多用することにより,より複雑なクラス間の関係を定義するこ とができる. しかし,どのように実行されるかわからない場合など,難しい問題もある. この節と,次節では,それを紹介しよう.

そもそも,「クラス=型」 にした理由は, プログラムのエラーを 「静的に」(コンパイル時) に見つけるための型 を,クラスと同等に扱うことにより,クラス間の関係の意味も含んだ型として,静的にエラーを発見しようとするためであった.しかし,「多重定義」,「オーバーライド」,「サブシュー ム」の性質などに より,静的にエラーのチェックをすることが不可能であることがわかってきた. その例を紹介しよう.

まず,サブシュームの性質は,上で紹介した代入演算の他に,オブジェクトを メソッドの引数で受渡した場合にも生ずる.

public class C {
  public void C1() {
    System.out.println("calling C1 of C.");
  }
  public void C2() {
    System.out.println("calling C2 of C.");
  }
  public static void main(String args[]) {
    E e = new E();
    e.E1(new D());
  }
}
class D extends C {
  public void C1() {
    System.out.println("calling C1 of D.");
  }
  public void D1() {
    System.out.println("calling D1 of D.");
  }
}
class E {
  public void E1(C c) {
    c.C1();
  }
}
このプログラムを実行すると以下のようになる.
calling C1 of D.
main メソッドの中で,
クラス E のインスタンスのメソッド E1 にクラス D のインスタンスを受渡している.
e.E1(new D());
しかし,受け口であるクラス E の定義では,以下のようになっている.
public void E1(C c) {
  c.C1();
}
クラス C のインスタンスを受付けるようになっている.これは,クラス D がクラス C のサブクラスであるため サブシュームによりクラス D のインスタンスを受け付けることができ るためである.

つまり,オブジェクトをメソッドの引数として受渡す場合は,対応するク ラスのサブクラスのどれかが受渡される可能性がある.例えば,上の例では,実際にはクラス D のインスタンスを受渡しているので,

public void E1(C c) {
  c.D1();
}
とすることも可能であると考えるが,
このように書いたのであれば,「静的なチェック」により, クラス C のメソッドには D1 がないことがわかり, エラーとなってしまう.そのため Java では,
public void E1(C c) {
  D d=(D)c;
  d.D1();
}
のように キャスト(cast) を使うことにより,
実際のメソッドを呼出すことができる.

これで,めでたく実際のメソッドを呼出すことが可能となったわけであるが, キャストは,非常に危うい性質を持っている.例えば,別のオブジェクトが,

e.E1(new C());
と呼出したらどうなるであろう.
これは,クラス C のインスタンスに は,メソッド D1 が存在しないのでエラーとなってしまう.

最後に,このような場合の最もエレガントなプログラミングを紹介しよう.

public void E1(C c) {
  if(c instanceof D) {D d=(D)c; d.D1();}
  else if(c instanceof C) c.C1();
}
このように, instanceof 演算子を
使うことにより,どのようなサブクラスかを「動的に」判断して適切な処理を 行うことが必要である.

一般に,「クラス=型」 であるオブジェクト指向言語でも, メソッドの引数として,オブジェクトを受渡す場合には,ちょうどそのクラス (型) のオブジェクトだけでなく,サブクラスのどれかが受渡される可能性がある.そのためには,本来型という「静的にチェックできるはず」の機能も, その範疇ではチェックしきれないことが知られている. そのために,Java では「動的に」サブクラス関係をチェックする instanceof という演算子が提供されている.また,他の同様のオブジェクト 指向言語でも同様の演算子が提供されている7プログラマは,どこで動的にチェックする必要があるかを常に,意識しなけれ ばならない.


平成12年8月9日