Java:从内部类访问受保护的字段

Tim*_*dik 16 java protected access-modifiers classloader inner-classes

最近,当我java.lang.IllegalAccessError尝试从内部类访问由不同类加载器加载的外部父类中声明的受保护字段时,我遇到了运行时错误的问题。简要地:

  1. Parent有受保护的字段p
  2. Outer扩展Parent
  3. ClassInner是在 class 中定义的内部类Outer
  4. Inner类里面有一个代码:Outer.this.p.
  5. 所有类都在同一个包中声明。

通常它的编译和运行正常,直到ParentOuter类是由不同的类加载器加载。在这种情况下,我们java.lang.IllegalAccessError在尝试Outer.this.pInner. 我发现了一个旧的错误报告(这似乎是一个功能)描述了这种行为:

https://bugs.java.com/bugdatabase/view_bug.do?bug_id=6258289

但分辨率对我来说听起来自相矛盾:

关键是在失败的情况下,内部类不在同一个包中(并且不是 ConcreteCommand/AbstractCommand 的子类)。这只是违反了受保护类的 Java 规范。

听起来是对的。但是,如果我们在不同的包中声明ParentOuter类,但使用单个类加载器加载(只需创建没有任何 jar 加载的示例控制台应用程序),我们就不会收到任何错误。因此,从技术上讲,它违反了受保护类的 Java 规范,但由于我们使用了内部类,因此它可以工作。

因此,对于“不同的包”的两种情况,我们有不同的行为。

  1. 在不同的包中声明,由单个类加载器加载 - 好的。
  2. 在单个包中声明,由不同的类加载器加载 - 不正常。

有人可以清楚地解释内部类如何访问父类的字段以及为什么它在两种情况下的工作方式不同吗?

Dha*_*l D 0

在不同的包中声明,由单个类加载器加载 - OK

“受保护”访问考虑了类之间的父子关系,允许子类访问父类的“受保护”成员,即使它们位于不同的包中。所以,我认为这是符合预期的。

在单个包中声明,由不同的类加载器加载 - 不行

这与运行时包有关。检查这个。现在我们知道 Parent 与 Outer 和 Inner 位于不同的运行时包中,因为它是通过两个不同的类加载器加载的。同时,我们还必须记住,Outer 是 Parent 的“子级”,但 Inner 不是。Inner 与 Parent 没有“Is-a”关系。

综上所述:由于 Parent 位于不同的运行时包中,Inner 无法访问 Parent 的“受保护”成员,因为 Inner 不是 Parent 的子级。