2015-11-04 72 views
0

我在下面的Java代碼中遇到了一個非常奇怪的編譯錯誤。Java通用返回類型問題

我有具有通用返回類型的API一個簡單的界面:

public interface AttributeGenerator { 

    <T> T generateAttribute(Record record); 
} 

我可以寫一個實現,這在一個晴朗的編譯:

public class StringAttributeGenerator implements AttributeGenerator { 

    @Override 
    public String generateAttribute(Record record) { 
      return "Test"; 
    } 
} 

現在,讓我們說,我再添參數到上述接口。

public interface AttributeGenerator { 

    <T> T generateAttribute(Record record, Set<Integer> indices); 
} 

我提供了另一種實現方式爲:

public class StringAttributeGenerator implements AttributeGenerator { 

    @Override 
    public String generateAttribute(Record record, Set<Integer> indices) { 
     return "Test"; 
    } 

} 

的編譯失敗,編譯器抱怨:

該方法不從其超覆蓋。

我不明白爲什麼編譯器不能編譯第二個實例,如果不是,我想了解爲什麼Java不能爲用戶提供編寫這樣的代碼的工具。

+0

第一個代碼段不能編譯給我(JDK 1.8.0_60) – Tunaki

+1

@Tanuki奇怪!它爲我編譯好!你會得到什麼錯誤? – bhuwansahni

+0

編譯第一個代碼片段,我得到:'Type safety:來自類型StringAttributeGenerator的generateAttribute(Record)的返回類型String需要未檢查的轉換以符合來自類型AttributeGenerator'的T,但我在eclipse中設置了警告。 – azurefrog

回答

3

AFAIK問題是,在第一種情況下,您確實禁用了泛型。這將導致T在這種情況下被強制爲Object,並且由於返回類型協方差返回String沒有問題。不過,這應該會產生一個警告,因爲你基本上迫使編譯器忽略泛型,並使用「傳統」的方式,直接編寫Object generateAttribute(Record record)

在第二種情況下,如果您按照上述方式禁用泛型,則簽名將看起來像generateAttribute(Record record, Set indices),其中第二個參數等於Set<Object>,因此簽名不再匹配。

另請注意,儘管您的第一個代碼段可以編譯,但您可能會遇到運行時問題,例如,如果你做了這樣的事情:

AttributeGenerator unknownGenerator = new StringAttributeGenerator(); 

//You'd get a string and the system would try to cast to Integer, which clearly will fail 
Integer iWontCompile = unknownGenerator.generateAttribute(someRecord); 

你可以做的是在界面,例如定義T像這樣:

public interface AttributeGenerator<T> { 
    T generateAttribute(Record record, Set<Integer> indices); 
} 

public class StringAttributeGenerator implements AttributeGenerator<String> { 
@Override 
    public String generateAttribute(Record record, Set<Integer> indices) { 
    return "Test"; 
    } 
} 
+0

我目前在這個主題的JLS中找不到適當的部分,所以如果有人確實可以隨意添加它作爲評論,我會將鏈接放入答案中。 – Thomas

+0

其實,我明白最後一部分,這是一個實驗。但是這意味着如果我想失去返回類型安全性,我也會失去泛型方法參數的安全性! – bhuwansahni

+0

@bhuwansahni是的,你只能得到一個或另一個。但是,如果你想犧牲返回類型的安全性(這可能導致難以跟蹤錯誤),爲什麼不提供一個方法來返回Object或者在接口中聲明通用類型並將它定義爲Object中的Object實施?除此之外,像你一樣使用類型推斷是非常危險的,因爲你不能直接訪問實現中的推斷類型,因此你必須相信調用者使用正確的類型。 – Thomas