Reputation: 698
I have code that looks like this:
public class A<T extends A> {
private T one() { return (T) this;}
protected T two() { return (T) this;}
protected void three() { two().one(); }
}
And IntelliJ tells me that "one() has private access in A", but hey, why can't I call the private member of the same class?
Upvotes: 24
Views: 4640
Reputation: 124225
private
members can be accessed only within class in which they ware declared. So if you have class
class X{
private int field = 1;
private void method(){}
void foo(X x){
x.field = 2;
x.method(); // this is OK, because we are accessing members from instance of X
// via reference of class X (which is same class as this one)
}
void bar(Y y){// = lets assume that Y extends X
y.field = 3;
y.method(); // ERROR: we can't access `method()`
}
}
As you see we are not allowed to access private member from derived class even if we are inside class in which this member was declared.
Possible reason for this is that private members are not inherited to interface of derived class (which is kind of whole purpose of private
visibility modifier). Because of that in such classes it is possible to redeclare these members any way author wants, for instance someone could create class like this one:
class Y extends X{
private String field = "foo";
private String method(){
return "bar";
}
}
So as you see it is possible that by calling y.method()
you are trying to access method
declared in Y
class, but you don't have access to it from X
class (due to encapsulation). And this is scenario compiler assumes because fields and private methods are not polymorphic.
To avoid this confusion you will need to explicitly state that you want to invoke private member from current class X by using casting
void bar(Y y){
((X)y).method();
}
Same thing happens for <T extends A>
. Since T
can be any subclass of A
compiler will not allow access to its private members. So you will need to cast it back to A
class A<T extends A> {
private T one() { return (T) this;}
protected T two() { return (T) this;}
protected void three() { ((A)two()).one(); }
}
Upvotes: 18
Reputation: 72844
This compiler error was introduced in Java 7 as per http://www.oracle.com/technetwork/java/javase/compatibility-417013.html:
Description: In JDK 5.0 and JDK 6, javac erroneously allowed access to private members of type-variables. This is wrong, as the JLS, Java SE 7 Edition, section 4.4, states that the members of a type-variable are the members of an intersection types whose components are the type-variable bounds (intersection types are defined in section 4.9) - and intersection types do not inherit private members from their components
The type of T
may not be A
. It can be of type B
that is a subclass of A
. In this case, accessing the private
method one()
does not conform to the inheritance rule which says that a subclass (that is class B
) does not inherit the private
members of its parent class (that is class A
).
Upvotes: 13
Reputation: 501
why i can't call the private member of the same class?
Because you try to call the private method from T
wich can be derived from A
. If you add a cast to A
again it will work:
protected void three() { ((A)two()).one(); }
Upvotes: 5