2016-05-04 14 views
4

私はそのように定義されたいくつかの継承クラスを持っています。Javaの多態性とメソッド連鎖

class Base { 
    public Base chainedMethodA() { 
     // some stuff 
     return this; 
    } 
} 

class Derived extends Base { 
    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

さて、次のコードは動作します:

Derived obj = new Derived(); 
obj.chainedMethodB().chainedMethodA(); 

しかし、これは(関数呼び出しの切り替え順に気づか)しません:

Derived obj = new Derived(); 
obj.chainedMethodA().chainedMethodB(); 

コンパイラがchainedMethodB()にエラーが発生します関数呼び出し。これは、chainedMethodA()を実行するとBaseのオブジェクトが返され、chainedMethodBが定義されていないためです。

私は、この問題に対するいくつかの解決策を考えることができます(「最初の方法、およびそれからBase呼び出す」Derivedを呼び出すの方法)を順番に注意を払いながら

  1. チェーン方法。これは非常に脆弱な解決策のように見えます。
  2. chainedMethodADerivedに上書きするため、Baseの代わりにDerivedのインスタンスを返します。これは相続の浪費のようです。

この問題を回避する方法はありますか?おそらくDerivedで明示的にオーバーライドされずにDerivedのオブジェクトによって呼び出されたときに、chainedMethodADerivedインスタンスを返すように魔法のように変更するいくつかのコンストラクトです。 Derived

+5

2は、継承の無駄ではありません。これは継承です:より具体的な何かを行うためのオーバーライドです。この場合、より具体的な型を返します。 – Tunaki

+1

@TI確かにそうです:より具体的な型を返すようにオーバーライドして宣言することができます。 @Override public Derived chainedMethodA(){...} ' – Tunaki

+0

' Derived'の 'chainedMethodA'が' Derived'のインスタンスを返すようにしたい場合は、とにかくsuper実装を呼び出すことはできませんそれは 'Derived 'ではない実際の' Base'を返すかもしれないからです)。そうして何かを失うことはありません。また、 'Derived'オブジェクトを' Base'として使うことができます。 –

答えて

2
chainedMethodA

オーバーライドので、 Derived代わりにベースのインスタンスを返します。これは相続の浪費のようです。

あなたは間違っています。あなたは継承を無駄にしていません。

オーバーライドの手法は、それだけで、つまりメソッドを特化することです。オーバーライドは、返された型が、スーパークラスの元のオーバーライドされたメソッドで宣言された戻り型の型またはサブ型である場合に実行できます。この場合、あなたは何も違反していません。

オーバーライドの詳細については、hereを参照してください。ここで

例1:(スーパークラスのメソッドを呼び出す)ここで

public class Derived extends Base { 
    @Override 
    public Derived chainedMethodA(){ 

     super.chainedMethodA(); 
     //some stuff 
     return this; 
    } 

    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

例2:このような状況の継承では

public class Derived extends Base { 
    @Override 
    public Derived chainedMethodA(){ 
     //some stuff 
     return this; 
    } 

    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
    } 
+1

IMO、あなたの答えはそのようなオーバーライドの例を使うことができます:)。 – Tunaki

+0

@君たちは右だよ – granmirupa

+0

編集ありがとう!私は 'return(Derived)super.chainedMethodA();'についてはあまりよく分かりません。 'chainedMethodA'は' Base'を返すことができ、これは失敗します( 'ClassCastException')。方法については 'super.chainedMethodA();これを返す; '? – Tunaki

0

を(それがcompletele変更すると)おそらく最も簡単なソリューションです。

しかし、あなたの最後の文はかなりジェネリックを説明します

魔法の派生型のオブジェクトによって呼び出されたとき が明示的に派生で上書きされることなく、 派生インスタンスを返すようにchainedMethodAを変更するかもしれないいくつかの構築物。

だから、このようなものは、他の類似のユースケースに有用であり得る:

static class Base { 
    public <T extends Base> T chainedMethodA(Class<T> clazz) throws Exception { 
     // some stuff 
     return clazz.cast(this); 
    } 
} 

static class Derived extends Base { 
    public Derived chainedMethodB() { 
     // some stuff 
     return this; 
    } 
} 

public static void main(String args[]) throws Exception { 
    Derived obj = new Derived(); 
    obj.chainedMethodA(Derived.class).chainedMethodB(); 
} 
+1

いいえこれは過剰です。リフレクションAPIの導入はここでは絶対必要だと本当に思いますか?さらに、新しいインスタンスを作成するのでOPが望むことをしません。 – Tunaki

+0

OPは返品の種類がより心配だったので、実際にそのメソッドが行っていたことに注意を払わなかった。それにもかかわらず、Iveは同じインスタンスを返すように更新しました。 (そして、私はそれがおそらくオペレーションの状況で過度なことに同意する、したがって最初の行) – cowls

関連する問題