[英]Java 8 generic function should be ambiguous, but failing in runtime
我正在嘗試將Java 7代碼遷移到Java 8,所以我的代碼類似於:
package tests;
import java.util.Arrays;
import java.util.Map;
public class Tests {
private static interface ComparableMap<K,V> extends Map<K,V>, Comparable {}
public static void main(String[] args) {
func(getString());
}
private static void func(Comparable...input){
System.out.println(Arrays.toString(input));
}
private static void func(ComparableMap <?,?> m){
System.out.println(m);
}
private static <T extends Comparable> T getString(){
return (T) "aaa";
}
}
在java 7中它正常工作,在Java 8中我得到:
java.lang.ClassCastException:java.lang.String無法強制轉換為tests.Tests $ ComparableMap
如果我將一個函數定義更改為:
private static <T> T getString(){
return (T) "aaa";
}
編譯將失敗:錯誤:
對func的引用含糊不清
為什么Java 8編譯器在第一種情況下沒有失敗? (看起來對我來說是錯誤的)是否可以更改第二個重載函數,以便在不更改調用本身的情況下使用varargs參數調用第一個函數?
在第一種情況下,需要方法getString
來返回Comparable
實例。 編譯器查找func
方法的重載,它只找到一個可以接受Comparable
: func(Comparable ... input)
。 Map
沒有實現該接口,因此第二個重載不適用。 沒有含糊之處。
在第二種情況下, getString
可以返回任何內容。 這兩個重載都有效,因此存在歧義。 但請注意,在兩種情況下,對T的強制轉換都是不安全/錯誤的。
你編寫的泛型方法基本上告訴編譯器“我可以返回你想要實現Comparable
的任何類的實例”。 但你實際上不能遵守這個承諾。
可以說我有以下代碼:
String str = getString();
Integer num = getString();
這段代碼將編譯, String
和Integer
實現Comparable
接口。 第二行在運行時會失敗:代碼嘗試將String
轉換為Integer
。
你的第二個案例也是錯誤的,原因與我上面解釋的相同。 它承諾它可以返回任何你想要的類型 。 它似乎也不能保持這個承諾( Runnable
這里是一個隨機的例子,它可以是任何東西):
Runnable run = getString()
編譯器看到兩個可能的重載,它們都匹配, func(Comparable...input)
和func(ComparableMap <?,?> m)
。 它更喜歡第二個,因為varargs方法總是最后選擇( 出於競爭性原因 )。 所有這些都是核心行為。
然后代碼拋出ClassCastException,因為你的getString
方法沒有保證它的承諾(讓調用者決定返回什么類型的Comparable
)。
根本問題是你的getString
方法犯了一個假承諾。 因此,我真的不知道該代碼試圖完成什么。 如果你能詳細說明,我們可以幫助你進一步發展。
是的,我不知道為什么Java 8會選擇帶有映射的重載超過采用Comparable vararg的映射。 我猜這個好的老式擦除在這里發揮作用。
也就是說,我只是讓getString()
返回一個Comparable
而不是T
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.