2016-12-20 3 views
2

初期クラスを返すメソッドを持つ非常に単純なクラスをサブクラス化するのに問題があります。MySubClassがMyClassを継承しているときに、MyClass内でMyClassオブジェクトを返すメソッドを使用する

public class MyClass { 

    public MyClass(){ 
    } 

    public MyClass filterOn(String something){ 
     MyClass result=new MyClass(); 
     result.doSomethingUsingThisInstance(this, something); 

     return result; 
    } 

} 


public class MySubClass extends MyClass{ 
    .... 
} 

[OK]を、今、私はこれをコールする場合:

MySubClass subClass=new MySubClass(); 
    MySubClass subClass2=(MySubClass)subClass.filterOn("Hello World"); 

は、その後、私は とjava.lang.ClassCastExceptionがあります。これを防ぐためにどのようにMYSUBCLASS

にMyClassのキャストできないのですか?

+0

を 'filterOn'からの戻り値が'です:あなたは今でもそれだけで(まだ実装、クライアントは心配する必要は何も内側)のキャストを必要とし、サブクラスで特定のサブタイプを返すとそれを組み合わせることができますMyClass'ではなく、 'MySubClass'であるので、例外は十分に有効です。 'result'の型を変更して修正してください。 – Henrik

+0

あなたのフィルタメソッドの 'MyClass result = new MyClass();'に問題があります。あなたはスーパーインスタンスを作成し、最後に返します。サブタイプにキャストすることはできません。 MySubClassのfilterOnメソッドをオーバーライドしたいと思うかもしれません。 – Kent

+0

最も簡単な解決策は 'subClass2'を' MySubClass'イントランスではないのでキャストしないことです。 'MySubClass'のインスタンスが必要な場合は、単純に' filteron'を上書きして、代わりに 'MySubClass'インスタンスを返します。 – n247s

答えて

2

オーバーライドfilterOn()方法は、あなたがMySubClassで希望のインスタンスを作成します。

public class MySubClass extends MyClass{ 

    public MyClass filterOn(String something){ 
     MySubClass result = new MySubClass(); 
     result.doSomethingUsingThisInstance(this, something); 
     return result; 
    } 
    .... 
} 

あなたはまた、避けることができfilterOn()メソッドの複製をMyClassにメソッドを導入して、サブクラスでオーバーライドする現在のクラスのインスタンスを作成します。

public class MyClass { 

    public MyClass(){ 
    } 

    public MyClass createSpecificInstance() { 
    return new MyClass(); 
    } 

    public MyClass filterOn(String something){ 
     MyClass result = createSpecificInstance(); 
     result.doSomethingUsingThisInstance(this, something); 

     return result; 
    } 

} 

今、サブクラスのみcreateSpecificInstance()をオーバーライド:

public class MySubClass extends MyClass { 

    public MyClass createSpecificInstance() { 
    return new MySubClass(); 
    } 

} 
+0

簡単な解決法:D。何らかの「ジェネリック」トリックを使って自分のメソッドを宣言する方法があるでしょうか(私はそれを全くマスターしません)? – Myoch

+0

確かにそうかもしれませんが、疑似ファクトリメソッド 'createSpecificInstance()'を避けたい場合は、リフレクションを使用するべきです。 – davidxxx

+0

もう少し説明してください。あなたはジェネリックスを使うことができると言っています(しかし、どのように?)私は反射を使用する場合(Methodクラスを使用する場合のように)、そうですか? – Myoch

0
(MySubClass)subClass.filterOn("Hello World"); 

public MyClass filterOn(String something) 

あなたは、派生クラスに基本クラスをキャストすることはできません。あなたが行う場合は、その例外、

がこれを読んでClassCastExceptionが得られます。java.lang.ClassCastException

0

あなたはクラスのキャスト例外では機能せず、結果として派生型のために、戻り値をキャストしようとします。

理由:基本クラスで属性/メソッドのみが必要なので、型階層の上向きキャストが機能します(些細なことですが)。それ以外の方法では問題が発生する可能性があるため、動作しません。考えてみましょう:

class Base { 
// some stuff here 
} 

class Derived1 extends Base { 
    private int foo; 
} 

class Derived2 extends Base { 
    private String bar; 
} 

Base myObject = new Derived1(); 
// this works, Derived1 has everything Base requires 
// myObject.foo still exists, but can not be trivially accessed. 

Derived2 myOtherObject = (Derived2)myObject; 
// Now what? 
// What happens to myObject.foo? 
// Where does myOtherObject.bar come from? 

あなたがあなたの状況にどのような操作を行うことができます。

  • filterOn()の実装は派生クラスの具体的な実装に応じて、非常に異なっている場合は、その中に抽象作ります派生クラスで再実装します。
  • デザインに問題がないかどうかを確認してください。あなたは本当に派生クラスにfilterOn()の結果をキャストする必要がありますか?
  • Genericsを使用してください。派生クラスはベースクラスのジェネリックとして使用できることに注意してください。これは、filterOn()の実装が各サブクラス(コースのタイプを除く)とまったく同じ場合にのみ機能します。
  • 基本クラスから派生クラスインスタンスを作成できるコンストラクタを提供します。キャストの代わりに使用してください。
Derived1(Base baseObject){ 
    // copy all the stuff from the base object 
    this.foo = 0; // initialize the rest 
} 
  • の行に何かがたぶん継承は何が必要ではありません。構成には相続性が非常に高い傾向があります(Explained nicely here)。だから、あなたはそれを試すことができます:
class BetterThenDerived { 
    private Base myBaseObject; 
    private int foo; 
} 
0

これは、共分散の問題の側面です。例えば、Covariance and contravarianceを参照してください。そしてDemonstrate covariance and contravariance in Java?。 Javaが優れている場所ではありませんが、いくつかのオプションがあります。

最初にメソッドをオーバーライドすると、より具体的な戻り値の型を宣言することができます。たとえば、MySubClassの場合、次のように宣言することができます。

@Override 
public MySubClass filterOn(String something) { 
    // ... 
} 

これで問題は解決しません。この方法でも、MySubClassオブジェクトに何かを作成して実行する方法が必要です。それがしていることは、クライアントコードをキャストする必要がなくなります。あなたは(result.doSomethingUsingThisInstance()protectedpublicであることを提供する)方法フォームdavidxxxの答えの実装を取ることがあります。

@Override 
public MySubClass filterOn(String something) { 
    MySubClass result = new MySubClass(); 
    result.doSomethingUsingThisInstance(this, something); 
    return result; 
} 

あなたはすべてのあなたのサブクラスでこのメソッドを複製する必要が悩まさすることができます。実際の仕事がresult.doSomethingUsingThisInstance()に残っていれば、私はあなたがそれと一緒に暮らすことができると思うべきです。他の考えは正しい実行時の型のオブジェクト生成するためのclone()にある

public class MyClass implements Cloneable { 

    public MyClass filterOn(String something) { 
     try { 
      MyClass result = (MyClass) this.clone(); 
      result.doSomethingUsingThisInstance(this, something); 

      return result; 
     } catch (CloneNotSupportedException cnse) { 
      throw new AssertionError(cnse); 
     } 
    } 

} 

を私はしかし、このアイデアを使用する前によく考えたいです。クローンに含まれたくないデータが含まれている理由の1つで、クローンで作業する前にクリアされていることを確認する必要があります。

public class MySubClass extends MyClass { 

    @Override 
    public MySubClass filterOn(String something) { 
     return (MySubClass) super.filterOn(something); 
    } 

} 
関連する問題