Java : Protected access restriction for subclass on superclass object
Quoting from book The Java Programming Language 3 ed. by Gosling et all - page 81 sec 3.5
"What Protected really means" - .. beyond being accessible within the class itself and to code within the same package , a protected member can also be accessed from a class through object references that are of atleast the same type as the class - that is references of class's type or one of its subclass
Actually you don't need two levels of inheritance and the code below would lead to the same behaviour:
public class B extends A{
public void accessField() {
A ancient = new A();
ancient.a = 2; //A - That wouldn't work.
a = 2; //B - That works.
}
}
The reason why a = 2
works is JLS 6.2.2.1:
Let C be the class in which a protected member is declared. Access is permitted only within the body of a subclass S of C.
Note that it does not say direct subclass, but only subclass. So a = 2
works within the B
class or the C
class.
On the other hand, ancient.a = 2;
is covered by the next bullet point in the same section:
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.
In your case, Q.Id
is ancient.a
=> it would only be accessible if the type of ancient
was B
or a subclass of B
. So for example, this would compile:
public class B extends A{
public void accessField() {
C ancient = new C();
ancient.a = 2; //A - That wouldn't work.
}
}
Protected members can only be accessed outside of the same package if it's via inheritance - i.e. within the hierarchy.
So when you're creating another instance of A from a different package, that's not an inheritance relationship and it thus fails.
As always, this is covered in the JLS, 6.6.2:
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.