我的印象是私有非静态变量只能通过调用变量所在对象的方法来访问,但事实并非如此。有人可以解释为什么以下编译和运行的原因?
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#中也是如此。
A类的私有成员变量可以通过任何A类方法(静态或非静态)访问(即读/写),因此在您的示例中,因为更改字符串的方法是同一类的方法成员属于,它被授予对变量的访问权限。
原因是因为一个类被认为是一个独立的逻辑体(即一个特定的实现),所以有意义的是隐私包含在一个类中;没有理由从该访问权限中排除静态方法,因为它们也是该类提供的特定实现的一部分。
正如其他一些帖子中所提到的,Java的可见性系统是基于类的,而不是基于对象的。
请注意,这在编译器中使用:当您具有嵌套类并访问外部类的私有字段时,将生成公共合成静态方法以允许访问。它通常被命名为“access $ 0”等。您可以使用这些合成方法创建一个违反封装的字节码而不使用Reflection API。您还可以从Reflection API访问它们,而无需启用对私有成员的访问权限。许多疯狂的事情都可以做到......
如果没有这样的可见性系统,编译器可能需要编译它。
...... Hoewver,终端程序员通常不需要知道这个细节。 IDE在代码完成中不包含合成方法,我希望编译器(Jasmin除外)不允许您使用它。因此,如果您不生成字节码并且不使用Reflection API并且您在堆栈跟踪中忽略这些方法,则可能不需要知道此详细信息。
你好像在混淆visibility
和scope
。实例变量在实例的范围内,因此不能直接在静态方法中访问它们,而只能在实例中使用实例引用限定符:s._privateString
。
但是,这并不意味着实例变量对于同一个类中的静态方法是不可见的,因为private
意味着在类中可见(对于任何具有任何范围的成员)。
规则很简单:
类的成员方法可以访问和修改同一类的私有成员,无论其可见性如何。
您的代码是编译的,因为在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");
}
}