【发布时间】:2016-02-28 18:38:38
【问题描述】:
JDK 是 Oracle 的 JDK 1.8u65,但“低至”1.8u25 也出现了问题。
这是完整的 SSCCE:
public final class Foo
{
private interface X
{
default void x()
{
}
}
private enum E1
implements X
{
INSTANCE,
;
}
private enum E2
implements X
{
INSTANCE,
;
}
public static void main(final String... args)
{
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);
}
}
此代码编译;但它在运行时失败:
Exception in thread "main" java.lang.BootstrapMethodError: call site initialization exception
at java.lang.invoke.CallSite.makeSite(CallSite.java:341)
at java.lang.invoke.MethodHandleNatives.linkCallSiteImpl(MethodHandleNatives.java:307)
at java.lang.invoke.MethodHandleNatives.linkCallSite(MethodHandleNatives.java:297)
at com.github.fge.grappa.debugger.main.Foo.main(Foo.java:38)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:497)
at com.intellij.rt.execution.application.AppMain.main(AppMain.java:144)
Caused by: java.lang.invoke.LambdaConversionException: Invalid receiver type class java.lang.Enum; not a subtype of implementation type interface com.github.fge.grappa.debugger.main.Foo$X
at java.lang.invoke.AbstractValidatingLambdaMetafactory.validateMetafactoryArgs(AbstractValidatingLambdaMetafactory.java:233)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:303)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 8 more
在代码中修复它很“容易”;在 main 方法中,您只需:
// Note the <X>
Stream.<X>of(E1.INSTANCE, E2.INSTANCE).forEach(X::x);
编辑实际上还有第二种方法,正如接受的答案中提到的那样...用 lambda 替换方法引用:
Stream.of(E1.INSTANCE, E2.INSTANCE).forEach(x -> x.x());
所以,嗯。这里会发生什么?为什么最初的代码会编译?我原以为编译器会注意到方法引用不在任何 Enum<?> 上,而是在 X 上,但没有...
我错过了什么?这是编译器中的错误吗?是我的误会?
【问题讨论】:
-
可能是一个相关的
javac错误:JDK-8141508 虽然它似乎处理相交类型。 -
它是一个相交类型。根据我的 Eclipse,
Stream.of(E1.INSTANCE,E2.INSTANCE)的推断类型是Stream<Enum<?>&Foo.X>。 -
@Tunaki Easy:您将其分配给一个不相关的变量,例如
int i = Stream.of(...),然后查看错误消息抱怨的内容。 :-) -
@RealSkeptic 不错,我明白了! :) 我猜这与上面的错误相同。
-
@fge 我会这么认为。它报告了两种不同类型的事实——一种是悬停在
of或forEach上时,它只是说它是一个枚举流,另一种是当我使用上面的技巧时意味着编译器本身有点混乱。我认为其中一个允许X::x,但另一个写入引用错误类型的字节码。
标签: java java-8 type-inference