使用方法引用和原始类型的函数接口特化来重载分辨率

Jen*_*ens 6 java language-lawyer overload-resolution method-reference

假设我们有一个类和一个重载函数:

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;
    }
}
Run Code Online (Sandbox Code Playgroud)

我想用方法引用调用g来调用类型为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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这适用于javac,但不适用于eclipse ecj.我向ecj提交了一个错误报告,但我不确定这是否是一个ecj或javac错误,并尝试按照重载解析算法来解决它.我的感觉是,代码应该被接受,因为它是直观合理的ToIntFunction是更好的匹配toIntToDoubleFunction.但是,我对JLS的解读是它应该被拒绝,因为没有理由让一个更具体.

我不得不承认我在JLS规范中有点迷失,并会感谢一些帮助.我首先想要计算它的类型Main::double2int,所以我看了15.13.2.方法参考的类型.它没有定义类型,但它定义了何时类型在不同的上下文中兼容:

如果T是函数接口类型(第9.8节),并且表达式与从T派生的地面目标类型的函数类型一致,则方法引用表达式在赋值上下文,调用上下文或具有目标类型T的转换上下文中是兼容的.

地面类型是ToIntFunction<A>ToDoubleFunction<A>.toInt返回一个int是分配兼容的两倍,所以我可以得出结论,该方法是参考与campatible ToIntFunction<? extends A>ToDoubleFunction<? extends A>在调用上下文.这可以通过将方法引用到两者ToIntFunction<? extends A>并且ToDoubleFunction<? extends A>在主函数中被接受来验证.

然后我查看了重载决议,找到了15.12.2.5.选择具有方法引用特殊情况的最具体方法,以确定两个重载中的哪一个ToIntFunctionToDoubleFunction更具体地用于Main::toInt编译时声明的参数A -> int.

如果T不是S的子类型且下列之一为真,则功能接口类型S比表达式e的功能接口类型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".double和之间没有关系int,因此这种情况不能定义哪种类型更具体.

最后两点不适合,因为两个功能接口都没有引用类型的返回值.

当两个功能接口返回原语并且代码应该被拒绝为模糊时,似乎没有规则.但是,javac接受了代码,我希望它能够这样做.所以我想知道这是否是JLS中的缺失点.

Ant*_*ton 3

\n

对于原始类型,根据类型的大小,在 4.10.1 中定义了子句“R1 <: R2”。double 和 int 之间没有关系,因此本例没有定义哪种类型更具体。

\n
\n\n

不是这种情况; double事实上,是一个超类型int

\n\n

第 4.10 段

\n\n
\n

类型的超类型是通过直接超类型关系(写作 )上的自反和传递闭包S >\xe2\x82\x81 T获得的,该关系由本节后面给出的规则定义。我们写到S :> T\n表示父类型关系在S和 之间成立T

\n
\n\n

第 4.10.1 段

\n\n
\n

以下规则定义了原始类型之间的直接父类型关系:

\n\n

double >\xe2\x82\x81 float

\n\n

float >\xe2\x82\x81 long

\n\n

long >\xe2\x82\x81 int

\n
\n\n

类型关系是直接超类型关系的自反和传递闭包,意味着 from(double >\xe2\x82\x81 float) \xe2\x88\xa7 (float >\xe2\x82\x81 long) \xe2\x88\xa7 (long >\xe2\x82\x81 int)如下double :> int

\n