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

2022-09-04 22:28:23

我有这两个接口。一个是公共(A),另一个是包私有(AA)。 延伸。AAA

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);
    }
}

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

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

答案 1

这是一个错误:

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

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

在 Java 9 中已修复。


答案 2

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

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

tj$ javac -version
javac 1.8.0_74
tj$ java -version
java version "1.8.0_74"
Java(TM) SE Runtime Environment (build 1.8.0_74-b02)
Java HotSpot(TM) 64-Bit Server VM (build 25.74-b02, mixed mode)

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

tj$ javac -version
javac 11.0.1
tj$ java -version
openjdk version "11.0.1" 2018-10-16
OpenJDK Runtime Environment 18.9 (build 11.0.1+13)
OpenJDK 64-Bit Server VM 18.9 (build 11.0.1+13, mixed mode)

tj$ javac -version
javac 12.0.2
tj$ java -version
java version "12.0.2" 2019-07-16
Java(TM) SE Runtime Environment (build 12.0.2+10)
Java HotSpot(TM) 64-Bit Server VM (build 12.0.2+10, mixed mode, sharing)

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


推荐