如何在没有编译器警告的情况下使用泛型将java.lang.Class类型的变量初始化为Collection?

时间:2019-04-07 15:20:52

标签: java generics

我需要初始化Class<Set<String>>类型的变量

当我使用Set.class时,它返回变量Class<Set>

Class<Set> clazz = Set.class;

当我尝试

Class<Set<String>> clazz = Set<String>.class;

我有一个编译错误。

1 个答案:

答案 0 :(得分:2)

首先,您需要了解,在运行时,只有一个Class对象代表Set接口。 ClassSet<String>等没有单独的Set<Integer>对象。因此,类型Class<Set<String>>的变量在运行时可以执行的大多数操作都指向该{{1 }}类对象,问题是这样做是否有意义?

让我们考虑一下如何使用类型为Set的变量。

  • 您可以调用其Class<Set<String>>方法。通常,如果您有.cast(),则Class<T> clazz返回类型clazz.cast(x),并且它在运行时的作用是检查所传递的对象是否是该类的实例,如果不是,则返回引发异常;这就是为什么安全返回类型T的原因。但是,如果您的变量指向代表T接口的Class对象,则其Set只能检查该对象是.cast()的实例,而不是它是Set的实例(无论如何,这是不可能的,因为对象在运行时不知道其泛型类型参数;如果您进行了强制转换Set<String>,它将给出未经检查的强制转换警告;因此它将如果您能够通过执行(Set<String>)x而没有警告而“绕过”警告,则没有任何意义),因此它不能“安全地”返回类型Set<String>.class.cast(x)
  • 您可以调用其Set<String>方法。通常,如果您有.isInstance(),则Class<T> clazz返回true或false取决于传递的对象是否是clazz.isInstance(x)的实例。但是仅使用T,就不可能在运行时检查对象的泛型类型参数,因此调用.cast()的{​​{1}}方法可能无法给出“正确”的答案。
  • 您可以通过调用Class<Set<String>>方法或通过获取构造函数并使用构造函数的.isInstance()方法来创建新实例。好吧,在这种情况下,.newInstance()是一个接口,无法实例化;让我们考虑说.newInstance()。使用Set,您可以使用无参数构造函数来调用HashSet以获取Class<HashSet<String>>。在这种情况下,这是安全的,因为在运行时.newInstance()HashSet<String>new HashSet()之间没有区别。但是,如果您获得带有参数的构造函数,则在参数中使用类型new HashSet<String>()可能是不安全的,因为它无法检查传递的参数是否与这些类型匹配(因为它不能在运行时不知道new HashSet<Integer>()

如您所见,T无法安全地履行T类的某些功能合同。因此,如果没有警告,您将无法获得Class<Set<String>>。如果确定使用案例安全,可以将代表Class的{​​{1}}对象视为Class<Set<String>>,则可以通过执行Class来手动强制它,但是您将收到警告,表示您有责任确保它的安全。