Java 当我试图调用一个超级类时,为什么会出现BootstrapMethodError';使用来自内部类的方法引用的受保护方法?

Java 当我试图调用一个超级类时,为什么会出现BootstrapMethodError';使用来自内部类的方法引用的受保护方法?,java,java-8,Java,Java 8,在Java 8中,给定包a中的一个超类super和包b中的一个子类sub,谁有一个内部类SubInner: //Super.java a包; 公共抽象类超级{ 私人长期价值; 受保护的最终无效设置值(长值){ 这个值=值; } } //Sub.java b包; 公共类子类扩展超级{ 公共图书馆{ 新建子内部().foo(); } 私有类次内部{ void foo(){ 可选.of(1L).ifPresent(Sub.this::setValue);//将在运行时抛出IllegalAccessEr

在Java 8中,给定包
a
中的一个超类
super
和包
b
中的一个子类
sub
,谁有一个内部类
SubInner

//Super.java
a包;
公共抽象类超级{
私人长期价值;
受保护的最终无效设置值(长值){
这个值=值;
}
}
//Sub.java
b包;
公共类子类扩展超级{
公共图书馆{
新建子内部().foo();
}
私有类次内部{
void foo(){
可选.of(1L).ifPresent(Sub.this::setValue);//将在运行时抛出IllegalAccessError。
可选.of(1L).ifPresent(t->setValue(t));//但是,lambda可以工作。
setValue(1L);//也可以工作。
}
}
}
我的问题是,为什么在这种情况下方法引用无法工作,而普通方法调用可以访问超类方法
setValue

另外,如果我尝试执行
Sub.super::setValue
,代码不会编译,错误似乎与运行时错误一致:
setValue
a.super
中具有受保护的访问权限

Exception in thread "main" java.lang.BootstrapMethodError: java.lang.IllegalAccessError: tried to access method a.Super.setValue(J)V from class b.Sub$SubInner
    at b.Sub$SubInner.foo(Sub.java:14)
    at b.Sub.foo(Sub.java:10)
    at b.Sub.main(Sub.java:22)
Caused by: java.lang.IllegalAccessError: tried to access method a.Super.setValue(J)V from class b.Sub$SubInner
    at java.lang.invoke.MethodHandleNatives.resolve(Native Method)
    at java.lang.invoke.MemberName$Factory.resolve(MemberName.java:975)
    at java.lang.invoke.MemberName$Factory.resolveOrFail(MemberName.java:1000)
    at java.lang.invoke.MethodHandles$Lookup.resolveOrFail(MethodHandles.java:1394)
    at java.lang.invoke.MethodHandles$Lookup.linkMethodHandleConstant(MethodHandles.java:1750)
    at java.lang.invoke.MethodHandleNatives.linkMethodHandleConstant(MethodHandleNatives.java:477)
    ... 3 more
看起来很像,这是固定的


我在本地没有java-9来确认它确实是在java-9中修复的,正如bug所述;但在java-11和java-12下运行良好。
javac/java
处理lambda/方法引用的方式出现异常已经不是第一次了;通常,lambda是方法引用的变通方法,反之亦然

是的,这就把事情弄清楚了。还向问题添加了堆栈跟踪。我可以确认它在使用JDK9编译时是有效的。当使用
--release8
时,编译后的代码甚至可以与Java8一起使用。这也适用于
Sub.super::setValue
,它甚至不在JDK 8下编译,但在使用JDK 9或更新版本
--release 8
编译时将运行。相比之下,使用JDK 8编译的代码在运行时的所有版本下都会失败,不过JDK 11将提供一个简化的堆栈跟踪,在
b.Sub$SubInner.foo(Sub.java:14)
处显示
IllegalAccessError