2010-10-27 53 views
19

我想了解Java的多態性,並且我有一個關於向下轉換對象的問題。 比方說,在這個例子中,我有兩個子類狗和貓,從一個超類動物如何向下轉換Java對象?

繼承我的理解,向下轉型目標的唯一途徑是,如果這個對象已經是不錯的類型,像這樣:

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

此作品正確嗎?

但是如果我想創造一個普通的動物而不知道它會是什麼,然後在我知道時施放它,我該怎麼做?

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

這會在運行時引發ClassCastException嗎?

我發現做到這一點的唯一方法是創建從一個普通的動物造成狗新狗的構造函數:

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

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

所以我的問題是,怎麼了我應該這樣做?

  • 我是不是最好的方法?
  • 我不應該這樣做,如果我必須這樣做意味着我的程序設計得不好?
  • 我錯過了更好的方法嗎?

非常感謝! nbarraille

回答

8

如果要創建可能因非本地條件而異的類型實例,請使用Abstract Factory(如設計模式手冊中所述)。

在它的最簡單的形式:

interface AnimalFactory { 
    Animal createAnimal(); 
} 

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

還要注意有靜態類型的引用的和動態對象的類型之間的差異。即使您有Animal參考,但如果原始對象是Dog,它仍然表現爲Dog

1

Java是一種強類型語言,這意味着您只能將對象轉換爲它的擴展類型(超類或接口)。

即使您「僞造」,例如複製所有類的方法和字段,你不能將一個對象轉換爲它沒有擴展的類型。

public class Foo{ 

    public String phleem; 

    public void bar(){ 

    } 

} 

public class Bar{ 

    public String phleem; 

} 

public interface Baz{ 

    public void bar(); 

} 

鑑於上面的代碼,你可以不投一個Foo對象到任何一個BarBaz,雖然階級結構似乎暗示着你可以。沒有涉及繼承,因此引發ClassCastException

3

您應該只投一類的對象還真是,所以如果你有一個Dog擴展Animal你可以將其轉換爲Animal(因爲它是一個),但你不應該投的AnimalDog因爲不是所有的Animal都是Dog s。 Dog類可能會有額外的字段,這些字段不會被Animal類實現,因此投射沒有意義(您將這些值初始化爲什麼?)。

0

在這裏您正在討論向下轉換,所以在這種情況下,總是應該使用超類作爲引用,並且應該指向子對象。這個usd基本上在工廠模式。