在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的 Effective 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
提供了哪些其他更基本的好处,而这些好处是使用Typesafe Enum模式无法实现的?
答案 0 :(得分:15)
enum
中定义的一组值,而不再是!enum
正确处理序列化。你可以使用类型安全的枚举来做到这一点,但它经常被遗忘(或者根本不知道)。这可确保e1.equals(e2)
始终暗示e1 == e2
任意两个enum
值e1
和e2
(反之亦然)更重要的是)。EnumSet
和EnumMap
(从this answer被盗)答案 1 :(得分:8)
当然,其他人会在这里提到很多优点作为答案。最重要的是,您可以非常快速地撰写enums
并执行许多操作,例如实施Serializable
,Comparable
,equals()
,toString()
,{{1}等等,你没有包含在你的枚举中。
但我可以向您展示hashCode()
(IMO)的严重缺陷。您不仅无法随意对它们进行子类化,而且还无法为它们配备通用参数。什么时候可以这样写:
enum
枚举时无法实现这一点:
// 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 ...
}
}
答案 2 :(得分:3)
您的类型安全枚举实现有点过于简单。当你处理序列化时,它将变得更加复杂。
Java enum
解决了序列化/反序列化的问题。 enum
保证是唯一的,您可以将它们与==
运营商进行比较。
阅读Effective Java 2nd Edition中的相关章节(关于使用枚举而不是单例,关于使用EnumSet
等)。
答案 3 :(得分:3)
现在在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
,覆盖toString
,提供values()
}和valueOf(String name)
。它们可以在类型安全开关语句中使用,并且是单例。
答案 4 :(得分:2)
答案 5 :(得分:2)
另外:
JDK5枚举可以在具有良好IDE支持的switch-case语句中轻松使用
Suit suit = ...;
switch (suit) {
case SPADES: System.out.println("Motorhead!"); break;
default: System.out.println("Boring ..");
}
答案 6 :(得分:2)
单独使用句法糖是值得的:-P毕竟,这也是(:)的原因。
但严重的是,开箱即用自动命名()和序号()以枚举它们,在switch()中使用它们,为它们附加额外的值这一事实对他们来说是很好的理由:它避免了很多样板代码。
使用整数的传统懒惰替代方案不是类型安全的,而且更加有限。 枚举这个替代方案的一个缺点是它们不再轻量级。