Why a protected member of a superclass can't be accessed from a subclass by using
a superclass' reference?
Keywords "public", "protected" and "private" are exclusively relevant for
access control. They enable the compiler to decide wether a statement
referencing a class member is allowed or not.
The protected modifier specifies that the member can only be accessed within its
own package and, in addition, by a subclass of its class in another package.
But, look the following codes (has two packages) from JLS:
package points;
public class Point {
protected int x, y;
}
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;
}
}
Point3d is a subclass of Point, so why can't it always
access protected members in its superclass? Form JLS:
6.6.2 Details on protected Access
A protected member or constructor of an object may be accessed from outside the
package in which it is declared only by code that is responsible for the
implementation of that object.
6.6.2.1 Access to a protected Member
Let C be the class in which a protected member m is declared. Access is
permitted only within the body of a subclass S of C. In addition, if Id denotes
an instance field or instance method, then:
-
If the access is by a qualified name Q.Id, where Q is an ExpressionName, then
the access is permitted if and only if the type of the expression Q is S or a
subclass of S.
-
If the access is by a field access expression E.Id, where E is a Primary
expression, or by a method invocation expression E.Id(. . .), where E is a
Primary expression, then the access is permitted if and only if the type of E
is S or a subclass of S.
6.6.2.2 Qualified Access to a protected Constructor
Let C be the class in which a protected constructor is declared and let S be
the innermost class in whose declaration the use of the protected constructor
occurs. Then:
-
If the access is by a superclass constructor invocation super(. . .) or by a
qualified superclass constructor invocation of the form E.super(. . .), where E
is a Primary expression, then the access is permitted.
-
If the access is by an anonymous class instance creation expression of the form
new C(. . .){...} or by a qualified class instance creation expression of the
form E.new C(. . .){...}, where E is a Primary expression, then the access is
permitted.
-
Otherwise, if the access is by a simple class instance creation expression of
the form new C(. . .) or by a qualified class instance creation expression of
the form E.new C(. . .), where E is a Primary expression, then the access is
not permitted. A protected constructor can be accessed by a class instance
creation expression (that does not declare an anonymous class) only from within
the package in which it is defined.
A method in subclass has access to the protected instance members/methods of its
superclass, but only if it accesses them via a subclass object. Let's go
back to the above code. 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 its parameter p to
be a Point3d, but this cast would fail, causing an exception, if the class of
p at run time were not Point3d.