saroff
saroff

Reputation: 698

Why doesn't Java allow me to access private method through method of the same class?

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

Answers (3)

Pshemo
Pshemo

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

M A
M A

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

tomse
tomse

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

Related Questions