为什么此方法引用在运行时失败,但没有相应的lambda调用失败? [英] Why is this method reference failing at runtime but not the corresponding lambda call?

查看:85
本文介绍了为什么此方法引用在运行时失败,但没有相应的lambda调用失败?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有这两个界面.一个是公共(A),另一个是包私有(AA). A 扩展了 AA .

I have these two interfaces. One is public (A), the other one is package private (AA). A extends AA.

package pkg.a;

@FunctionalInterface
public interface A extends AA {

}

.

package pkg.a;

interface AA {

    default void defaultM() {
        System.out.println(m());
    }

    String m();
}

我有此代码(在其他包装中):

I have this code (in a different package):

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表达式可以,但是方法引用为什么不能访问package-private接口中定义的方法?我正在Java版本1.8.0_191的Eclipse(版本:2018-12(4.10.0))中运行它.

When running the above code the list.stream().forEach(A::defaultM); throws the below exception. Why? Why can't the method reference access the methods defined in the package-private interface while the lambda expression can? I'm running this in Eclipse (Version: 2018-12 (4.10.0)) with Java version 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

推荐答案

这是一个错误:

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

对在包访问类中声明的方法的引用(通过public subtype)编译为lambda桥;符合条件的类型bridge方法是声明类,而不是引用的类.这会导致一个IllegalAccessError.

A reference to a method declared in a package-access class (via a public subtype) compiles to a lambda bridge; the qualifying type in the bridge method is the declaring class, not the referenced class. This leads to an IllegalAccessError.

已在Java 9中修复.

Fixed in Java 9.

这篇关于为什么此方法引用在运行时失败,但没有相应的lambda调用失败?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆