首页 > 解决方案 > Java:从内部类访问受保护的字段

问题描述

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. 在单个包中声明,由不同的类加载器加载 - 不好。

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

标签: javaclassloaderinner-classesprotectedaccess-modifiers

解决方案


  • 相同的类加载器似乎正在工作
  • 我问对了吗?
  • 您是否有任何单元测试用例来重现您的问题?

家长班

package p1;

public class Parent {
    
    protected String p = "Value from Parent";
    
    public void test() {
        System.out.println(p);
    }

}

外层

package p1;

public class Outer extends Parent {

    class Inner {
        public void test() {
            Outer.this.p = "Value set from Inner";
            System.out.println(Outer.this.p);
        }
    }

    public void test() {
        new Inner().test();
    }
}

主班

package p1;

public class Main {

    public static void main(String[] args) {
        Parent p = new Parent();
        p.test();
        p = new Outer();
        p.test();
    }
}

输出

Value from Parent
Value set from Inner

推荐阅读