问题描述
在JDK1.5之前的Java中," typesafe enum"模式是实现只能采用有限值的类型的通常方法:
public class Suit { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); private Suit(String name){ this.name =name; } public String toString(){ return name; } }
(请参阅Bloch的有效Java 的项目21.
现在在JDK1.5+中,"官方"方式显然是使用enum:
public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }
显然,语法有点更好,更简洁(无需明确定义值的字段,合适的toString()提供),但是到目前为止,enum看起来非常类似于Typesafe enum模式.
我知道的其他差异:
- 枚举会自动提供values()方法
- 枚举可以在switch()中使用(编译器甚至检查您不会忘记一个值)
但这看起来只不过是句法糖,甚至施加了一些局限性(例如enum始终从java.lang.Enum继承,也不能被分类).
enum提供的其他更基本的好处是无法通过类型的枚举模式实现的?
推荐答案
- "不能分类"不是限制.这是最大的优势之一:它确保总有enum中定义的一组值,而不再有!
- enum正确处理序列化.您 can 也可以用类型的安全枚举来做到这一点,但经常被遗忘(或根本不知道).这样可以确保e1 == e2 总是表示任何两个e1和e2的e1 == e2(反之亦然,这可能更重要). .
- 有特定的轻量化数据结构可以处理枚举:EnumSet和EnumMap(从这个答案)
其他推荐答案
当然,这里有很多优点在这里提到答案.最重要的是,您可以非常快地编写enums,并且它们做了很多事情,例如实现Serializable,Comparable,equals(),hashCode(),hashCode(),等等,等等,您未包含在您的枚举.
但是我可以向您展示enum(IMO)的严重缺点.您不仅不能随意将它们分类,而且不能为它们配备通用参数.当您可以写这篇文章时:
// A model class for SQL data types and their mapping to Java types public class DataType<T> { private final String name; private final Class<T> type; public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class); public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class); public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class); public static final DataType<Long> BIGINT = new DataType<Long>("bigint", Long.class); private DataType(String name, Class<T> type){ this.name = name; this.type = type; } // Returns T. I find this often very useful! public T parse(String string) throws Exception { // [...] } } class Utility { // Enums equipped with generic types... public static <T> T doStuff(DataType<T> type) { return ... } }
枚举是不可能的:
// This can't be done public enum DataType<T> { // Neither can this... INT<Integer>("int", Integer.class), INT4<Integer>("int4", Integer.class), // [...] }
其他推荐答案
现在在JDK1.5+中,"官方"方式是 显然要使用enum:
public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }
实际上,更像
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES; }
因为枚举已经提供了name()方法.此外,它们提供了ordinal()方法(可以启用EnumSet和EnumMap等有效的数据结构,实现Serializable,Override toString,提供values()和valueOf(String name).它们可以在类型的安全开关语句中使用,并且是单例.
问题描述
In Java prior to JDK1.5, the "Typesafe Enum" pattern was the usual way to implement a type that can only take a finite number of values:
public class Suit { private final String name; public static final Suit CLUBS =new Suit("clubs"); public static final Suit DIAMONDS =new Suit("diamonds"); public static final Suit HEARTS =new Suit("hearts"); public static final Suit SPADES =new Suit("spades"); private Suit(String name){ this.name =name; } public String toString(){ return name; } }
(see e.g. Item 21 from Bloch's Effective Java).
Now in JDK1.5+, the "official" way is obviously to use enum:
public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }
Obviously, the syntax is a bit nicer and more concise (no need to explicitly define fields for the values, suitable toString() provided), but so far enum looks very much like the Typesafe Enum pattern.
Other differences I am aware of:
- enums automatically provide a values() method
- enums can be used in switch() (and the compiler even checks that you don't forget a value)
But this all looks like little more than syntactic sugar, with even a few limitations thrown in (e.g. enum always inherits from java.lang.Enum, and cannot be subclassed).
Are there other, more fundamental benefits that enum provides that could not be realized with the Typesafe Enum pattern?
推荐答案
- "cannot be subclassed" isn't a restriction. It's one of the big advantages: It ensures there there is always only ever exactly the set of values defined in the enum and no more!
- enum correctly handles serialization. You can do that with type-safe enums as well, but it's often forgotten (or simply not known). This ensures that e1.equals(e2) always implies e1 == e2 for any two enum values e1 and e2 (and vice versa, which is probably more important).
- There are specific lightweight data structures that handle enums: EnumSet and EnumMap (stolen from this answer)
其他推荐答案
Of course there are lots of advantages other people will mention here as answers. Most importantly, you can write enums very fast and they do a lot of things like implement Serializable, Comparable, equals(), toString(), hashCode(), etc, which you didn't include in your enum.
But I can show you a serious drawback of enum (IMO). Not only can't you subclass them at will, but you can't equip them with a generic parameter. When you could write this:
// A model class for SQL data types and their mapping to Java types public class DataType<T> { private final String name; private final Class<T> type; public static final DataType<Integer> INT = new DataType<Integer>("int", Integer.class); public static final DataType<Integer> INT4 = new DataType<Integer>("int4", Integer.class); public static final DataType<Integer> INTEGER = new DataType<Integer>("integer", Integer.class); public static final DataType<Long> BIGINT = new DataType<Long>("bigint", Long.class); private DataType(String name, Class<T> type){ this.name = name; this.type = type; } // Returns T. I find this often very useful! public T parse(String string) throws Exception { // [...] } } class Utility { // Enums equipped with generic types... public static <T> T doStuff(DataType<T> type) { return ... } }
This is not possible with an enum:
// This can't be done public enum DataType<T> { // Neither can this... INT<Integer>("int", Integer.class), INT4<Integer>("int4", Integer.class), // [...] }
其他推荐答案
Now in JDK1.5+, the "official" way is obviously to use enum:
public enum Suit { CLUBS("clubs"), DIAMONDS("diamonds"), HEARTS("hearts"), SPADES("spades"); private final String name; private Suit(String name) { this.name = name; } }
Actually, it's more like
public enum Suit { CLUBS, DIAMONDS, HEARTS, SPADES; }
because enums already provide a name() method. Additionally, they provide an ordinal() method (which enables efficient data structures like EnumSet and EnumMap), implement Serializable, override toString, provide values() and valueOf(String name). They can be used in a type safe switch statement, and are singletons.