在Java中通过对象引用访问静态变量

14

为什么我们可以通过Java中的对象引用访问静态变量,像下面的代码一样?

public class Static {
    private static String x = "Static variable";

    public String getX() {
        return this.x;                 // Case #1
    }

    public static void main(String[] args) {
        Static member = new Static();
        System.out.println(member.x);  // Case #2
    }   
}

2
你也可以使用 Static.x,无需创建对象。 - nikhil
3
据我所知,Josh Bloch曾表示允许这样做是一个糟糕的决定。 - Ellen Spertus
6个回答

12

通常情况下,公共变量可以被所有人访问,而私有变量只能从当前类实例内部访问。 在您的示例中,由于该方法位于 Static 类中,因此您可以从 main 方法访问 x 变量。

如果您想知道为什么您可以从 Static 类的另一个实例中访问它(通常不允许访问私有变量),那是因为静态变量不存在于每个实例之间,而是存在于每个类之间。 这意味着 A 的相同静态变量可以从所有 A 的实例中访问。

如果不是这种情况,由于私有静态变量不属于任何一个实例,而是所有实例共享,因此没有人能够访问它。


6
允许这种情况的原因是JLS规定了这一点。具体允许这种情况的章节为JLS 6.5.6.2(对于member.x情况)和JLS 15.11.1(两种情况都适用)。后者指出:

如果字段是静态的:

  • 如果该字段是非空白final字段,则结果是主表达式类型所在的类或接口中指定类变量的值。

  • 如果该字段不是final,或者是一个空白final并且字段访问发生在类变量初始化器(§8.3.2)或静态初始化器(§8.7)中,则结果是一个变量,即主表达式类型所在的类中指定的类变量。


为什么JLS允许这些内容?

坦白地说,我不知道。我想不出任何允许它们的好理由。

无论如何,使用引用或 this 来访问静态变量都是一个坏主意,因为 大多数程序员 很可能会误认为你正在使用实例字段。这是不使用 Java 的这个特性的一个强烈理由。

在第一和第二种情况下,您应该将变量引用为 xStatic.x 而不是 member.x。(我更喜欢 Static.x。)


同意。我想明确强调,虽然不建议使用member.xthis.x,但仍然是可行的,并且不会有任何编译错误。 - Jacqueline P.
1
感谢您的评论。然而,我认为不需要再强调了;已经有一个很好的被接受的答案了。无论如何,问题是“为什么允许”,而不是“是否允许”。 - Stephen C

4

以那种方式引用静态变量不是最佳做法。

然而,您的问题是为什么允许这样做?我猜答案是为了使开发人员可以将实例成员(字段或变量)更改为静态成员,而无需更改对该成员的所有引用。

特别是在多开发人员环境中,这一点尤其重要。否则,您的代码可能因为您的合作伙伴将一些实例变量更改为静态变量而无法编译。


将实例变量设置为静态应该会导致编译错误。这不是一个功能,而是一个设计缺陷,这样的更改无法向下游传播。 - John Kugelman

0
static变量也被称为类变量,因为它们对于该类的每个对象都是可用的。
由于成员是Static类的一个对象,所以你可以通过成员对象访问Static类的所有静态和非静态变量。

2
不回答问题,不是因为没有答案。 - user207421

-1

非静态成员是实例成员。静态成员(类范围)无法访问实例成员,因为没有办法确定哪个实例拥有任何特定的非静态成员。

实例对象始终可以引用静态成员,因为它属于全局(共享)类,适用于其实例。


-2

从逻辑上讲,虽然这不是有趣的实践,但这是有意义的。静态变量通常用于在实例化期间强制变量的单个声明。对象是具有其他名称的类的新副本。即使对象是类的新副本,它仍具有(未实例化)类(第一个不可见实例)的特征。因此,新对象也具有指向原始副本的静态成员。需要注意的是:StackOverflow的新实例也是StackOverflow。


一个对象不是类的“副本”,也没有“指向原始副本”的概念。静态字段实际上并不存储在类的任何实例中,它们存储在其他地方。(在哪里?这取决于具体实现!)基本上,你试图根据JVM对静态变量的实现的错误心理模型来解释JLS语义。 - Stephen C

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