问题1 :我对这些代码感到有点困惑:
public class MyClass1 <E extends Enum<?>> {
// ...
}
public class MyClass2 <E extends Enum<E>> {
// ...
}
MyClass1
和MyClass2
之间的区别是什么?三种不同的E
是什么意思?
问题2 :来自Class Enum <E extends Enum<E>>
这是所有Java语言枚举类型的通用基类。
但是不是所有枚举类型Enum<E>
的公共基类?
问题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;
}
}
如何在enumType
中初始化数据字段MyClass
?
如果MyClass
不包含数据字段enumType
,那么函数getEnumSetFromStringList(List<String> list)
如何获得泛型<E extends Enum<?>>
的类型?
我可以通过这种方式获取Enum类型:E.class
?如果没有,是否在编译期间从泛型类型的 type-erasure 开始?
答案 0 :(得分:4)
Enum<E extends Enum<E>>
很难理解。
我们考虑两个enums
。
enum Colour { RED, GREEN, BLUE }
enum Shape { SQUARE, CIRCLE, TRIANGLE }
考虑compareTo()
中的Enum
方法。这用于根据声明的顺序比较同一Enum
中的不同常量。如果Enum
不是泛型类,则此方法的签名必须为int compareTo(Enum e)
。但这没有任何意义,因为那时你可以将Colour
与Shape
进行比较。我们希望compareTo
中的Colour
签名为int compareTo(Colour colour)
。唯一的方法是Enum
是具有类型参数E
的通用类,而Colour
的类型参数是Colour
!只要Colour
的类型参数为Colour
且Shape
的类型参数为Shape
,我们就只能将Colour
与Colour
进行比较}和Shape
到Shape
s。
所以在Enum
的定义中,我们想要一些表达方式,对于每个子类,type参数不仅必须是enum
,而且type参数应该是子类本身。因此,E
不应仅扩展Enum
,E
应扩展Enum<E>
!
这是Enum<E extends Enum<E>>
来自的地方。
(你不应该写Enum<E extends Enum<?>>
)。
将值赋给enumType
的一种方法是将Class<E>
传递给构造函数。喜欢这个
class MyClass2<E extends Enum<E>> {
private final Class<E> enumType;
MyClass2(Class<E> enumType) {
this.enumType = enumType;
}
}
如果您不想这样做,另一种在运行时获取Class<E>
对象的方法是使用Enum
实例方法getDeclaringClass()
。这要求您手头有一个E
实例来调用该方法。在运行时获取所有枚举常量数组的一种方法是编写e.getDeclaringClass().getEnumConstants()
。
你不能写E.class
,因为你正确地说,泛型是使用类型擦除过程实现的。在运行时,ArrayList<String>
只是ArrayList
,因此无法访问类型参数。
答案 1 :(得分:3)
MyClass1和MyClass2有什么不同,这三种不同的E是什么意思?
MyClass1
引入了一个名为E
的泛型类型参数,它扩展了Enum<?>
类。在这里,?
意味着我们不知道(并且关心)Enum
类的通用版本对E
进行扩展,因此通配符是使用
同时,MyClass2
还引入了一个名为E
的泛型类型参数,该参数再次扩展了Enum
类型。这一次,Enum
类型是相同 E
的通用类型,这意味着此类型参数必须是Enum
类的子类,并且还支持Enum
中定义的所有方法,这些方法使用完全相同的类型E
。例如,此类方法为getDeclaringClass()
,将返回Class<E>
而不是Class<Object>
。
但是不是所有枚举类型枚举的公共基类吗?
没有。如果它不是Enum<E>
的子类,那么泛型参数将没有意义。
如何在MyClass中初始化数据字段enumType?
您必须在构造函数中传递Class<E>
并将值复制到私有成员:
public MyClass(Class<E> enumType) {
this.enumType = enumType;
}
如果MyClass不包含数据字段enumType,那么函数getEnumSetFromStringList(...)如何获得泛型类型?
由于类型擦除,它将无法获得它。如果您需要泛型类的类,则必须维护一个包含Class<E>
值的成员;
我可以这样得到Enum类型:E.class?如果不是,那么在编译期间从泛型类型擦除的原因是什么?
你不能因为E
只是运行时特定的别名。