2016-11-09 104 views
3
abstract class AbsClass {} 

class MyAbs extends AbsClass {} 

class MyClass<S extends AbsClass> { 
    S getObj() { 
     return new MyAbs(); 
    } 
} 

獲取編譯器的問題:Java泛型和不兼容的類型<S伸展{}類>

Error:(33, 16) java: incompatible types: MyAbs cannot be converted to S

什麼是做這種正確的方法是什麼?

編輯: 我希望能夠初始化MyClass {MyAbs},然後調用getObj(),它將返回MyAbs對象。隨着安迪的回答,我將不得不將AbsClass施加到MyAbs或MySecondAbs,這正是我試圖避免

+2

刪除'',並更改單曲getObj()'要麼'MyAbs getObj( )'或'AbsClass getObj()'。就目前而言,沒有理由有一個類型變量。 –

+1

你能說出「做這個」時你想要什麼嗎? – Simon

+0

我希望能夠初始化MyClass ,然後調用getObj(),它將返回MyAbs對象。隨着安迪的回答,我將不得不將AbsClass投給MyAbs或MySecondAbs,這正是我試圖避免的 – mwong56

回答

3

S擴展MyAbs,而不是相反。 S類型的任何對象都可以投射到MyAbs,但MyAbs不能投射到它的派生類中。

請解釋你想達到的目標。

+1

所有的貴賓狗都是狗,但並非所有的狗都是貴賓狗。 – Taylor

5

Andy已經描述瞭如何解決這個問題,我會盡力解釋原因。

S不保證可指定爲MyAbs,只能指定爲AbsClass,每個實例將指定AbsClass的子類。

考慮:

class MyOtherAbs extends AbsClass {} 

MyClass myClass = new MyClass<MyOtherAbsClass>{}; 

這跟你有什麼衝突。

UPDATE:

根據您的意見,它看起來像你想實現以上。挑戰是如果MyOtherAbs有一個帶參數的構造函數?或者被實現爲單例(即私有構造函數和靜態getInstance())。總之,沒有保證統一的方式可以構建這些。此外,由於類型擦除,在運行時,S的概念沒有了,所以你不能這樣做:

return new S(); 

你基本上有兩種選擇,一種是使用子類:

public interface AbsClassFactory<S extends AbsClass>{ //takes the place of MyClass 
    public S getInstance(); 
} 

MyAbsFactory implements AbsClassFactory<MyAbs>{ 
    public MyAbs getInstance(){ 
     return new MyAbs(); //or however MyAbs is instantiated 
    } 
} 

另一種選擇是反思:

class MyClass { 
    public <S extends AbsClass> S getObj(Class<S> clazz) throws InstantiationException, IllegalAccessException { 
     return clazz.newInstance(); 
    } 
} 

注意,第二個假設有可用的無參數的構造函數,將拋出一個運行時異常,如果一個不是。

+0

你的例子就是我想要完成的事情,對不清楚的事情感到抱歉。 – mwong56

+0

我會擴大答案以提供替代方案 – Taylor

1

從您的評論似乎可以使用Supplier接口來完成相同的:

Supplier<MyAbs> supp = MyAbs::new; // Constructor reference 
MyAbs obj = supp.get(); 

Supplier<MySecondAbs> supp2 = MySecondAbs::new; 
MySecondAbs obj2 = supp2.get();