我的印象是私有非静态变量只能通过调用变量所在对象的方法来访问,但事实并非如此。有人可以解释为什么以下编译和运行的原因?
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 :(得分:21)
A类的私有成员变量可以通过任何类A(静态或非静态)方法访问(即读/写),因此在您的示例中,因为该方法更改了string是成员所属的同一个类的方法,它被授予对变量的访问权。
原因是因为一个类被认为是一个独立的逻辑体(即一个特定的实现),所以隐含在一个类中是有意义的;没有理由从该访问权限中排除静态方法,因为它们也是该类提供的特定实现的一部分。
答案 1 :(得分:3)
规则很简单:
类的成员方法可以访问和修改同一类的私有成员,无论其可见性如何。
答案 2 :(得分:3)
正如其他一些帖子所述,Java的可见性系统是基于类的,而不是基于对象的。
请注意,这在编译器中使用:当您具有嵌套类并访问外部类的私有字段时,将生成公共合成静态方法以允许访问。它通常被命名为“access $ 0”等。您可以使用这些合成方法创建一个违反封装的字节码而不使用Reflection API。您还可以从Reflection API访问它们,而无需启用对私有成员的访问权限。许多疯狂的事情都可以做......
如果没有这样的可见性系统,编译器可能需要将其编译成其他方式。
...... Hoewver,终端程序员通常不需要知道这个细节。 IDE在代码完成中不包含合成方法,我希望编译器(Jasmin除外)不允许您使用它。因此,如果您不生成字节码并且不使用Reflection API而忽略了堆栈跟踪中的这些方法,那么您可能不需要知道这些细节。
答案 3 :(得分:3)
您似乎将visibility
与scope
混为一谈。实例变量在实例的范围内,因此不能直接在静态方法中访问它们,而只能在实例中使用实例引用限定符:s._privateString
。
但是,这并不意味着同一个类中的静态方法的实例变量不是 visible ,因为private
表示在类中可见(对于任何具有任何范围的成员)
答案 4 :(得分:0)
您的代码已编译,因为在 setPrivateString(String str,Sandbox s)中,您正在通过引用变量s访问私有变量 _privateString 。
非静态成员只能通过静态API通过实例变量进行访问。
检查此代码
public class Sandbox {
public static void main(String[] args) {
Sandbox s = new Sandbox();
// testAccess();// If you uncomment this line you will get compile time error
s.testAccess();//can only access in this way
}
private void testAccess() {
System.out.println("can only access by instance variable from static method");
}
}