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

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

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

通常,它会编译并正常运行,直到ParentOuter类由不同的类加载器加载为止。在这种情况下,尝试从java.lang.IllegalaccessError访问Outer.this.p时得到Inner。 我发现一个旧的错误报告(似乎是一个功能)描述了此行为:

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

但是分辨率听起来与我矛盾:

关键是,在失败的情况下,内部类不是同一类 包(也不是ConcreteCommand / AbstractCommand的子类)。 这完全违反了Java保护规范 课程。

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

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

  1. 声明为不同的包,由单个类加载器加载-确定。
  2. 声明为单个包,由不同的类加载器加载-不好。

有人可以对内部类如何访问父级字段进行解释,以及为什么在两种情况下内部类的工作方式不同吗?

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

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

父类

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
,

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

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

声明为单个包,由不同的类加载器加载-不好

这与运行时包有关。选中this。 现在我们知道,由于通过两个不同的类加载器进行加载,因此Parent与外部和内部位于不同的运行时程序包中。同时,我们还必须记住,外部是父级的“孩子”,而内部不是。内部与父母之间没有“ Is-a”关系。

将所有内容放在一起: 由于Parent处于不同的运行时程序包中,因此Inner不能访问Parent的“受保护”成员,因为Inner不是Parent的子代。

本文链接:https://www.f2er.com/1946714.html

大家都在问