IllegalAccessError when using a public method reference of a package-private class through a public subclass from another package,怎么解决?

内容来源于 Stack Overflow,并遵循CC BY-SA 3.0许可协议进行翻译与使用

  • 回答 (2)
  • 关注 (0)
  • 查看 (29)

在Tomcat 8上部署了我的Java 8 Web应用程序之后,两个类定义如下:

foo.java

package package1;

abstract class Foo {

    public String getFoo() {
        return "foo";
    }

}

bar.java

package package1;

public class Bar extends Foo {

    public String getBar() {
        return "bar";
    }

}

在我的Webapp中,有一段代码可以:

package package2;

public class Something {

    ...

    Bar[] sortedBars = bars.stream()
                           .sorted(Comparator.comparing(Bar::getBar)
                                             .thenComparing(Bar::getFoo))
                           .toArray(Bar[]::new);

    ...

}

当它被执行时,我得到:

java.lang.IllegalAccessError: tried to access class package1.Foo from class package2.Something

我能够避免错误的两种方式:

  1. 将foo类改为公共类,而不是包私有;
  2. 将某某类的包更改为“Package 1”(即与foo和Bar类完全相同,但在webapp中定义的对象类在物理上不同);

结果是:

WebappClassLoader
context: my-web-app
delegate: false
----------> Parent Classloader:
java.net.URLClassLoader@681a9515

用这个简单的POM:

<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
    xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
    <modelVersion>4.0.0</modelVersion>
    <groupId>my.test</groupId>
    <artifactId>commons</artifactId>
    <version>0.0.1-SNAPSHOT</version>

    <properties>
        <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding>
        <maven.compiler.source>1.8</maven.compiler.source>
        <maven.compiler.target>1.8</maven.compiler.target>
    </properties>

</project>
  1. 如果我执行“MVN干净包”(作为Eclipse运行配置),并在Eclipse内部运行主程序,我就得到了美妙的IllegalAccessError(酷!);
  2. 如果我执行Maven->Update项目...并在Eclipse中运行主程序,我不会收到任何错误。

然后,我进一步简化了某某类,并发现了一些有趣的东西:

package package2;

import java.util.stream.Stream;
import package1.Bar;

public class Something {

    public static void main(String[] args) {

        System.out.println(new Bar().getFoo());
        // "foo"

        Stream.of(new Bar()).map(Bar::getFoo).forEach(System.out::println);
        // IllegalAccessError

    }

}

提问于
用户回答回答于

IF包Commons.jar和罐子包装2由另一个类加载器加载,则不同。还有一个解决方案:重写Ba类中的getfoo方法。

用户回答回答于

只需从下面的配置切换:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
    </configuration>
</plugin>

然后:

<plugin>
    <groupId>org.apache.maven.plugins</groupId>
    <artifactId>maven-compiler-plugin</artifactId>
    <version>3.5.1</version>
    <configuration>
        <source>1.8</source>
        <target>1.8</target>
        <compilerId>eclipse</compilerId>
    </configuration>
    <dependencies>
        <dependency>
            <groupId>org.codehaus.plexus</groupId>
            <artifactId>plexus-compiler-eclipse</artifactId>
            <version>2.7</version>
        </dependency>
    </dependencies>
</plugin>

扫码关注云+社区