为什么应该以静态方式访问静态字段?

73
public enum MyUnits
{
    MILLSECONDS(1, "milliseconds"), SECONDS(2, "seconds"),MINUTES(3,"minutes"), HOURS(4, "hours");

    private MyUnits(int quantity, String units)
    {
        this.quantity = quantity;
        this.units = units;
    }

    private int quantity;
    private  String units;

 public String toString() 
 {
    return (quantity + " " + units);
 }

 public static void main(String[] args) 
 {
    for (MyUnits m : MyUnits.values())
    {
        System.out.println(m.MILLSECONDS);
        System.out.println(m.SECONDS);
        System.out.println(m.MINUTES);
        System.out.println(m.HOURS);
    }
 }
}
这是指向来自 这篇帖子 的内容。我无法回复或评论任何内容,因此创建了一个新的帖子。为什么我的

会消失?
System.out.println(m.MILLSECONDS);

警告提示-静态字段MyUnits.MILLSECONDS应该以静态方式访问?谢谢。


7
我修改了标题,原来是“Java 代码优化”。请更加注意问题的标题。 - user unknown
抱歉,我的错,下次会注意的 :) - Ava
3个回答

116

因为当您访问静态字段时,应该在类(或在此情况下是枚举)上这样做。如下所示:

MyUnits.MILLISECONDS;

不是像实例一样

m.MILLISECONDS;

编辑:为了回答“为什么”的问题:在Java中,当您将某个内容声明为static时,您是在说它是类的成员,而不是对象的成员(这就是为仅有一个的原因)。 因此,在对象上访问它是没有意义的,因为该特定数据成员与类相关联。


13
是的,但为什么静态字段应该以静态方式访问?! - dokaspar
1
如果我使用的类在静态方法中扮演重要角色,那就会出现问题。例如:new Object().getClass().getEnclosingClass(); - Seby
但是类的成员也是对象,不是吗? - sivi

84

实际上有一个很好的理由:
出于歧义原因,非静态访问并不总是起作用。

假设我们有两个类A和B,后者是A的子类,并且具有相同名称的静态字段:

public class A {
    public static String VALUE = "Aaa";
}

public class B extends A {
    public static String VALUE = "Bbb";
}

直接访问静态变量:

A.VALUE (="Aaa")
B.VALUE (="Bbb")

使用实例进行间接访问(会产生编译器警告,提示应该静态访问VALUE):

new B().VALUE (="Bbb")

目前为止,编译器能够猜测使用哪个静态变量,在超类中的那个似乎更远一些,这看起来似乎很合理。

现在到了棘手的地方:接口也可以有静态变量。

public interface C {
    public static String VALUE = "Ccc";
}

public interface D {
    public static String VALUE = "Ddd";
}

让我们从B中移除静态变量,并观察以下情况:

  • B实现C、D
  • B扩展自A,实现C
  • B扩展自A,实现C、D
  • B扩展自A,实现C,且A实现D
  • B扩展自A,实现C,且C扩展自D
  • ...

现在语句new B().VALUE有歧义的,因为编译器无法确定指的是哪个静态变量,并将其报告为错误:

错误:对VALUE的引用不明确
C中的变量VALUE和D中的变量VALUE都匹配

这正是为什么应该以静态方式访问静态变量的原因。


13
我认为这应该是正确的答案,它表明了为什么这很危险。 - Water
5
@ChrisThompson的回答只是“这不合理--你声明了它为静态,所以要将其用作静态”--而这个回答实际上给出了为什么这是一个不好的做法并值得具体负面后果的解释。 - Don Cheadle
4
我同意这个答案比被采纳的那个更有帮助。我猜SO并不总是按照预期工作!尽管如此,它仍然很棒。最后,我想一个相关的有趣问题是:为什么可以从实例访问静态字段或方法呢? - Dici
2
本答案中所解释的情况最适合这个问题。 - Preetam Kumar
2
好的回答,但仍然不太令人信服:给出的例子并不危险,因为编译器可以检测到它。 - nyholku
显示剩余3条评论

12

因为它(MILLISECONDS)是一个静态字段(隐藏在枚举中,但实际上就是这样)。然而,它被调用于给定类型的实例(但请看下面,因为这并不是真的1)。

javac会"接受"这个,但它应该是MyUnits.MILLISECONDS(或者在适用范围内没有前缀)。

1 实际上,javac会将代码重写为首选形式--如果m恰好是null,它不会在运行时抛出NPE--它实际上从未被调用过。

愉快的编码。


我并没有看到问题标题与其余内容的关联。更准确和专业的标题可以增加问题/答案对其他程序员的帮助。

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