在拥有引用时,Java私有字段访问是否可行?

9

今天我发现了以下“奇怪”的特性——如果你在类A的主体中有一个对类A对象的引用,那么你可以访问这个对象的私有字段,即:

public class Foo{
   private int bar;
   private Foo foo;
   public void f()
   {
       if(foo.bar == bar) // foo.bar is visible here?!
       {
            //
       }
   }
}

有没有人能够对此做出好的解释呢?

3
当你需要编写一个 equals 方法时,这个特性非常有用。 - S.L. Barth
2
同样的问题:https://dev59.com/h0vSa4cB1Zd3GeqPfIZc,http://stackoverflow.com/questions/4340129/accessing-private-field-in-java,https://dev59.com/xnVC5IYBdhLWcg3wYQAp - Stephen C
7个回答

21

访问修饰符是在类级别上起作用,而不是实例级别上起作用:在同一类中的所有代码都可以访问该类所有实例的私有成员。

这并没有什么特别奇怪的地方。


5

这是有意为之的。

引用Java语言规范:

只有可访问类型及其成员或构造函数声明允许访问时,引用类型(类、接口或数组)的成员(类、接口、字段或方法)或类类型的构造函数才是可访问的:

  • ...
  • 如果成员或构造函数被声明为private,则仅当它出现在包围该成员声明的顶级类体内(§7.6)时,才允许访问。
  • ...

3

f()是Foo的一个成员函数,因此它有权限访问Foo的私有成员。这对我来说并不意外。


问题在于,为什么当foo是Foo类的另一个实例,bar是私有字段时,我们可以访问foo.bar。 - asenovm
@iLate:我猜设计师只是遵循了C++的行为。 - LLS

1

如果你考虑到“private”修饰符隐藏实现细节的意图,那么这是有道理的。

试着从“这应该是这个类的私有内容”(在Java中等同于“这应该是这个源文件的私有内容”)而不是“这应该是这个实例的私有内容”的角度来思考。


0

@Michael的回答是正确的。对于@asenovm的代码,.NET的行为也是相同的。

此外,对于Java中的内部类也是如此。即使您将变量定义为私有,也可以访问它。当我第一次遇到时感到惊讶,因为这与C#不同。

public class WrapperClass
{

  public static  class NotThreadsafe {
        private int x = 0;
       //....          
    }

    public static void main(String[] args) {           
    final NotThreadsafe nts=new NotThreadsafe(); 
     int x = nts.x ; // !!! THIS IS ACCESSIBLE AS WELL FOR JAVA BUT NOT.NET
    }
}

对于嵌套类,C# 的情况不同。如果您将此代码粘贴到 Visual Studio 中,则无法正常工作。编译器会对访问级别进行干扰。


0

因为私有并不意味着它对对象外部是私有的,而是对其他类是私有的。您在Foo内部,因此可以看到bar。

这也是单例模式中私有构造函数的工作方式。


0

这些关键字是面向类的,而不是面向对象的。因此,它只是看到并认为“哦,一个类Foo的对象正在尝试访问Foo上的私有对象。好吧,那没问题。”


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