Java lang IllegalAccess通过HashBasedTable累加器收集Guava不可变表

sid*_*dss 1 java guava java-8 collectors

执行下面的代码时出错,

引起:java.lang.IllegalAccessError:试图从类访问com.google.common.collect.AbstractTable类

 ImmutableTable.copyOf(listItemsToProcess.parallelStream()
                    .map(item ->
                            ProcessorInstanceProvider.getInstance()
                            .buildImmutableTable(item))
                    .collect(() -> HashBasedTable.create(),
                            HashBasedTable::putAll,

                            HashBasedTable<Integer, String,    
                            Boolean>::putAll)
                    );
Run Code Online (Sandbox Code Playgroud)

出现错误 - HashBasedTable :: putAll使用Oracle的1.8 jre

Hol*_*ger 5

这是编译器错误,相关报告是

  • JDK-8152643:"Javac编译方法引用,允许导致IllegalAccessError"
  • JDK-8059632:"方法引用编译使用不正确的限定类型"

请注意,第一个报告的状态为"已在8u102中修复",因此下载JDK8u102可以解决此问题.当然,当使用除javacECJ 之外的编译器时,您必须确保该编译器也是最新的.

在任何一种情况下,您都必须重新编译源代码,因为它是编译器问题.但是,编译后的代码甚至可以与较旧的JRE一起使用.


为了解释这个问题,通常,static无论实际方法实现的声明类型如何,都应使用接收器的编译时类型(或方法中的显式类型)将调用编码到字节代码中.因此,如果您有一个从非public类A继承该public方法foo的public类B,则A.foo应该将调用编码为A.foo而不是B.foo.对于普通的调用,编译器以这种方式工作,但是对于方法引用,javac(并且afaik也是旧版本的ECJ)无法正确执行.因此,当遇到一个试图B.foo直接访问而无法访问的类时B,IllegalAccessError会抛出一个.

它在使用lambda表达式时起作用,然后,将调用编译成普通的调用指令,编译器在合成方法中正常工作,并在构造函数接口的实例时使用对该合成方法的引用在运行时.由于合成方法在同一个类中,因此总是可以访问.