Java lang 非法访问通过 HashBasedTable 累加器收集 Guava Immutable Table
Java lang IllegalAccess on collecting Guava Immutable Table via HashBasedTable accumulator
执行以下代码时出错,
Caused by: java.lang.IllegalAccessError: tried to access class
com.google.common.collect.AbstractTable from class
ImmutableTable.copyOf(listItemsToProcess.parallelStream()
.map(item ->
ProcessorInstanceProvider.getInstance()
.buildImmutableTable(item))
.collect(() -> HashBasedTable.create(),
HashBasedTable::putAll,
HashBasedTable<Integer, String,
Boolean>::putAll)
);
Error in coming on - HashBasedTable::putAll Using Oracle's 1.8 jre
AbstractTable
是在 Guava 版本 15 中引入的。看看你的类路径配置;您可能在运行时使用了较早的库版本。
有趣的是,我用 Lambda 表达式替换了方法引用并且它起作用了。
ImmutableTable.copyOf(itemList.parallelStream()
.map(item ->
ProcessorInstanceProvider.get()
.buildImmutableTable(item))
.collect(() -> HashBasedTable.create(),
(a, b) -> a.putAll(b),
(a, b) -> a.putAll(b))
);
这是一个编译器错误,相关报告是
- JDK-8152643:“Javac 编译的方法引用允许导致 IllegalAccessError”
- JDK-8059632:“方法引用编译使用了不正确的限定类型”
请注意,第一份报告的状态为“已在 8u102 中修复”,因此下载 JDK8u102 可以解决问题。当然,当使用 javac
以外的编译器时,例如ECJ,你必须确保编译器也是最新的。
无论哪种情况,您都必须重新编译源代码,因为这是编译器问题。但是,编译后的代码甚至可以与较旧的 JRE 一起使用。
为了解释这个问题,通常情况下,调用应该使用接收器的编译时类型(或 static
方法中的显式类型)编码到字节码中,而不考虑声明类型的实际方法实现。因此,如果您有一个 public
class A
从非 public
class [=17] 继承 public
方法 foo
=],对 A.foo
的调用应编码为 A.foo
而不是 B.foo
。对于普通调用,编译器以这种方式工作,但对于方法引用,javac
(以及 afaik 也是旧版本的 ECJ)未能正确地做到这一点。因此,当遇到 class 试图直接访问 B.foo
而无法访问 B
时,将抛出 IllegalAccessError
。
它在使用 lambda 表达式时有效,因为那时,调用被编译成普通的调用指令,编译器在合成方法中正常工作,并且在构造运行时功能接口的实例。由于合成方法在同一 class 中,因此始终可以访问。
执行以下代码时出错,
Caused by: java.lang.IllegalAccessError: tried to access class com.google.common.collect.AbstractTable from class
ImmutableTable.copyOf(listItemsToProcess.parallelStream()
.map(item ->
ProcessorInstanceProvider.getInstance()
.buildImmutableTable(item))
.collect(() -> HashBasedTable.create(),
HashBasedTable::putAll,
HashBasedTable<Integer, String,
Boolean>::putAll)
);
Error in coming on - HashBasedTable::putAll Using Oracle's 1.8 jre
AbstractTable
是在 Guava 版本 15 中引入的。看看你的类路径配置;您可能在运行时使用了较早的库版本。
有趣的是,我用 Lambda 表达式替换了方法引用并且它起作用了。
ImmutableTable.copyOf(itemList.parallelStream()
.map(item ->
ProcessorInstanceProvider.get()
.buildImmutableTable(item))
.collect(() -> HashBasedTable.create(),
(a, b) -> a.putAll(b),
(a, b) -> a.putAll(b))
);
这是一个编译器错误,相关报告是
- JDK-8152643:“Javac 编译的方法引用允许导致 IllegalAccessError”
- JDK-8059632:“方法引用编译使用了不正确的限定类型”
请注意,第一份报告的状态为“已在 8u102 中修复”,因此下载 JDK8u102 可以解决问题。当然,当使用 javac
以外的编译器时,例如ECJ,你必须确保编译器也是最新的。
无论哪种情况,您都必须重新编译源代码,因为这是编译器问题。但是,编译后的代码甚至可以与较旧的 JRE 一起使用。
为了解释这个问题,通常情况下,调用应该使用接收器的编译时类型(或 static
方法中的显式类型)编码到字节码中,而不考虑声明类型的实际方法实现。因此,如果您有一个 public
class A
从非 public
class [=17] 继承 public
方法 foo
=],对 A.foo
的调用应编码为 A.foo
而不是 B.foo
。对于普通调用,编译器以这种方式工作,但对于方法引用,javac
(以及 afaik 也是旧版本的 ECJ)未能正确地做到这一点。因此,当遇到 class 试图直接访问 B.foo
而无法访问 B
时,将抛出 IllegalAccessError
。
它在使用 lambda 表达式时有效,因为那时,调用被编译成普通的调用指令,编译器在合成方法中正常工作,并且在构造运行时功能接口的实例。由于合成方法在同一 class 中,因此始终可以访问。