为什么Java不允许我通过同一类的方法访问私有方法?

2022-09-01 23:05:34

我有这样的代码:

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

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

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

IntelliJ告诉我“one()在A中具有私有访问权限”,但是嘿,为什么我不能称呼同一类的私有成员呢?


答案 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()methodYX

为了避免这种混淆,您需要显式声明要通过使用强制转换从当前类X调用私有成员

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

同样的事情也发生在 .因为编译器可以是任何子类,所以不允许访问其私有成员。因此,您需要将其转换回<T extends A>TAA

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 节中定义)-并且交集类型不会从其组件继承私有成员

的类型可能不是 。它可以是 的子类的类型。在这种情况下,访问该方法不符合继承规则,该规则指出子类(即类)不继承其父类(即类)的成员。TABAprivateone()BprivateA


推荐