为什么受保护的静态字段在Java中的不同类中是可见的

Yoh*_*oth 5 java

这是以下代码:

package ab:
public class A {
    protected static int var = 10;
    protected int var2 = 20;
}
Run Code Online (Sandbox Code Playgroud)

    package cd;
    public class C extends A {
        A test;

        public C(){
            test = new A();
        }

        void printValues(){
            System.out.println(A.var); //this is perfectly visible
            System.out.println(test.var2); // here I get error saying var2 is not visible
        }
    }
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么静态保护字段可通过A在不同的包中访问...

Mar*_*nik 4

由于可以从任何包中的子类访问成员这一事实protected是众所周知的,因此我正在回答您问题的另一面:为什么protected 实例字段对子类不可见?

\n\n

与往常一样,寻找权威答案的地方是 Java 语言规范,在本例中是第 6.6.2 节。我引用那里找到的例子是因为它比前面的法律术语更容易理解。

\n\n

TL;DR:最好的思考方式是:protected是一个继承的类内部。从其所有子类的角度来看,A.var2其行为就像每个子类私有成员,而不是超类的成员。所有这些都已到位,因为旨在用于为扩展而设计的类中,以便子类可以访问那些被视为扩展类的公共 API 的部分,但不能访问该类的客户端。protected

\n\n

为了完成您的一系列示例,我还提交了两个示例:

\n\n
System.out.println(this.var2);      // works---intended use of protected\nSystem.out.println(((A)this).var2); // fails same as your test.var2\n
Run Code Online (Sandbox Code Playgroud)\n\n

值得深思:)

\n\n
\n

示例 6.6.2-1。访问受保护的字段、方法和构造函数

\n\n

考虑这个例子,其中points包声明:

\n\n
package points;\npublic class Point {\n  protected int x, y;\n  void warp(threePoint.Point3d a) {\n    if (a.z > 0)  // compile-time error: cannot access a.z\n      a.delta(this);\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

并且threePoint包声明:

\n\n
package threePoint;\nimport points.Point;\npublic class Point3d extends Point {\n  protected int z;\n  public void delta(Point p) {\n    p.x += this.x;  // compile-time error: cannot access p.x\n    p.y += this.y;  // compile-time error: cannot access p.y\n  }\n  public void delta3d(Point3d q) {\n    q.x += this.x;\n    q.y += this.y;\n    q.z += this.z;\n  }\n}\n
Run Code Online (Sandbox Code Playgroud)\n\n

这里的方法发生了编译时错误delta:它无法访问其参数的受保护成员x和,因为 while (对字段和进行引用的类)是(在其中声明和的类)的子类,它不参与a (参数的类型)的实现。该方法可以访问其参数的受保护成员,因为该类是 a 的子类并且参与 a 的实现。ypPoint3dxyPointxyPointpdelta3dqPoint3dPointPoint3d

\n\n

方法 delta 可以尝试将 (\xc2\xa75.5, \xc2\xa715.16) 其参数转换为 a Point3d,但如果 p 在运行时的类不是 ,则此转换将失败,从而导致异常Point3d

\n\n

方法中也会出现编译时错误:它无法访问其参数的warp受保护成员,因为虽然类(发生对字段的引用的类)参与了a (参数的类型)的实现,它不是(在其中声明的类)的子类。zaPointzPoint3daPoint3dz

\n
\n