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