【发布时间】:2020-11-02 13:40:19
【问题描述】:
最近,当我尝试从内部类访问由不同类加载器加载的外部父类中声明的受保护字段时,我遇到了运行时错误java.lang.IllegalAccessError 的问题。简要说明:
- 类
Parent具有受保护字段p。 -
Outer类扩展Parent。 -
Inner类是在Outer类中定义的内部类。 - 在
Inner类中有一个代码:Outer.this.p。 - 所有类都在同一个包中声明。
通常在Parent 和Outer 类被不同的类加载器加载之前,它会被编译并运行良好。在这种情况下,当我们尝试从Inner 访问Outer.this.p 时,我们会得到java.lang.IllegalAccessError。
我发现了一个描述这种行为的旧错误报告(这似乎是一个特性):
https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289
但分辨率听起来与我矛盾:
关键是在失败的情况下内部类不在同一个 包(不是子类)ConcreteCommand/AbstractCommand。 这简直违反了受保护的 Java 规范 类。
听起来很正确。但是,如果我们在不同的包中声明 Parent 和 Outer 类但使用单个类加载器加载(只需创建没有任何 jar 加载的示例控制台应用程序),我们不会收到任何错误。所以从技术上讲,这违反了受保护类的 Java 规范,但由于我们使用了内部类,所以它可以工作。
因此,对于两种“不同的包”,我们有不同的行为。
- 在不同的包中声明,由单个类加载器加载 - 好的。
- 在单个包中声明,由不同的类加载器加载 - 不正常。
有人可以清楚地解释内部类如何访问父级的字段以及为什么它在两种情况下的工作方式不同吗?
【问题讨论】:
-
如何重现类被不同类加载器加载的场景?
标签: java classloader inner-classes protected access-modifiers