为什么不应该';Java枚举文本是否能够具有泛型类型参数?

为什么不应该';Java枚举文本是否能够具有泛型类型参数?,java,generics,enums,Java,Generics,Enums,Java枚举非常好。泛型也是如此。当然,由于类型擦除,我们都知道后者的局限性。但有一件事我不明白,为什么我不能创建这样的枚举: public enum MyEnum<T> { LITERAL1<String>, LITERAL2<Integer>, LITERAL3<Object>; } 更具体的例子#1 因为上面的例子对某些人来说可能太抽象了,这里有一个更真实的例子来说明我为什么要这么做。在这个例子中,我想使用 枚举,

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

public enum MyEnum<T> {
    LITERAL1<String>,
    LITERAL2<Integer>,
    LITERAL3<Object>;
}
更具体的例子#1 因为上面的例子对某些人来说可能太抽象了,这里有一个更真实的例子来说明我为什么要这么做。在这个例子中,我想使用

  • 枚举,因为这样我可以枚举一组有限的属性键
  • 泛型,因为这样我就可以有方法级别的类型安全性来存储属性
公共接口MyProperties{
公共作废put(MyEnum键,T值);
公共T-get(MyEnum密钥);
}
更具体的例子#2 我有一个数据类型的枚举:

public interface DataType<T> {}

public enum SQLDataType<T> implements DataType<T> {
    TINYINT<Byte>,
    SMALLINT<Short>,
    INT<Integer>,
    BIGINT<Long>,
    CLOB<String>,
    VARCHAR<String>,
    ...
}
公共接口数据类型{}
公共枚举SQLDataType实现数据类型{
TINYINT,
斯莫林,
INT,
比金特,
克洛布,
瓦查尔,
...
}
每个枚举文字显然都有基于泛型类型的附加属性,同时也是一个枚举(不可变、单例、可枚举等)

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

谁能给我解释一下?在回答之前,考虑一下:

  • 我知道泛型类型被删除:-)
  • 我知道有一些使用类对象的变通方法。它们是变通办法
  • 泛型类型在适用的情况下会导致编译器生成类型强制转换(例如,在调用convert()方法时)
  • 泛型类型将位于枚举上。因此它由每个枚举的文本绑定。因此编译器将知道在编写类似
    String String=LITERAL1.convert(myObject);Integer Integer=LITERAL2.convert(myObject);
  • 这同样适用于
    T getvalue()
    方法中的泛型类型参数。编译器可以在调用
    String String=someClass.getvalue(LITERAL1)

    • 我认为,因为基本上枚举不能实例化

      如果JVM允许,您将在哪里设置T类

      枚举是指数据应该总是相同的,或者至少不会发生变化

      新的MyEnum()

      不过,以下方法可能有用

      public enum MyEnum{
      
          LITERAL1("s"),
          LITERAL2("a"),
          LITERAL3(2);
      
          private Object o;
      
          private MyEnum(Object o) {
              this.o = o;
          }
      
          public Object getO() {
              return o;
          }
      
          public void setO(Object o) {
              this.o = o;
          }   
      }
      

      问题的答案是:

      因为类型擦除

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

      public <T> T getValue(MyEnum<T> param);
      public T convert(Object);
      
      publictgetvalue(MyEnum参数);
      公共T转换(对象);
      
      为了实现这些方法,您可以将枚举构造为:

      public enum MyEnum {
          LITERAL1(String.class),
          LITERAL2(Integer.class),
          LITERAL3(Object.class);
      
          private Class<?> clazz;
      
          private MyEnum(Class<?> clazz) {
            this.clazz = clazz;
          }
      
          ...
      
      }
      
      公共枚举MyEnum{
      LITERAL1(String.class),
      LITERAL2(Integer.class),
      LITERAL3(Object.class);
      私人课堂;
      私有MyEnum(类clazz){
      this.clazz=clazz;
      }
      ...
      }
      
      因为你不能。说真的。这可以添加到语言规范中。但事实并非如此。这会增加一些复杂性。成本效益意味着它不是一个高优先级

      更新:当前添加到语言中。

      因为“enum”是枚举的缩写。 它只是一组命名常量,用来代替序数,使代码更具可读性


      我不明白类型参数化常量的预期含义是什么。

      坦率地说,这似乎更像是一种寻找问题的解决方案

      java枚举的全部目的是对共享相似属性的类型实例的枚举进行建模,其提供的一致性和丰富性超出了可比较的字符串或整数表示

      以教科书枚举为例。这不是非常有用或一致:

      public enum Planet<T>{
          Earth<Planet>,
          Venus<String>,
          Mars<Long>
          ...etc.
      }
      
      公共枚举行星{
      地球,,
      维纳斯
      火星
      等
      }
      
      为什么我希望我的不同星球有不同的泛型类型转换?它解决了什么问题?它是否证明了使语言语义复杂化的合理性?如果我确实需要这种行为,枚举是实现它的最佳工具吗

      此外,您将如何管理复杂的转换

      比如说

      public enum BadIdea<T>{
         INSTANCE1<Long>,
         INSTANCE2<MyComplexClass>;
      }
      
      public enum baddea{
      实例1,
      实例2;
      }
      

      使用
      String
      Integer
      来提供名称或序号很容易。但是泛型允许您提供任何类型。您如何管理到
      MyComplexClass
      的转换?现在,通过强制编译器知道可以提供给gene的类型的有限子集,您可以将两个结构弄糟ric枚举并对概念(泛型)引入额外的混淆,这似乎是许多程序员都无法理解的。

      枚举中还有其他方法不起作用。
      MyEnum.values()
      会返回什么

      那MyEnum.valueOf(字符串名)呢

      如果您认为编译器可以使泛型方法

      公共静态MyEnum valueOf(字符串名称)

      为了像调用MyEnum myStringEnum=MyEnum.value(“某些字符串属性”)那样调用它,这也不起作用。 例如,如果您调用
      MyEnum myIntEnum=MyEnum.value(“某些字符串属性”)
      ,该怎么办?
      不可能实现该方法来正确工作,例如,当您像
      MyEnum.value(“某个双属性”)那样调用它时,抛出异常或返回null
      因为类型擦除。

      很遗憾,这一点已于讨论,但被撤回。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
      
      enum参数{//声明泛型枚举
      字符串(STRING.class),
      整数(INTEGER.class);
      课堂讨论;
      参数(类clazz){this.clazz=clazz;}
      类getClazz(){
      
      public enum Planet<T>{
          Earth<Planet>,
          Venus<String>,
          Mars<Long>
          ...etc.
      }
      
      public enum BadIdea<T>{
         INSTANCE1<Long>,
         INSTANCE2<MyComplexClass>;
      }
      
      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