【问题标题】:Java static methods accessing private variables访问私有变量的 Java 静态方法
【发布时间】:2011-07-04 23:40:54
【问题描述】:

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

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# 中也是如此。

【问题讨论】:

  • 您可以直接从main() 修改_privateString,因为它在同一类中。

标签: java variables static scope private


【解决方案1】:

A 类的私有成员变量可以通过 A 类的 any 方法(静态或非静态)访问(即读/写),因此在您的示例中,由于方法更改string 是成员所属类的方法,它被授予访问变量的权限。

原因是因为一个类被认为是一个自包含的逻辑体(即一个特定的实现),所以隐私包含在一个类中是有道理的;没有理由从该访问权限中排除静态方法,因为它们也是该类提供的特定实现的一部分。

【讨论】:

  • 那么类的任何实例都可以访问该类的所有其他实例的所有私有变量?
  • 没错!乍一看,这可能看起来很奇怪,但当您考虑到一个类是一个单一的实现时,这是有道理的。
  • @T.K.例如,public void changeOther(String changeTo, Sandbox s) { s._privateString=changeTo; } 可以完全在另一个实例上执行:s1.changeOther("blah", s2);
  • 好的。是否有一种设计模式会强制执行只有变量a 所属的实例才能访问a 的规则?或者我应该在另一个问题中而不是在评论中提出这个问题,然后开放给更多人回答?
【解决方案2】:

规则很简单:

类的成员方法可以访问和修改同一类的私有成员无论其可见性如何

【讨论】:

    【解决方案3】:

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

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

    如果没有这样的可见性系统,编译器可能需要以其他方式编译它。

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

    【讨论】:

      【解决方案4】:

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

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

      【讨论】:

        【解决方案5】:

        您的代码已编译,因为在 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");
            }
        }
        

        【讨论】:

          猜你喜欢
          • 2021-11-24
          • 1970-01-01
          • 2021-11-13
          • 2015-07-22
          • 2012-06-29
          • 1970-01-01
          • 1970-01-01
          • 2010-10-13
          • 1970-01-01
          相关资源
          最近更新 更多