比方说,我们有一个类和重载函数:重载分析基本类型
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