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

Java枚举是伟大的。 泛型也是如此。 当然,由于类型擦除,我们都知道后者的局限性。 但有一件事我不明白,为什么我不能创建这样的枚举:

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

这个泛型类型参数<T>反过来可以在各个地方有用。 设想一个方法的泛型类型参数:

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

或者甚至在枚举类本身:

public T convert(Object o);

更具体的例子#1

由于上面的例子对某些人来说可能看起来太抽象了,下面是我为什么要这样做的一个更真实的例子。 在这个例子中,我想使用

  • 枚举,因为那样我可以枚举一组有限的属性键
  • 泛型,因为那样我就可以拥有方法级别的类型安全性来存储属性
  • public interface MyProperties {
         public <T> void put(MyEnum<T> key, T value);
         public <T> T get(MyEnum<T> key);
    }
    

    更具体的例子#2

    我有一个枚举的数据类型:

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

    每个枚举字面值显然会有基于泛型类型<T>附加属性,同时也是一个枚举(不可变,单例,枚举等)

    题:

    没有人想到这个? 这是编译器相关的限制吗? 考虑到这个事实,关键字“ enum ”被实现为语法糖,代表JVM生成的代码,我不理解这个限制。

    谁可以向我解释这一点? 在你回答之前,考虑一下:

  • 我知道泛型类型被删除:-)
  • 我知道有使用Class对象的解决方法。 他们是解决方法。
  • 泛型类型会导致编译器生成的类型强制转换(例如,在调用convert()方法时)
  • 泛型类型<T>将在枚举上。 因此它受到每个枚举文字的约束。 因此,编译器会知道在编写类似String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);时应用的类型String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject); String string = LITERAL1.convert(myObject); Integer integer = LITERAL2.convert(myObject);
  • 这同样适用于T getvalue()方法中的泛型类型参数。 编译器可以在调用String string = someClass.getValue(LITERAL1)时应用类型转换String string = someClass.getValue(LITERAL1)

  • 现在正在讨论JEP-301增强型枚举。 JEP中给出的例子正是我所期待的:

    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
    

    问题的答案是:

    由于类型擦除

    这两种方法都不可能,因为参数类型被擦除。

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

    为了实现这些方法,你可以构造你的枚举为:

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

    因为你不能。 认真。 这可以添加到语言规范。 它没有。 这会增加一些复杂性。 这对成本的好处意味着它不是高优先级。

    更新:当前正在添加到JEP 301:增强型枚举下的语言。

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

    上一篇: Why shouldn't Java enum literals be able to have generic type parameters?

    下一篇: Get generic type of class at runtime