Подтвердить что ты не робот

Почему Java не позволяет мне получить доступ к приватному методу с помощью метода того же класса?

У меня есть код, который выглядит так:

public class A<T extends A> {
    private T one() { return (T) this;}

    protected T two() { return (T) this;}

    protected void three() { two().one(); }
}

И IntelliJ говорит мне, что "у одного() есть личный доступ в A", но эй, почему я не могу вызвать частный член того же класса?

4b9b3361

Ответ 1

private Доступ к элементам возможен только внутри класса, в котором они были объявлены. Поэтому, если у вас есть класс

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()` 
    }
}

Как вы видите, нам не разрешен доступ к частному члену из производного класса, даже если мы внутри класса, в котором объявлен этот член.

Возможной причиной этого является то, что частные члены не наследуются для интерфейса производного класса (который является цельной целью модификатора видимости private). Из-за этого в таких классах можно обновлять эти элементы любым способом, который хочет автор, например, кто-то может создать класс, подобный этому:

class Y extends X{
    private String field = "foo";
    private String method(){
        return "bar";
    }
}

Итак, как вы видите, возможно, что при вызове y.method() вы пытаетесь получить доступ к method, объявленному в классе Y, но у вас нет доступа к нему из класса X (из-за инкапсуляции), И это компилятор сценария предполагает , потому что поля и частные методы не являются полиморфными.

Чтобы избежать этой путаницы, вам нужно явно указать, что вы хотите вызывать частный член из текущего класса X, используя кастинг

void bar(Y y){
    ((X)y).method(); 
}

То же самое происходит для <T extends A>. Поскольку T может быть любым подклассом A, компилятор не разрешит доступ к его частным членам. Поэтому вам нужно будет вернуть его обратно в A

class A<T extends A> {
    private T one() { return (T) this;}

    protected T two() { return (T) this;}

    protected void three() { ((A)two()).one(); }
}

Ответ 2

Эта ошибка компилятора была введена в Java 7 по http://www.oracle.com/technetwork/java/javase/compatibility-417013.html:

Описание. В JDK 5.0 и JDK 6 javac ошибочно разрешает доступ к закрытым членам переменных типа. Это неверно, поскольку JLS, Java SE 7 Edition, раздел 4.4, указывает, что члены переменной типа являются членами типов пересечений, компоненты которых являются границами переменных типов (типы пересечений определены в разделе 4.9) - и типы пересечений не наследуют частных членов от их компонентов.

Тип T может не быть A. Он может быть типа B, который является подклассом A. В этом случае доступ к методу private one() не соответствует правилу наследования, в котором говорится, что подкласс (то есть класс B) не наследует членов private его родительского класса (класса A).

Ответ 3

почему я не могу вызвать частный член того же класса?

Потому что вы пытаетесь вызвать частный метод из T, который может быть получен из A. Если вы добавите приведение в A снова, он будет работать:

protected void three() { ((A)two()).one(); }