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

时间:2015-03-01 19:32:40

标签: java

以下是代码:

package ab:
public class A {
    protected static int var = 10;
    protected int var2 = 20;
}

    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
        }
    }

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

2 个答案:

答案 0 :(得分:4)

由于可以从任何包中的子类访问protected成员这一事实已广为人知,因此我回答了问题的另一面:为什么protected 实例字段对子类可见?

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

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

要完成一系列示例,我再提交两个:

System.out.println(this.var2);      // works---intended use of protected
System.out.println(((A)this).var2); // fails same as your test.var2

思考的食物:)

  

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

     

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

package points;
public class Point {
  protected int x, y;
  void warp(threePoint.Point3d a) {
    if (a.z > 0)  // compile-time error: cannot access a.z
      a.delta(this);
  }
}
     

threePoint包声明:

package threePoint;
import points.Point;
public class Point3d extends Point {
  protected int z;
  public void delta(Point p) {
    p.x += this.x;  // compile-time error: cannot access p.x
    p.y += this.y;  // compile-time error: cannot access p.y
  }
  public void delta3d(Point3d q) {
    q.x += this.x;
    q.y += this.y;
    q.z += this.z;
  }
}
     

此处的方法delta发生编译时错误:它无法访问其参数x的受保护成员yp,因为{{1} (Point3dx字段的引用所在的类)是y的子类(Pointx所在的类声明),它不参与y(参数类型Point)的实现。方法p可以访问其参数delta3d的受保护成员,因为类qPoint3d的子类,并且参与Point的实现}。

     

方法delta可以尝试将其参数(§5.5,§15.16)转换为Point3d,但是如果运行时的p类不是{{{},则此转换将失败,从而导致异常。 1}}。

     

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

答案 1 :(得分:2)

受保护意味着所有子类都可以访问它,以及同一个包中的所有其他类。在这种情况下,CA的子类,因此无论其所在的包是什么,都可以访问这些字段。

子类C无法访问任何其他A对象的受保护字段,但只能访问C个对象。因此,它可以访问this.var2,如果您将A test;更改为C test;(并初始化为test = new C();,则可以访问它。