Just found this construction does not compile:
class A {
private int data;
public static int process(B b) {
return b.data;// error here: 'data has private access in A'
}
}
class B extends A {}
Of course this problem can be solved easily manually (cast b to A, make field protected, etc.). But the question is, why java does not allow such construction? I thought that compiler must know that B is a subclass of A, so methods of A must have access to A's private fields.
The only possible problem I can think of is if B has its own 'data' field, compiler must not know which field we want to access, but that's what inheritance is for, right?
Well, the compiler doesn't allow it because the language specification doesn't allow it. JLS section 8.3 (field declarations) specifies (emphasis mine):
A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class.
A private field of a superclass might be accessible to a subclass - for example, if both classes are members of the same class. Nevertheless, a private field is never inherited by a subclass.
So looking up the field as a member of the subclass (6.5.6.2) must fail - the compiler is being slightly helpful in explaining why it's failed rather than just saying the member doesn't exist, but I believe that in a pure sense, the look up should just say "Type B doesn't have a member called data
" rather than complaining that it's inaccessible.
As for why the language was designed that way - I'm not sure. The equivalent code in C# is fine, and it makes perfect sense to me. For example, in the C# 5 specification, section 3.4:
When a type inherits from a base class, all members of the base class, except instance constructors, destructors and static constructors, become members of the derived type. The declared accessibility of a base class member does not control whether the member is inherited—inheritance extends to any member that isn't an instance constructor, static constructor, or destructor. However, an inherited member may not be accessible in a derived type, either because of its declared accessibility (§3.5.1) or because it is hidden by a declaration in the type itself (§3.7.1.2).