2011-02-26 99 views
11

我的印象是私有的非静态变量只能通过变量驻留在对象上的方法访问,但事实并非如此。有人能解释为什么以下编译和运行的原因吗?访问私有变量的Java静态方法

public class Sandbox { 
    private String _privateString = "unmodified"; 
    public static void setPrivateString(String str, Sandbox s) { 
     s._privateString = str; 
    } 
    public String toString() 
    { 
     return _privateString; 
    } 

    public static void main(String[] args) { 
     Sandbox s = new Sandbox(); 
     setPrivateString("modified", s); 
     System.out.println(s); 
    } 
} 

输出:

modified 

编辑:同样是在C#真。

+0

您可以直接从'main()'修改'_privateString'作为它在同一个类中。 – 2011-02-26 19:15:45

回答

17

类A的私有成员变量可以被访问(即读/写)任何类的方法(静态或非静态),所以在你的例子中,因为改变字符串的方法是一个方法该成员属于同一个类,它被授予访问该变量的权限。

原因是因为一个类被认为是一个自包含的逻辑体(即一个特定的实现),因此隐私被包含在一个类中是合理的,尽管没有理由从该访问中排除静态方法正确,因为它们也是类提供的具体实现的一部分。

+1

因此,类的任何实例都可以访问该类的所有其他实例的所有私有变量?正确! – 2011-02-26 19:17:08

+0

起初可能看起来很奇怪,但当你考虑一个类作为一个单一的实现时,它是有意义的。 – davin 2011-02-26 19:19:02

+0

@ T.K。例如,'public void changeOther(String changeTo,Sandbox s){s._privateString = changeTo; }'可以完全在另一个实例上执行:'s1.changeOther(“blah”,s2);' – davin 2011-02-26 19:21:37

2

规则很简单。类的成员方法可以访问和修改相同类的私有成员,而不管它们的可见性修饰符如何。

3

正如其他一些文章中提到的,Java的可见性系统是基于类的,而不是基于对象的。

请注意,这是在编译器中使用的:当您有嵌套类并访问外部类的专用字段时,会生成一个公共静态方法以允许访问。它通常被命名为“access $ 0”等。您可以通过使用这些合成方法创建一个违反封装而不使用Reflection API的字节码。您也可以从Reflection API访问它们,而无需访问私有成员。许多疯狂的事情可以做...

如果没有这样的可见性系统,编译器可能需要编译它elsehow。

...... Hoewver,最终程序员通常不需要知道这个细节。 IDE在代码完成中不包含合成方法,我希望编译器(除了Jasmin)不允许您使用它。所以如果你不生成字节码,也不使用Reflection API,并且你在堆栈跟踪中忽略了这些方法,那么你可能不需要知道这个细节。

3

您似乎很困惑visibilityscope。实例变量在实例的范围内,因此它们不能直接在静态方法中访问,而只能使用实例引用限定符:s._privateString

但是,这并不意味着对于同一类中的静态方法,实例变量不是可见,因为private表示类内部可见(对于具有任何作用域的任何成员)。