Java的枚举相对于旧的“Typesafe Enum”模式的优势?

在 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;
    }
}

(例如,参见布洛赫的《有效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;
  }
}

显然,语法更好,更简洁(无需显式定义值的字段,提供合适的),但到目前为止看起来非常像Typesafe枚举模式。toString()enum

我所知道的其他差异:

  • 枚举自动提供方法values()
  • 枚举可以在 中使用(编译器甚至检查您不会忘记值)switch()

但这一切看起来都只不过是句法糖,甚至有一些限制(例如 始终继承自 ,并且不能被子类化)。enumjava.lang.Enum

是否还有其他更基本的好处,这些好处是Typesafe枚举模式无法实现的?enum


答案 1
  • “不能被子类化”不是一个限制。这是最大的优势之一:它确保始终只有完全由中定义的一组值,并且没有更多!enum
  • enum正确处理序列化。您也可以使用类型安全的枚举来执行此操作,但它经常被遗忘(或者根本不知道)。这确保了对于任何两个值和(反之亦然,这可能更重要)始终隐含。e1.equals(e2)e1 == e2enume1e2
  • 有特定的轻量级数据结构来处理枚举:和(从这个答案中窃取EnumSetEnumMap)

答案 2

当然,其他人会在这里提到很多优点作为答案。最重要的是,你可以写得非常快,他们做了很多事情,比如实现,,,,等,你没有包括在你的枚举中。enumsSerializableComparableequals()toString()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 ...
    }
}

这对于枚举是不可能的:

// This can't be done
public enum DataType<T> {

    // Neither can this...
    INT<Integer>("int", Integer.class), 
    INT4<Integer>("int4", Integer.class), 

    // [...]
}

推荐