Java 如何定义枚举项的属性

Java 如何定义枚举项的属性,java,enums,Java,Enums,我已经读过这个问题,但我仍然感到困惑 我希望以下内容返回相关字符串: public enum Checker { EMPTY ("Empty"), RED ("Red"), YELLOW ("Yellow"); } 据我所知,这应该是可能的。只是想让您了解一下如何实现它。简短回答 您需要一个构造函数、一个字段和一个getter 建设者 枚举类型可以有构造函数,前提是其访问级别为私有或默认(包私有)。除了在枚举声明本身中,您不能直接调用这些构造函数。与类类似,当定义不带参

我已经读过这个问题,但我仍然感到困惑

我希望以下内容返回相关字符串:

public enum Checker {
    EMPTY ("Empty"),
    RED ("Red"),
    YELLOW ("Yellow");
}
据我所知,这应该是可能的。只是想让您了解一下如何实现它。

简短回答 您需要一个构造函数、一个字段和一个getter

建设者 枚举类型可以有构造函数,前提是其访问级别为私有或默认(包私有)。除了在枚举声明本身中,您不能直接调用这些构造函数。与类类似,当定义不带参数的枚举常量时,实际上调用编译器生成的默认构造函数。例如

public enum King {
    ELVIS
}
相当于

public enum King {
    ELVIS() // the compiler will happily accept this
}
就像在类中一样,如果定义显式构造函数,编译器不会插入默认构造函数,因此不会编译:

public enum King {
    ELVIS, // error, default constructor is not defined
    MICHAEL_JACKSON(true)
    ;
    private boolean kingOfPop;
    King(boolean kingOfPop){this.kingOfPop = kingOfPop;}
}
这也解释了构造函数的问题

字段和访问器 枚举是常量,因此是不可变的。但是,它们可以定义具有状态的字段。这是一种糟糕的做法,因为开发人员希望枚举及其关联值是常量,但您仍然可以使用getter和setter在枚举中定义非final字段

这是合法的java代码:

public enum Color {
    RED("FF0000"),
    GREEN("00FF00"),
    BLUE("0000FF");
    private String code;
    public String getCode(){return code;}
    public void setCode(String code){this.code = code;}
    private Color(String code){this.code = code;}
}
但它启用了如下邪恶代码:

String oldBlue = Color.BLUE.getCode();
Color.BLUE.setCode(Color.RED.getCode());
Color.RED.setCode(oldBlue);
因此,在99.99%的情况下:如果枚举中有字段,则应将其设为最终字段,并仅提供getter。如果字段本身不是不可变的,请提供防御性副本:

public enum Band {
    THE_BEATLES("John","Paul","George","Ringo");
    private final List<String> members;
    public List<String> getMembers(){
        // defensive copy, because the original list is mutable
        return new ArrayList<String>(members);
    }
    private Band(String... members){
        this.members=Arrays.asList(members);
    }
}

如果模式保持不变,这也会起作用并消除重复:

public enum Checker {
    EMPTY,
    RED,
    YELLOW;


    public String getDescription(){
        String name = name();
        return ""+Character.toUpperCase(name.charAt(0))
                 +name.substring(1).toLowerCase();
    }

}

@约阿希姆:没有setter,我看不出有什么区别。@约阿希姆:没错,我在你添加注释时加了一句:-)@mmyers,我认为在最终版本中有一些编译器优化的魔力fields@mmyers奇怪但真实。它在JLS中。运行时可以进行优化,而不是仅仅因为
final
。但是添加
final
的一个更好的理由是,可能有人想阅读代码。@mmyers:除了Tom所说的,这也是记录意图的一个重要方式。该字段没有任何更改的理由,它应该在构造函数完成后初始化,并且不允许设置它。为什么不用一个能准确表达这一点的关键字来记录呢?为什么这样更好?您每次都要重新分配所有这些字符串,我不会特别说这更具可读性。它避免了名称的重复(DRY原则),并且不需要构造函数或字段(从而减少内存)。如果重新分配是一个问题,而使用内存则不是,那么可以将它们缓存在字段或枚举映射中。实际上,可能有两个构造函数,一个具有直接存储值的值,另一个为空的构造函数使用getDescription方法生成值。无论如何,我都会把它们写在田野里。很明显,你们可能走得太远了!甚至不能确定枚举名称和“相关的”
字符串是否总是以它们天真的显示方式相关。您可能想要
FUSCHIA(“Fuchsia”)、WTF(“Dusty Lavendar”)
@Tom确切地说,这就是我提出两个构造函数场景的原因
public enum Checker {
    EMPTY,
    RED,
    YELLOW;


    public String getDescription(){
        String name = name();
        return ""+Character.toUpperCase(name.charAt(0))
                 +name.substring(1).toLowerCase();
    }

}