【问题标题】:Why doesn't Java allow me to access private method through method of the same class?为什么Java不允许我通过同一个类的方法访问私有方法?
【发布时间】:2015-07-12 12:02:36
【问题描述】:

我的代码如下所示:

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 中具有私有访问权限”,但是,为什么我不能调用同一类的私有成员?

【问题讨论】:

  • T 是一些扩展 A 但可能不是 A 的类
  • From the horse's mouth。类的子类无法访问其父类的私有方法,因为……这就是语言的设计方式。
  • “一个班级的孩子不能访问他们父母的私有方法” 但我尝试在父母班级访问他们!如果我写 class A { public void method(A obj) { 那么我可以访问 A 类的私有成员,但传递的 obj 可以是这个类的子级。那么为什么在这种情况下它不起作用呢?
  • 这有点不相关,但请注意,即使这确实有效,您也不能在一行中链接超过 2 个。为此,您应该将其声明为A&lt;T extends A&lt;T&gt;&gt;,这将允许无限链接。
  • 这是个好问题。正如@Peter Lawrey 所说,T 扩展A 但可能不是A- 但如果T 扩展A 那么T 的实例将有一个方法one,只能定义在课堂上A。我明白为什么从一个对其定义没有保证的范围内访问一个成员是不好的,但是这里的调用范围有一个有保证的具体定义——A 的扩展不能修改one 的行为,可以是吗?

标签: java generics inheritance casting


【解决方案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(),您可能试图访问在Y 类中声明的method,但您无法从X 类中访问它(由于封装) .这是场景编译器假设的因为字段和私有方法不是多态的

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

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

&lt;T extends A&gt; 也会发生同样的事情。由于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】:

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

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

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

    【讨论】:

    • 好吧,我只是用通常的类型检查了它,没有泛型,它以相同的方式工作。但我还是不明白为什么?我们知道,我们有一个类 A 的子类型,那么为什么我们不能访问 A 中私有的成员,在子类的变量上呢?我们最终会尝试从 A 类访问它们,我们不会破坏任何继承/封装规则。
    【解决方案3】:

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

    因为您尝试从T 调用私有方法,而该方法可以从A 派生。如果您再次向A 添加演员表,它将起作用:

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

    【讨论】:

      猜你喜欢
      • 2021-07-20
      • 2014-03-28
      • 2010-11-17
      • 2013-11-12
      • 2014-11-03
      • 2021-04-03
      • 2016-11-16
      • 1970-01-01
      • 2011-06-26
      相关资源
      最近更新 更多