2016-11-16 42 views
1

我正在使用我公司中的API,我想爲現有對象創建子類。下面是警告:如何在Java中拋棄對象

  • 我不能修改超
  • 我不能修改超類對象如何實例

我看到最常見的例子是狗作爲動物的一個子類,所以我會用它。假設你在API中有這樣的類:

//API class, which I cannot modify 
public class Animal(){ 
    public void eat(){ 
     //All animals can do this 
    } 
} 

現在我想創建一個這樣的類,它向Animal添加了一些方法。

//My subclass, which I can modify 
public class Dog extends Animal(){ 
    public void fetch(){ 
     //Only dogs can do this 
    } 
} 

現在讓我們說,我有動物的一個實例(一個是不是狗)。我基本上需要將它貶低爲狗。我知道Java不直接支持向下轉換,但是有沒有解決方法?

public class AnimalExample{ 
    public static void main(String[] args){ 
     Animal animal = MyApi.getAnAnimal(); 
     //Dog dog = (Dog) animal; ---throws a runtime error 
     Dog dog = Dog.getDog(animal); //Maybe something like this? 

     //Then I should be able to call both eat() and fetch() 
     dog.eat(); 
     dog.fetch(); 
    } 
} 

我再次明白,不直接支持向下轉換。但是必須有一些解決方法,我無法弄清楚。我知道我可以使用包裝類(例如DogWrapper),但這會比我想要的更困難,因爲我仍然經常調用幾十種超類方法。

UPDATE:我知道它還不是狗,但我想知道是否有方法將它轉換成狗。它基本上聽起來像是,從人們所說的話,我要麼必須手動轉換它(逐個複製每個屬性/方法),要麼只是使用Wrapper類。一個包裝類似乎很少雜亂,所以不幸的是我只能走這條路。所以DogWrapper將有一個fetch()方法和getAnimal()方法。所以如果我想Dog吃,那麼我不得不打電話dog.getAnimal().eat()。我避免這樣做,但我想這是無法解決的。有沒有人看到比這更簡單的東西?

+2

「我基本上需要將其向下成狗」但它*不*一個'Dog'。你不能要求非狗狗表現得像狗一樣。 Downcasting *被*支持,但是它安全地完成了......只有當執行時間類型與請求的類型兼容時,轉換才能成功。你會期望'dog.fetch()'做什麼?如果它使用'Dog'中聲明的某些字段,它們不在實際的對象中呢? –

+0

所以,你有一些「動物」,它不是'狗',但是你想把它當作一隻狗來對待。您必須自己將其轉換爲「Dog」; Java自己無法知道如何做到這一點。 (爲什麼你認爲這是有用的?如果動物不是'狗',那麼如果你想調用一個特定於'狗'的方法,它應該怎麼做?)。 – Jesper

+0

我會建議做一些像if(動物instanceof狗){狗狗=(狗)動物}其他{//處理問題案例} – mdewit

回答

0

您可以擁有一個構造函數,該構造函數接受Animal並以默認值或根據需要實例化對象的Dog部分。

public Dog (Animal animal) { 
    super(); // any instantiation that has to be done for animal 
    // Dog instantiation 
    // Use animal properties as required 
} 
Dog dog = new Dog(animal); 

而且具有如你所說Dog.getDog(animal)是一種選擇,取決於你的喜好編碼的靜態方法。

+0

問題在於我沒有再使用_original_'Animal'對象。 「狗」的實例是一種全新的「動物」。因此,如果我要調用'dog.eat()',它會在'super()'中創建的'Animal'上調用'eat()'方法,而不是先創建的原始'Animal'。 –

+0

@JakeFairbairn你說的是不真實的,你用原始動物對象做的唯一事情是複製你需要的任何屬性,你做一個深層複製,以便不使用原始對象的引用。這將導致實例化一個全新的Dog對象,並且當您調用dog.eat時,它將位於新對象 – tinker

0

假設我創建了一個方法,它需要一個Dog,但是意在擴展Animal API。當然,我可以只讓簽字,像這樣:

public void doFetch(Dog dog) 

但正如我所說,我希望延長Animal API。現在,如果給定的Animal不是Dog,我無法獲取。考慮到這一點,我可以做到以下幾點:

public void doFetch(Animal fetcher) { 
    if(fetcher instanceof Dog) { 
     Dog dog = (Dog) fetcher; 
     ... //Do fetchy things 
     return; 
    } 
    //If we reach this point, then the animal is not a dog 
    throw new IllegalArgumentException("fetcher is not a Dog!"); 
} 

現在讓我們假設,在你的情況,我有一個Animal不是一隻狗,但我希望它是出於某種原因Dog。在這種情況下,我可以使用某種翻譯器將任何Animal轉換成狗。我喜歡來定義這樣的事情爲static方法在Dog類本身:

//Breaks the laws of nature by making a Dog from any Animal. 
public static Dog fromAnimal(Animal animal) { 
    Dog dog = new Dog(); 
    //Here you would set all the properties of the animal, e.g.: 
    dog.setName(animal.getName()); 
    ... 
    return dog; 
} 
+0

是的,我想過在一個新的Dog對象中創建一個動物的副本,但這真的很麻煩。如果在「動物」中做出任何更改,則不會在「狗」中反映出來。另外還有將近一百名隊員,我不得不經歷,這已經很醜了。 –