假设我们有一个类和一个重载函数:
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的函数来调用g-
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。方法引用的类型。它不定义类型,但定义类型在不同上下文中何时兼容:
如果T是函数接口类型(§9.8),且表达式与从T派生的基本目标类型的函数类型一致,则方法引用表达式在赋值上下文、调用上下文或转换上下文中与目标类型T兼容。
地面类型是ToIntFunction
然后我查看了过载分辨率,发现是15.12.2.5。对于编译时声明
a的参数
Main::toInt
,选择对方法引用有特殊情况的最具体的方法来决定ToIntFunction
或ToDoubleFunction
的两个重载中的哪一个更具体-
对于表达式e,函数接口类型S比函数接口类型T更具体,如果T不是S的子类型,并且以下之一为真(其中U1... Uk和R1是S捕获的函数类型的参数类型和返回类型,V1...Vk和R2是T)的函数类型的参数类型和返回类型:
...
如果e是精确的方法参考表达式(§15.13.1),则i)表示所有i(1≤ 我≤ k) ,Ui与Vi相同,ii)以下情况之一是正确的:
R2是空的。
R1
R1是基元类型,R2是引用类型,方法引用的编译时声明的返回类型是基元类型。
R1是引用类型,R2是基元类型,方法引用的编译时声明具有引用类型的返回类型。
第一个条件显然不匹配,因为R1和R2不是无效的。
这两个接口
ToInFunction
和ToDoubleFunction
的不同之处在于它们的返回类型是基本类型double
和int
。对于基元类型,子句“R1”
最后两点也不合适,因为这两个函数接口都没有引用类型的返回值。
对于两个函数接口返回原语,并且代码应该被拒绝为不明确的情况,似乎没有规则。然而,javac接受该代码,我希望它也会接受。所以我想知道这是否是JLS中缺失的一点。
对于基元类型,子句"R1
事实并非如此double
实际上是int
的超类型。
第4.10段:
类型的超类型是通过对直接超类型关系的自反和传递闭包获得的,写为S
第4.10.1段:
以下规则定义了基元类型之间的直接超类型关系:
double
float
long
超类型关系是直接超类型关系的自反和传递闭包,这意味着从
(double
对于DynamicMessage,我想使用不同的处理方式,所以我尝试了 但它给出了编译错误 com中的“addMessageToResult(Message,Descriptor,Builder)”。谷歌。云垂直方向。电信公司。taap。数据流。数据摄取。常见的解析器。CSVParserDynamicMessage与com中的addMessageToResult(Message,Descripto
有没有办法告诉Java不要试图从使用基元类型的方法引用中推断类型? 这是我写的一个方法,原因现在无关紧要: 现在,如果您将方法引用传递给返回原始类型的“isEquals”,该怎么办? 这一切都很好,但Java也会接受这种奇怪的用法: 这是因为编译器将推断类型参数T为"
在C 11中,如何专门化一个函数模板,该模板使用decltype声明为“复杂”的尾部返回类型?以下内容适用于GCC,但在VC2013中产生了“错误C2912:显式专业化‘int f(void)’i不是功能模板的专业化”: 我说“复杂”是因为缺乏一个技术上精确的词,因为我不确定是什么造成了差异。例如,以下decltype使用不依赖于任何函数结果类型的内置操作,可以与模板专业化配合使用: 自动f()-
具有以下3种重载 以下内容是否格式不正确? Clang选择重载#2,而gcc无法编译(演示) 移除过载#1时,双方同意选择过载#2(演示)。 删除重载#2时,gcc选择重载#1,clang编译失败(演示)
顺便说一句,我确实编译了以下内容,但是专门化在运行时没有像预期的那样工作。基类型和派生类型最终要经历的非专用版本。 正确的语法是什么?
J.Bloch在《Effective Java》中提到,将varargs方法与基元类型一起使用是不安全的。简而言之,的返回类型为,这听起来很合理。现在我试图自己复制这种行为,但做不到: 我的问题是,为什么类型被推导为,而不是像他所说的那样被推导为?这是否意味着,在Java8中,关于varargs的问题不再相关了,如果我们不太关心性能,我们可以在任何地方安全地使用它们。