web-dev-qa-db-ja.com

Javaオブジェクトをダウンキャストする方法は?

Javaのポリモーフィズムを理解しようとしていますが、オブジェクトのダウンキャストについて1つ質問があります。この例では、スーパークラスの動物から継承する2つのサブクラスDogとCatがあるとします。

私が理解したことから、オブジェクトをダウンキャストする唯一の方法は、このオブジェクトがすでに次のように適切なタイプである場合です。

Animal a = new Dog();
Dog d = (Dog) a;

これは正しく機能しますか?

しかし、それが何であるかを知らずに通常の動物を作成し、それを知ったときにそれをキャストしたい場合はどうすればよいですか?

Animal a = new Animal();
Dog d = (Dog) a;

これは実行時にClassCastExceptionをスローしますよね?

私がそれを行うために見つけた唯一の方法は、通常の動物から犬を作成する新しいDogコンストラクターを作成することです。

Animal a = new Animal();
Dog d = new Dog(a);

public Class Dog extends Animal{
   public Dog(Animal a){
      super(a);
   }
}

だから私の質問は、これをどのように行うべきかということです。

  • 私はそれを最善の方法でやっていますか?
  • 私はこれをまったく行うべきではありません、もし私がそうしなければならないのであれば、私のプログラムはよく考えられていませんか?
  • 私が逃したより良い方法はありますか?

どうもありがとう! nbarraille

19
nbarraille

非ローカル条件に応じて変化する可能性のあるタイプのインスタンスを作成する場合は、 Abstract Factory を使用します(デザインパターンの本で説明されています)。

最も単純な形式では:

interface AnimalFactory {
    Animal createAnimal();
}

class DogFactory implements AnimalFactory {
    public Dog createAnimal() {
        return new Dog();
    }
}

参照の静的タイプとオブジェクトの動的タイプには違いがあることにも注意してください。 Animal参照がある場合でも、元のオブジェクトがDogの場合は、Dogのように動作します。

オブジェクトが実際にあるクラスにのみキャストする必要があるため、Dogを拡張するAnimalがある場合は、それをAnimalにキャストできます(1つであるため)ただし、すべてのAnimalDogsであるとは限らないため、AnimalDogにキャストしないでください。 Dogクラスには、Animalクラスによって実装されていない追加のフィールドがある可能性があるため、キャストは意味がありません(これらの値を何に初期化するのですか?)。

3
Jackson Pope

Javaは強く型付けされた言語であるため、オブジェクトをキャストできるのは、オブジェクトの拡張元の型(スーパークラスまたはインターフェース)のみです。

あなたが「それを偽造」したとしても、例えばすべてのクラスのメソッドとフィールドをコピーします。オブジェクトを拡張しない型にキャストすることはできません。

public class Foo{

    public String phleem;

    public void bar(){

    }

}

public class Bar{

    public String phleem;

}

public interface Baz{

    public void bar();

}

上記のコードを考えると、FooオブジェクトをBarまたはBazのいずれかにキャストすることはできませんが、クラス構造はキャストできることを示唆しているようです。継承は含まれないため、ClassCastExceptionがスローされます。

1

ここではダウンキャストについて話しているので、このシナリオでは常にスーパークラスを参照として使用し、子オブジェクトをそれによって指す必要があります。この米ドルは基本的に工場のパターンです。

0
Arun Pandeu