了解 Java 的受保护修饰符

我在 package1 中有一个名为 A 的类,在 package2 中有另一个名为 C 的类。C 类扩展了类 A。

A 有一个实例变量,其声明如下:

protected int protectedInt = 1;

下面是类 A 的代码

package package1;

public class A {
    
    public int publicInt = 1;
    private int privateInt = 1;
    int defaultInt = 1;
    protected int protectedInt = 1;

}

下面是类 C 的代码:

package package2;
import package1.A;

public class C extends A{

    public void go(){
        //remember the import statement
        A a = new A();
        System.out.println(a.publicInt);
        System.out.println(a.protectedInt);
        
    }
}

Eclipse 在中的最后一行加了下划线,并说“A.protectedInt”不可见。这似乎与“受保护”关键字的定义相冲突,因为Oracle文档说:C.go()

受保护的修饰符指定只能在其自己的包中访问成员(与包专用一样),此外,还可以由另一个包中其类的子类访问。

这是怎么回事?


答案 1

这是怎么回事?

您误解了 .可以从 内部访问 中声明的受保护成员,但只能访问 的实例或子类。有关受保护访问的详细信息,请参阅 JLS 的第 6.6.2 节。特别:protectedACCC

设 C 为声明受保护成员的类。只允许在 C 的子类 S 的主体内访问。

此外,如果 Id 表示实例字段或实例方法,则:

  • [...]

  • 如果访问是通过字段访问表达式 E.Id(其中 E 是主表达式)或通过方法调用表达式 E.Id(. . .),其中 E 是主表达式,则当且仅当 E 的类型是 S 或 S 的子类时,才允许访问。

(强调我的。

所以这个代码会很好:

C c = new C();
System.out.println(c.publicInt);
System.out.println(c.protectedInt);

答案 2

由于是继承,可以直接使用如下变量CACprotectedA

public class C extends A{

    public void go(){

       System.out.println(protectedInt);

    }
}

根据您的代码,您正在创建一个实例并通过该实例访问变量,这违反了java的规则 - 受保护的变量在包外部不可见Aprotected