2017-05-09 69 views
0

我已經爲協變返回類型創建了一個繼承的小例子。有basicly三個不同的類別:具有協變返回類型的Java類型轉換

MainApp:

public class MainApp { 
    public static void main(String[] args) { 
    BaseManager manager = new BirdManager(); 
    BirdManager birds = (BirdManager) manager.getManager(); // <-- Why type cast here 
    // prints BirdManager 
    } 
} 

BaseManager:

public abstract class BaseManager { 
    private Map<ManagerType, BaseManager> list = new EnumMap<>(ManagerType.class); 
    protected Map<ManagerType, BaseManager> getList() { 
    return list; 
    } 
    public abstract BaseManager getManager(); 
} 

BirdManager:

public class BirdManager extends BaseManager { 
    public BirdManager getManager() { 
    if (!super.getList().containsKey(ManagerType.BIRD)) { 
     super.getList().put(ManagerType.BIRD, this); 
    } 
    return (BirdManager) super.getList().get(ManagerType.BIRD); 
} 

爲什麼我需要強制轉換BaseManagerBirdManager當我重寫方法getManager()返回BirdManager

我用Can overridden methods differ in return type?作爲參考。

編輯:

我有不同的子型號,所有從BaseManager繼承。所有型號都允許存在一次。我試圖將這些模型添加到列表中,而不是爲每個模型使用單例。隨着getManager()我想獲得實際的模型。也許我必須重新設計我的設計。

+1

這是因爲'manager'屬於'BaseManager'類型,所以編譯器只'知道''manager.getManager()'返回一個'BaseManager'。 'BaseManager.getManager()'的簽名證實了這一點。 [見這篇文章](http://stackoverflow.com/questions/16730109/difference-between-object-type-and-reference-type)。爲什麼你需要'getManager()'方法呢? –

回答

3

您打電話給您的方法的manager對象是BaseManager,而不是BirdManager。編譯器不知道你實際調用了一個BirdManager的方法,它只會在運行時才知道,這就是爲什麼你需要一個強制轉換。

+0

好的,這是有道理的。有沒有辦法避免使用某種模式或泛型的類型轉換?或者在這種情況下強調「足夠好」? – FaltFe

+0

我真的不明白'getManager()'方法的意義,但是'BaseManager'類中可能類似這樣:'public T getManager(){return(T)this; }'。我不建議使用它,這只是一種可能性,它打破了泛型的全部目的(編譯時類型安全性)。 – Shadov

0

因爲manager是BaseManager的一個實例,而不是BirdManager。因此,您可以將它用於鳥類實例,您需要對它進行類型化。