从Java中的枚举属性获取泛型类的实例

Get instance of generic class from an enum attribute in Java

我的类中有一个枚举,它包含一个类属性,因此:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public enum DatEnum {
  CONSTANT_ONE(ClassOne),
  CONSTANT_TWO(ClassTwo);

  private Class<? extends UpperBoundClass> classAttribute;

  private DatEnum(Class<? extends UpperBoundClass> classAttribute) {
    this.classAttribute = classAttribute;
  }

  public <T extends UpperBoundClass> T getInstance() {
    UpperBoundClass instance = classAttribute.newInstance();
    return instance;
  }
}

但我在第一行得到警告:

Unchecked cast from capture#4-of ? extends UpperBoundClass to T

在吸气剂的第二行:

Unchecked cast from UpperBoundClass to T

到目前为止,代码是有效的,但是我真的想摆脱警告,并且更好地理解问题的实质所在。


1
2
3
4
public <T extends UpperBoundClass> T getInstance() {
  UpperBoundClass instance = classAttribute.newInstance();
  return instance;
}

此代码实际上并不返回。它返回由classAttribute字段引用的特定Class的实例。所有编译器可以验证的是,instance是可分配给(可以强制转换到)UpperBoundClass的。但是,该实例与方法签名中由表示的特定类型之间没有声明的关系。

最终结果:你会得到一个警告。只要使用CONSTANT_ONECONSTANT_TWO的每个地方都已经期望与在它们各自的构造函数中放入的类型相同,那么它可能会正常工作,但编译器无法强制执行或知道这一点。

如果您将方法更改为以下内容,那么您将看到(在调用代码中)不严格类型安全的使用站点,因为它们具有特定的子类:

1
2
3
public UpperBoundClass getInstance() {
  return classAttribute.newInstance();
}

或者,可以提供和存储类引用之间的一些关系:

1
2
3
4
public <T extends UpperBoundClass> T getInstance(Class<T> type) {
  UpperBoundClass instance = classAttribute.newInstance();
  return type.cast(instance); // verifies type-safety
}

但是这样做没有什么意义,因为调用方可以自己调用type.newInstance(),也可以简单地调用new ClassOne()(取决于用例)。调用type.cast(instance)可以在运行时抛出ClassCastException,但编译器会很高兴,因为它认为这是您的问题。

您正在与enum呈现统一契约这一事实作斗争;虽然您可以使用多态行为自定义单个常量,但不能使用泛型将enum的基本API参数化为随实例变化的内容。

相关阅读:为什么JavaEnm文字不能具有泛型类型参数?


首先,您的enum类没有枚举常量;其次,我认为您的enum对象将ClassObject作为其memeber变量。在大多数情况下,每个类都有一个对象(除非您使用多个类加载器加载一个类),那么为什么不使用简单的数据结构呢?只包含类对象。

事实上,你总是可以使用Class.newInstance()Class.getDeclaredConstructors()来获取Constructor并起诉它拥有你自己的实例。