比方說,我們有一個類和重載函數:重載分析基本類型
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
}
,我想打電話給摹與方法參照A型的功能 - > INT:
public class Main {
static final class A {
}
public static String g(ToIntFunction<? extends A> f) {
return null;
}
public static String g(ToDoubleFunction<? extends A> f) {
return null;
}
private static int toInt(A x) {
return 2;
}
public static void main(String[] args) {
ToIntFunction<? extends A> f1 = Main::toInt;
ToDoubleFunction<? extends A> f2 = Main::toInt;
g(Main::toInt);
}
}
這個工程用javac,但不是用eclipse ECJ。我向ecj提交了一個錯誤報告,但我不確定這是一個ecj還是javac錯誤,並試圖按照重載解析算法計算出來。我的感覺是代碼應該被接受,因爲ToIntFunction
比ToDoubleFunction
更適合toInt
。但是,我對JLS的閱讀是,它應該被拒絕,因爲沒有理由讓某個人更具體。
我不得不承認,我有點迷失在JLS規範,並希望得到一些幫助。我首先想要計算Main::double2int
的類型,所以我查看了15.13.2. Type of a Method Reference。它沒有定義的類型,但是,當類型是在不同的上下文兼容它定義:
的方法參照表達是在分配上下文, 調用上下文,或者與目標類型T如果鑄造上下文兼容Ť是 功能接口類型(§9.8)和表達式是全等 從T.
接地類型是ToIntFunction<A>
和ToDoubleFunction<A>
導出的地面目標類型的函數類型。 toInt
返回一個int,它的賦值兼容性爲double,所以我可以斷定在調用上下文中方法引用可與ToIntFunction<? extends A>
和ToDoubleFunction<? extends A>
兼容。這可以通過將方法參考同時在主函數中接受ToIntFunction<? extends A>
和ToDoubleFunction<? extends A>
來驗證。
然後我看着重載,發現15.12.2.5. Choosing the Most Specific Method這對於方法的引用來決定哪兩個重載ToIntFunction
或ToDoubleFunction
的是編譯時聲明A -> int
的參數Main::toInt
更具體的一個特例。
如果T不是S的子類型,並且以下情況之一成立,則函數接口類型S比函數接口類型T更具體:(其中U1 ... Uk和R1是參數類型和S的捕獲的功能類型的返回類型,V1 ... VK和R2是參數類型和返回T的函數類型)的類型:
...
如果e是精確的方法參考表達式(§15.13.1),則i)對於 全部i(1≤i≤k),Ui與Vi相同,並且ii)以下其中一個 爲真:
R2無效。
R1 <:R2。
R1是原始類型,R2是引用類型,並且方法引用的編譯時間 聲明的返回類型是 基本類型。
R1是引用類型,R2是原始類型,並且方法引用的編譯時間 聲明的返回類型是 引用類型。
第一個條件顯然不匹配,因爲R1和R2不是無效的。
兩個接口ToIntFunction
和ToDoubleFunction
的區別僅在於它們的返回類型是原始類型double
和int
。對於原始類型,根據類型的大小在4.10.1中定義子句「R1 <:R2」。 double
和int
之間沒有關係,所以這種情況並沒有定義哪種類型更具體。
最後兩點不適合,因爲兩個功能接口都沒有引用類型的返回值。
似乎沒有規則的情況下,當兩個功能接口返回原語和代碼應拒絕爲不明確的。但是,javac接受代碼,我期望它能這樣做。所以我想知道這是否是JLS中的一個缺點。
好的。非常簡單...所以結論是,ToIntFunction比ToDoubleFunction更好匹配,並且代碼是兼容的。在這種情況下,這是一個ecj錯誤。 – Jens