Why shouldn't Java enum literals be able to have generic type parameters?

Java enums are great. So are generics. Of course we all know the limitations of the latter because of type erasure. But there is one thing I don't understand, Why can't I create an enum like this:

public enum MyEnum<T> {
    LITERAL1<String>,
    LITERAL2<Integer>,
    LITERAL3<Object>;
}

This generic type parameter <T> in turn could then be useful in various places. Imagine a generic type parameter to a method:

public <T> T getValue(MyEnum<T> param);

Or even in the enum class itself:

public T convert(Object o);

More concrete example #1

Since the above example might seem too abstract for some, here's a more real-life example of why I want to do this. In this example I want to use

  • Enums, because then I can enumerate a finite set of property keys
  • Generics, because then I can have method-level type-safety for storing properties
  • public interface MyProperties {
         public <T> void put(MyEnum<T> key, T value);
         public <T> T get(MyEnum<T> key);
    }
    

    More concrete example #2

    I have an enumeration of data types:

    public interface DataType<T> {}
    
    public enum SQLDataType<T> implements DataType<T> {
        TINYINT<Byte>,
        SMALLINT<Short>,
        INT<Integer>,
        BIGINT<Long>,
        CLOB<String>,
        VARCHAR<String>,
        ...
    }
    

    Each enum literal would obviously have additional properties based on the generic type <T> , while at the same time, being an enum (immutable, singleton, enumerable, etc. etc.)

    Question:

    Did no one think of this? Is this a compiler-related limitation? Considering the fact, that the keyword " enum " is implemented as syntactic sugar, representing generated code to the JVM, I don't understand this limitation.

    Who can explain this to me? Before you answer, consider this:

  • I know generic types are erased :-)
  • I know there are workarounds using Class objects. They're workarounds.
  • Generic types result in compiler-generated type casts wherever applicable (eg when calling the convert() method
  • The generic type <T> would be on the enum. Hence it is bound by each of the enum's literals. Hence the compiler would know, which type to apply when writing something like String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject); String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
  • The same applies to the generic type parameter in the T getvalue() method. The compiler can apply type casting when calling String string = someClass.getValue(LITERAL1)

  • This is now being discussed as of JEP-301 Enhanced Enums. The example given in the JEP is, which is precisely what I was looking for:

    enum Argument<X> { // declares generic enum
       STRING<String>(String.class), 
       INTEGER<Integer>(Integer.class), ... ;
    
       Class<X> clazz;
    
       Argument(Class<X> clazz) { this.clazz = clazz; }
    
       Class<X> getClazz() { return clazz; }
    }
    
    Class<String> cs = Argument.STRING.getClazz(); //uses sharper typing of enum constant
    

    The answer is in the question:

    because of type erasure

    None of these two methods are possible, since the argument type is erased.

    public <T> T getValue(MyEnum<T> param);
    public T convert(Object);
    

    To realise those methods you could however construct your enum as:

    public enum MyEnum {
        LITERAL1(String.class),
        LITERAL2(Integer.class),
        LITERAL3(Object.class);
    
        private Class<?> clazz;
    
        private MyEnum(Class<?> clazz) {
          this.clazz = clazz;
        }
    
        ...
    
    }
    

    Because you can't. Seriously. That could be added to the language spec. It hasn't been. It would add some complexity. That benefit to cost means it isn't a high priority.

    Update: Currently being added to the language under JEP 301: Enhanced Enums.

    链接地址: http://www.djcxy.com/p/57844.html

    上一篇: 在Java中将类型参数的类作为类型参数传递给泛型方法

    下一篇: 为什么Java枚举文字不能具有泛型类型参数?