6

比方說,我們有一個類和重載函數:重載分析基本類型

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錯誤,並試圖按照重載解析算法計算出來。我的感覺是代碼應該被接受,因爲ToIntFunctionToDoubleFunction更適合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這對於方法的引用來決定哪兩個重載ToIntFunctionToDoubleFunction的是編譯時聲明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不是無效的。

兩個接口ToIntFunctionToDoubleFunction的區別僅在於它們的返回類型是原始類型doubleint。對於原始類型,根據類型的大小在4.10.1中定義子句「R1 <:R2」。 doubleint之間沒有關係,所以這種情況並沒有定義哪種類型更具體。

最後兩點不適合,因爲兩個功能接口都沒有引用類型的返回值。

似乎沒有規則的情況下,當兩個功能接口返回原語和代碼應拒絕爲不明確的。但是,javac接受代碼,我期望它能這樣做。所以我想知道這是否是JLS中的一個缺點。

回答

3

對於原始類型,子句「R1 <:R2」根據類型的大小在4.10.1中定義。 double和int之間沒有關係,所以這種情況並沒有定義哪種類型更具體。

事實並非如此;實際上,doubleint的超類型。

Paragraph 4.10

一種類型的超類型由自反和傳遞 閉合在所述直接超類型關係獲得,寫入S >₁ T,這是 通過在本節後面給出規則定義的。我們寫S :> T至 表示超類型關係在ST之間。

Paragraph 4.10.1

以下規則定義的 原始類型之間的直接父類型關係:

double >₁ float

float >₁ long

long >₁ int

超型關係是所述直接超類型關係的一種反射性和傳遞閉包意味着從(double >₁ float) ∧ (float >₁ long) ∧ (long >₁ int)如下double :> int

+0

好的。非常簡單...所以結論是,ToIntFunction比ToDoubleFunction更好匹配,並且代碼是兼容的。在這種情況下,這是一個ecj錯誤。 – Jens