私有成员访问 Java

8
私有成员是在类级别还是对象级别访问的。如果是在对象级别,则以下代码不应该编译。
    class PrivateMember {
   private int i;
   public PrivateMember() {
      i = 2;
   }
   public void printI() {
      System.out.println("i is: "+i);
   }
   public void messWithI(PrivateMember t) {
      t.i *= 2;
   }
   public static void main (String args[]) {
      PrivateMember sub = new PrivateMember();
      PrivateMember obj = new PrivateMember();
      obj.printI();
      sub.messWithI(obj);
      obj.printI();
   }
}

请确认在 sub 的 messWithI() 方法中访问 obj 的第 i 个成员是否有效。
7个回答

7

正如DevSolar所说,这是在(顶层)类级别上。

根据Java语言规范第6.6节

否则,如果成员或构造函数被声明为private,则仅当它出现在包含成员或构造函数声明的顶层类(§7.6)的主体内部时,访问才被允许。

请注意,并没有表明它仅限于特定对象的成员。

从Java 7开始,编译器不再允许访问类型变量的私有成员。因此,如果该方法的签名类似于public <T extends PrivateMember> void messWithI(T t),那么访问t.i将导致编译错误。但这并不会改变你特定的情况。


5
请注意,您甚至不需要源级别访问权限来操作私有字段。通过使用java.lang.reflect.AccessibleObject.setAccessibe(),所有代码都可以访问所有其他代码的私有成员,除非您指定禁止访问的安全策略。 private本身并不是一个安全功能!它只是向其他开发人员传达了一个强烈的提示,说明某些内容是内部实现细节,其他代码部分不应该依赖它们。

1
private(私有的)和默认访问(“包级私有”)是Java的主要安全特性!setAccessible上有一个安全检查。 - Tom Hawtin - tackline
1
默认安全策略允许这样做,因此它很难被视为“主要安全功能”。大多数开发人员的代码将使用默认安全策略运行,因此他们不应该过分信任私有成员无法访问。 - Michael Borgwardt

3

不是的。私有访问权限仅限于封闭的顶级类,因此您可以在同一顶级类中访问不同类的私有成员:

class PrivateAccess {
    static class InnerOne {
        private int value;
    }

    static class InnerTwo {
        int getOne ( InnerOne other ) {
            return other.value;
        }
    }
}

“类访问”的通常意思是您可以访问同一类型的其他实例的私有成员。在Java中,私有访问是由词法决定的,而不是由类型决定的。


1
从技术上讲,无论您谈论类还是封装外部类都没有关系。只是私有比预期或所需的更公共一些。 - Tom Hawtin - tackline
@Pete,你的意思是“这样你就可以访问同一顶层类中不同对象的私有成员”吗? - NSPKUWCExi2pr8wVoGNk
@tori3852,无论它们是实例成员还是静态成员,在同一顶级类中,您可以访问不同类的私有成员。 - Pete Kirkham

2

类级别。这意味着一个类的代码(但仅限于此)知道如何处理该类的对象。

如果您已经可以访问类的源代码,那么隐藏任何内容对您来说没有太大意义。


1

正如其他人所说,私有、默认访问(“包级私有”)、受保护的,以及在JDK 7模块中可能是基于类的(嵌套类继承有非常奇怪的规则,我记不清了)。但为什么呢?

主要原因是作为二进制(或更多)运算符的方法。为了有效实现,它们通常需要或更容易编写,而无需使用或修改公共API。查看equals的实现-在良好的代码中,您将发现直接访问字段,并且只有少量对this的方法调用。(这方面的性能问题现在在现代JVM中大多已经不重要了,但代码质量问题仍然存在。)


0

补充一下DevSolar的回答,我认为messWithI应该声明为静态的:

public static void messWithI(PrivateMember t) {
  t.i *= 2;

} 我甚至很难读懂你试图做什么,如果没有“static”提示...而且这也使得回答你最初的问题更容易——即私有成员不仅限于当前实例的范围。


0
同一页面在6.6.8小节中也提到了以下声明:
“私有类成员或构造函数只能在包含该成员或构造函数声明的顶级类的主体内部访问。它不会被子类继承。”
我们要评估访问的私有类成员是i。 public void messWithI()是一个存在于i被声明的顶级类PrivateMember中的方法。
你的结构符合上述声明,这就是为什么它可以无问题运行的原因。
这与Jon和Devsolar所说的意思相同。
类成员的访问修饰符与代码编写的位置有关(在哪个包和哪个类中),而不管授予访问权限的成员类型是类成员还是实例成员。
从逻辑上讲,如果没有类的实例,就不能使用类的实例成员,但这是一个不同的问题,与成员的生命周期有关。

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接