为什么此方法引用在运行时失败,但相应的 lambda 调用却失败?



我有两个接口。一个是公共的(A(,另一个是包私有的(AA(。A扩展AA.

package pkg.a;
@FunctionalInterface
public interface A extends AA {
}

.

package pkg.a;
interface AA {
default void defaultM() {
System.out.println(m());
}
String m();
}

我有以下代码(在不同的包中(:

package pkg;
import java.util.Arrays;
import java.util.List;
import pkg.a.A;
public class Test {
public static void main(String[] args) {
List<A> list = Arrays.asList(() -> "imp1", () -> "imp2");
list.stream().forEach(a -> a.defaultM());
list.stream().forEach(A::defaultM);
}
}

运行上述代码时,list.stream().forEach(A::defaultM);会引发以下异常。为什么?为什么方法引用无法访问包私有接口中定义的方法,而 lambda 表达式可以访问?我在 Eclipse(版本:2018-12 (4.10.0((中使用 Java 版本 1.8.0_191 运行它。

imp1
imp2
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 pkg.Test.main(Test.java:14)
Caused by: java.lang.IllegalArgumentException: java.lang.IllegalAccessException: class is not public: pkg.a.AA.defaultM()void/invokeInterface, from pkg.Test
at java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1360)
at java.lang.invoke.AbstractValidatingLambdaMetafactory.<init>(AbstractValidatingLambdaMetafactory.java:131)
at java.lang.invoke.InnerClassLambdaMetafactory.<init>(InnerClassLambdaMetafactory.java:155)
at java.lang.invoke.LambdaMetafactory.metafactory(LambdaMetafactory.java:299)
at java.lang.invoke.CallSite.makeSite(CallSite.java:302)
... 3 more
Caused by: java.lang.IllegalAccessException: class is not public: pkg.a.AA.defaultM()void/invokeInterface, from pkg.Test
at java.lang.invoke.MemberName.makeAccessException(MemberName.java:850)
at java.lang.invoke.MethodHandles$Lookup.checkAccess(MethodHandles.java:1536)
at java.lang.invoke.MethodHandles$Lookup.revealDirect(MethodHandles.java:1357)
... 7 more

这是一个错误:

方法引用使用错误的限定类型。

对在包访问类中声明的方法的引用(通过 公共子类型(编译为 lambda 桥;中的限定类型 桥接方法是声明类,而不是引用的类。 这会导致非法访问错误。

在 Java 9 中修复。

这似乎是某些Java版本中的错误。

如果我使用 JDK 8 编译并运行它,我可以复制它,特别是:

TJ$ javac -version javac 1.8.0_74 TJ$ java -version Java 版本 "1.8.0_74" Java(TM( SE 运行时环境(内部版本 1.8.0_74-b02( Java HotSpot(TM( 64-bit Server VM(build 25.74-b02,混合模式(

...但不适用于 JDK 11 或 12,特别是:

TJ$ javac -version 爪哇 11.0.1 TJ$ java -version OpenJDK 版本 "11.0.1" 2018-10-16 OpenJDK 运行时环境 18.9(内部版本 11.0.1+13( OpenJDK 64 位服务器 VM 18.9(内部版本 11.0.1+13,混合模式(

TJ$ javac -version 爪哇 12.0.2 TJ$ java -version Java版本"12.0.2" 2019-07-16 Java(TM( SE 运行时环境(build 12.0.2+10( Java HotSpot(TM( 64-bit Server VM(build 12.0.2+10,混合模式,共享(

如果我使用 JDK8 编译但使用 JDK 12 的运行时运行它,我也可以复制它,这表明存在编译问题。

最新更新