【问题标题】:Confused about the generic which extends an exist Enum type对扩展现有 Enum 类型的泛型感到困惑
【发布时间】:2014-12-25 17:43:04
【问题描述】:

问题 1:我对这些代码有点困惑:

public class MyClass1 <E extends Enum<?>> {
    // ...
}
public class MyClass2 <E extends Enum<E>> {
    // ... 
}

MyClass1MyClass2 有什么区别,三个不同的E 是什么意思?

问题 2:来自Class Enum &lt;E extends Enum&lt;E&gt;&gt;

这是所有 Java 语言枚举类型的通用基类。

但不是所有Enum类型的公共基类Enum&lt;E&gt;吗?

问题 3:现在我有这门课:

public class MyClass<E extends Enum<E>> {

    // for example, EnumSet<Category> 
    public Set<E> category; 

    // how to initial this member
    private Class<E> enumType; 

    // initial this.category with given strings
    public void getEnumSetFromStringList(List<String> list) {
        this.category = EnumSet.noneOf(enumType);
        for (String str : list) {
            this.category.add(Enum.valueOf(this.enumType, str));
        }
    }
}

// this is the Category of Enum type
public enum Category {

    LOCATION("LOCATION"), 
    HUMAN("HUMAN"),
    // ...
    DESCRIPTION("DESCRIPTION");

    private final String categoryName;

    Category(String categoryName) {
        this.categoryName= categoryName;
    }
}
  1. 如何在MyClass 中初始化数据字段enumType

  2. 如果MyClass不包含数据字段enumType,那么函数getEnumSetFromStringList(List&lt;String&gt; list)怎么能得到泛型类型&lt;E extends Enum&lt;?&gt;&gt;的类型呢?

  3. 我可以这样获取枚举类型:E.class吗?如果不是,是不是因为编译时泛型类型的type-erasure

【问题讨论】:

    标签: java generics interface enums type-erasure


    【解决方案1】:

    Enum&lt;E extends Enum&lt;E&gt;&gt; 很难理解。

    让我们考虑两个enums

    enum Colour { RED, GREEN, BLUE }

    enum Shape { SQUARE, CIRCLE, TRIANGLE }

    想想Enum 中的compareTo() 方法。这用于根据声明的顺序比较同一 Enum 中的不同常量。如果 Enum 不是泛型类,则此方法的签名必须是 int compareTo(Enum e)。但这没有任何意义,因为您可以将ColourShape 进行比较。我们希望ColourcompareTo 的签名为int compareTo(Colour colour)。这样做的唯一方法是如果Enum 是具有类型参数E 的泛型类并且Colour 的类型参数是Colour!只要Colour的类型参数为ColourShape的类型参数为Shape,那么我们只能将Colours与Colours和Shapes与Shapes进行比较.

    所以在Enum 的定义中,我们想要某种方式来表达,对于每个子类,类型参数不仅必须是enum,而且类型参数应该是子类本身。因此E 不应该只是扩展EnumE 应该扩展Enum&lt;E&gt;

    这就是Enum&lt;E extends Enum&lt;E&gt;&gt; 的来源。

    (你不应该写Enum&lt;E extends Enum&lt;?&gt;&gt;)。

    enumType 赋值的一种方法是将Class&lt;E&gt; 传递给构造函数。像这样

    class MyClass2<E extends Enum<E>> {
        private final Class<E> enumType;
    
        MyClass2(Class<E> enumType) {
            this.enumType = enumType;
        }
    }
    

    如果您不想这样做,另一种在运行时获取Class&lt;E&gt; 对象的方法是使用Enum 实例方法getDeclaringClass()。这要求您手头有一个E 的实例来调用该方法。在运行时获取所有枚举常量数组的一种方法是编写e.getDeclaringClass().getEnumConstants()

    你不能写E.class,因为正如你所说的,泛型是使用类型擦除的过程来实现的。在运行时,ArrayList&lt;String&gt; 只是一个ArrayList,因此无法访问类型参数。

    【讨论】:

    • 那么Enum&lt;E extends Enum&lt;E&gt;&gt;中的第二个E指定了E的Enum类型的基本类型,而第一个E作为泛型名称的名称?另一个问题是,由于 Enum 类型不能有子类,Enum&lt;E extends Enum&lt;E&gt;&gt; 只代表 Enum 类,Category 仅在传递给泛型类型时扩展自身?
    【解决方案2】:

    MyClass1和MyClass2有什么不同,三个不同的E分别代表什么?

    MyClass1 引入了一个泛型类型参数,称为E,它扩展了Enum&lt;?&gt; 类。在这里,? 意味着我们不知道(也不关心)Enum 类的哪个通用版本扩展了E,因此使用了通配符。

    同时,MyClass2 还引入了一个泛型类型参数,称为E,它再次扩展了Enum 类型。这一次,Enum 类型是由E 泛型的相同,这意味着该类型参数必须是Enum 类的子类,并且还支持所有方法,在Enum 中定义,它使用完全相同的类型E。比如这个方法是getDeclaringClass(),它会返回Class&lt;E&gt;而不是Class&lt;Object&gt;


    但不是所有Enum类型Enum的通用基类吗?

    没有。如果泛型参数不是Enum&lt;E&gt; 的子类,它就没有意义。


    如何在 MyClass 中初始化数据字段 enumType?

    您必须在构造函数中传递Class&lt;E&gt; 并将值复制到私有成员:

    public MyClass(Class<E> enumType) {
        this.enumType = enumType;
    }
    

    如果 MyClass 不包含数据字段 enumType,那么函数 getEnumSetFromStringList(...) 如何获取泛型类型的类型?

    由于类型擦除,它将无法获取它。如果您需要泛型类型的类,则必须维护一个成员,该成员包含 Class&lt;E&gt; 值;


    我可以通过这种方式获取Enum类型:E.class吗?如果不是,是不是编译过程中泛型类型擦除的原因?

    你不能,因为E 只是在运行时特定的东西的别名。

    【讨论】:

    • 而如果MyClass&lt;E extends Enum&lt;E&gt;&gt;需要实现Serializable接口,我需要处理public Set&lt;E&gt; categoryprivate Class&lt;E&gt; enumType。对于category,我可以对待它Set&lt;String&gt; categoryStringSet = new HashSet&lt;String&gt;(); for (E e : this.category) { categoryStringSet.add(e.name());} writeObject(categoryStringSet);。以及如何序列化enumType?序列化一个内部有 Enum 类型的类是个好主意吗?
    • 据我所知,ClassSerializable,所以你可以把它传递给writeObject()
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2013-02-25
    相关资源
    最近更新 更多