Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Can't access private variable from own class via subclass instance

Tags:

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.)

like image 226
John Kugelman Avatar asked Feb 07 '15 00:02

John Kugelman


People also ask

Can you access private variables from subclass?

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.

Does a subclass have access to private instance variables of its superclass?

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.

Can an instance of a class access private members?

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.


1 Answers

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

like image 146
Nikolay Avatar answered Sep 21 '22 06:09

Nikolay