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

sar*_*off 22 java generics inheritance casting

我的代码看起来像这样:

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

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

    protected void three() { two().one(); }
}
Run Code Online (Sandbox Code Playgroud)

IntelliJ告诉我"one()在A中有私人访问权限",但是,嘿,为什么我不能调用同一个类的私有成员?

Psh*_*emo 18

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()` 
    }
}
Run Code Online (Sandbox Code Playgroud)

如您所见,即使我们在声明此成员的类中,也不允许从派生类访问私有成员.

可能的原因是私有成员不会继承到派生类的接口(这是private可见性修饰符的一种完整目的).因为在这样的类中,可以按照作者想要的方式重新声明这些成员,例如有人可以像这样创建类:

class Y extends X{
    private String field = "foo";
    private String method(){
        return "bar";
    }
}
Run Code Online (Sandbox Code Playgroud)

因此,您可能会看到通过调用y.method()您尝试访问类中method声明的内容Y,但您无法从X类中访问它(由于封装).这是场景编译器假设的,因为字段和私有方法不是多态的.

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

void bar(Y y){
    ((X)y).method(); 
}
Run Code Online (Sandbox Code Playgroud)

同样的事情发生了<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(); }
}
Run Code Online (Sandbox Code Playgroud)


man*_*uti 12

根据http://www.oracle.com/technetwork/java/javase/compatibility-417013.html,在Java 7中引入了此编译器错误:

描述:在JDK 5.0和JDK 6中,javac错误地允许访问类型变量的私有成员.这是错误的,因为JLS,Java SE 7 Edition,第4.4节规定,类型变量的成员是交集类型的成员,其组件是类型变量边界(交集类型在4.9节中定义) - 和交集类型不会从其组件继承私有成员

类型T可能不是A.它可以B是类的子类A.在这种情况下,访问该private方法one()不符合继承规则,该规则表明子类(即类B)不继承private其父类(即类A)的成员.


tom*_*mse 5

为什么我不能调用同一个类的私有成员?

因为您尝试调用T可以从A. 如果您A再次添加演员表,它将起作用:

protected void three() { ((A)two()).one(); }
Run Code Online (Sandbox Code Playgroud)