Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Why protected static fields are visible from different class in Java

Tags:

java

Here is the following code:

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

and

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

I cannot understand why static protected field is accessible though A in different package...

like image 845
YohanRoth Avatar asked Mar 01 '15 19:03

YohanRoth


2 Answers

Since the fact that a protected member is accessible from a subclass in any package is widely familiar, I am answering the flip side of your question: Why is the protected instance field not visible to the subclass?

As usual, the place to look for the authoritative answer is the Java Language Specification, in this case Section 6.6.2. I am quoting the example found there because it is much easier to follow than the legalese that precedes it.

TL;DR: The best way to think of it is this: protected is an inherited class internal. From the perspective of all its subclasses, A.var2 behaves like a private member of each subclass individually and not a member of the superclass. And all this is in place because protected is intended to be used in a class designed for extension, so that the subclasses can access those parts which are considered public API for the extending class, but not for the client of the class.

To complete your series of examples I submit two more:

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

Food for thought :)

Example 6.6.2-1. Access to protected Fields, Methods, and Constructors

Consider this example, where the points package declares:

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

and the threePoint package declares:

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

A compile-time error occurs in the method delta here: it cannot access the protected members x and y of its parameter p, because while Point3d (the class in which the references to fields x and y occur) is a subclass of Point (the class in which x and y are declared), it is not involved in the implementation of a Point (the type of the parameter p). The method delta3d can access the protected members of its parameter q, because the class Point3d is a subclass of Point and is involved in the implementation of a Point3d.

The method delta could try to cast (§5.5, §15.16) its parameter to be a Point3d, but this cast would fail, causing an exception, if the class of p at run time were not Point3d.

A compile-time error also occurs in the method warp: it cannot access the protected member z of its parameter a, because while the class Point (the class in which the reference to field z occurs) is involved in the implementation of a Point3d (the type of the parameter a), it is not a subclass of Point3d (the class in which z is declared).

like image 160
Marko Topolnik Avatar answered Oct 13 '22 19:10

Marko Topolnik


Protected means that all subclasses get access to it, and all other classes in the same package. In this case, C is a subclass of A and thus get access to the fields, regardless of the package it is in.

The subclass C can't access a protected field of any other A object though, only of C objects. So it can access this.var2, and if you change A test; into C test; (and the initialization into test = new C();, you are able to access it.

like image 40
mstorsjo Avatar answered Oct 13 '22 20:10

mstorsjo