【问题标题】:Java: access to the constants in an enumeration (enum)Java:访问枚举中的常量(枚举)
【发布时间】:2011-07-09 13:28:03
【问题描述】:

阅读 SCJP 的书,我在第 1 章“自测”中发现了类似的内容:

enum Animals {
    DOG("woof"), CAT("meow"), FISH("burble");
    String sound;
    Animals(String s) { sound = s; }
}

class TestEnum {      
    static Animals a; 
    public static void main(String[] args) {                                                                                     
        System.out.println(a.DOG.sound + " " + a.FISH.sound);   

        // the following line is from me
        System.out.println(Animals.DOG.sound + " " + Animals.FISH.sound);
    }
} 

注意:代码编译正常。 我不明白为什么我们可以从变量a 中访问 DOG、CAT 或 FISH 常量。我认为(并且它也写在书中)作为常量的 DOG、FISH、CAT 以类似于public static final Animals DOG = new Animals(1); 的方式实现 因此,如果它们真的是静态的,为什么我们可以从 a 访问它们? 最后一行是我熟悉的方式。

【问题讨论】:

    标签: java enums constants


    【解决方案1】:

    可以从实例中访问静态数据,但这确实很糟糕,因为静态数据不像绑定到类那样绑定到实例。

    无论书上怎么说,不要那样使用静力学。如果你运行 checkstyle 之类的,他们也会发出警告:)

    顺便说一句,在您的示例中 a 为空。它会在某处初始化吗?

    编辑

    我知道编译器知道 a.DOG 绑定到什么,因为静态不能被覆盖。它不需要 a 来确定调用,只需要它具有的 a 的编译时类型。

    我也知道,即使 anull,该示例仍然有效(我试过了,所以我知道:)。

    但我仍然认为你可以从 null 获取东西很奇怪。这令人困惑:

    Animals a = null;
    System.out.println(a.DOG); // OK
    a.doSomething(); // NullPointerException
    

    当我调试 NPE 时,我会假设 a 不能为空,因为 println 工作正常。令人困惑。

    嗯,Java。如果你认为你已经看到了这一切,你会再次得到其他东西:)

    【讨论】:

    • 因为代码访问一个静态字段,它使用对象引用的类型而不是实例的值,所以它是否为空并不重要。这就是这个例子的怪异之处。
    • 本书并没有说要这样编码。这只是第一章末尾的一个问题,我回答错了,因为我不知道我们可以使用 a.SOMETHING。我知道这是不好的做法。
    • @florian 让我感到困惑的是,你可以从 null a 中得到一些东西 :)
    • 我认为“神奇”在于它不查看 a.DOG 的值,因为它知道我们要访问枚举常量,因此它使用“编译时类型”动物”直接。在书中的例子中,'a' 甚至没有被初始化,只是被声明了。
    • @florian 我能理解如何它是如何工作的。这是为什么让我感到困惑。可能是速度优化(通过设计)。编译时绑定是可能的,为什么要检查实例?
    【解决方案2】:

    虽然这可行,但不要那样做。将枚举与Animal.DOGAnimal.CAT 等一起使用。

    上面所做的是声明一个枚举类型的对象,并在其上引用静态DOG。编译器知道a 的类型,并且知道你想要Animal.DOG。但这会降低可读性。

    我相信这样做的目的是减少枚举的使用。 a.DOG 而不是 Animal.DOG。如果你真的想缩短它,你可以使用import static fqn.of.Animal,然后简单地使用DOG

    【讨论】:

    • 或者目的是你没有得到你的Java证书... :-(
    • +1 for the import static 出于某种原因,我只在 junit 测试中使用它(导入静态 junit.assertEquals 或模拟),但它也适用于枚举 :)
    • @xtraneon - 我也是。即使在测试中,我也倾向于避免静态导入。但无论如何,这是更短代码的官方选项。没有丑陋的黑客。
    【解决方案3】:

    a.DOG 与写Animal.DOG 相同。也就是说,编译器会将变量替换为其编译时类型 Animal。它被认为是糟糕的代码,因为它隐藏了它依赖于编译时类型而不是 a 的动态类型的事实。

    【讨论】:

    • a.DOG 与动物狗不同,a 不得为空。
    • @bestsss 枚举值是静态的,因此它不依赖于 a 的值,使用 a == null 运行它就可以了。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-08-21
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2010-12-10
    相关资源
    最近更新 更多