class A { private int foo; void bar(B b) { b.foo = 42; } } class B extends A { }
This fails to compile with the error:
A.java:3: error: foo has private access in A void bar(B b) { b.foo = 42; } ^ 1 error
Adding a cast to the base class makes it work.
void bar(B b) { ((A) b).foo = 42; }
Can someone point me to an explanation about why the first snippet is illegal? What's the reason it's prohibited? Here's what the JLS says:
Otherwise, the member or constructor is declared
private
, and access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
As best I can tell, my code meets this wording. So is this a bug with the Java compiler, or is my interpretation of the JLS incorrect?
(Note: I'm not looking for workarounds, like making the variable protected
. I know how to work around this.)
A subclass does not inherit the private members of its parent class. However, if the superclass has public or protected methods for accessing its private fields, these can also be used by the subclass.
Subclasses inherit public methods from the superclass that they extend, but they cannot access the private instance variables of the superclass directly and must use the public accessor and mutator methods.
Private: The class members declared as private can be accessed only by the functions inside the class. They are not allowed to be accessed directly by any object or function outside the class. Only the member functions or the friend functions are allowed to access the private data members of a class.
Error message "has a private access in A" is a java bug for a very very long time.
JDK 1.1:
JDK-4096353 : JLS 6.6.1: When subclass references are used to access privates of superclasses
contains code snippet exactly conforms the question one
class X{ private static int i = 10; void f() { Y oy = new Y(); oy.i = 5; // Is this an error? Is i accessable through a reference to Y? } } class Y extends X {}
They tried to fix it and it leads to
JDK-4122297 : javac's error messages are not appropriate for a private field.
======TP1====== 1 class C extends S { 2 void f(){ 3 java.lang.System.out.println("foo"); 4 } 5 } 6 7 class S { 8 private int java; 9 } ====== % javac C.java C.java:3: Variable java in class S not accessible from class C. java.lang.System.out.println("foo"); ^ C.java:3: Attempt to reference field lang in a int. java.lang.System.out.println("foo"); ^ 2 errors ======
But by specification java
isn't inherited in C and this program should compile.
It fixed in 1.2, but appears in 1.3 again
JDK-4240480 : name00705.html: JLS6.3 private members should not be inherited from superclasses
JDK-4249653 : new javac assumes that private fields are inherited by a subclass
And when generics come
JDK-6246814 : Private member of type variable wrongly accesible
JDK-7022052 : Invalid compiler error on private method and generics
However, by the JLS this member simply doesn't exist in the inherited type.
JLS 8.2. Class Members
Members of a class that are declared private are not inherited by subclasses of that class.
So b.foo
is illegal because class B
has no field named foo
. It is no restriction, it is an absent field in B
.
Java has strong typing and we cannot access fields that do not exist in B
even if they exist in superclass A
.
Cast (A) b
is legal because B
is a subclass of A
.
A
has a field named foo
and we can access this private field because b(B b)
is a function in class A
even if b != this
due to
JLS 6.6.1. Determining Accessibility
Otherwise, if the member or constructor is declared private, then access is permitted if and only if it occurs within the body of the top level class (§7.6) that encloses the declaration of the member or constructor.
Also if we write
class A { private int foo; void baz(A b) { b.foo = 42; } } class B extends A { } class T { void x() { B b = new B(); b.baz(b); } }
It will compile because Java infer type arguments for polymorphic calls.
JLS 15.12.2.7. Inferring Type Arguments Based on Actual Arguments:
A supertype constraint T :> X implies that the solution is one of supertypes of X. Given several such constraints on T, we can intersect the sets of supertypes implied by each of the constraints, since the type parameter must be a member of all of them. We can then choose the most specific type that is in the intersection
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With