【问题标题】:How to initialize a variable of type java.lang.Class to Collection with generics without compiler warnings?如何在没有编译器警告的情况下使用泛型将 java.lang.Class 类型的变量初始化为 Collection?
【发布时间】:2019-04-08 23:54:21
【问题描述】:

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

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

Class<Set> clazz = Set.class;

当我尝试时

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

我有一个编译错误。

【问题讨论】:

  • 由于类型擦除(类型参数被编译器删除);以下是好的:Class&lt;Set&lt;String&gt;&gt; clazz = (Class)Set.class;
  • @Daniele,感谢您的解决方案。它可以工作,但会产生编译器警告。我正在尝试在没有警告的情况下找到解决方案。将对我的问题做出一些澄清。
  • 您可以放心地添加 @SuppressWarnings({"unchecked", "rawtypes"}) 。也许看看这个 SO 问题:stackoverflow.com/questions/313584/…
  • @SergeiTarasov :我没有看到一种优雅的方式来解决这里取消选中类型的问题。如果集合的初始化是由你的 API 的客户端完成的,也许你应该在你的一端添加一个额外的实现,它会在你端而不是客户端来抑制类型转换.....跨度>

标签: java generics


【解决方案1】:

首先,您需要了解,在运行时,只有一个Class 对象代表Set 接口。 Set&lt;String&gt;Set&lt;Integer&gt; 等没有单独的 Class 对象。所以Class&lt;Set&lt;String&gt;&gt; 类型的变量在运行时最多可以指向这个Set 类对象,问题是这样做有意义吗?

让我们考虑一下使用Class&lt;Set&lt;String&gt;&gt; 类型的变量可以做什么。

  • 您可以调用它的.cast() 方法。通常,如果你有一个Class&lt;T&gt; clazzclazz.cast(x) 返回类型T,它在运行时会检查传递的对象是否是类的实例,如果不是,则抛出异常;这就是为什么它返回类型T 是安全的。但是,如果你的变量指向代表Set接口的Class对象,那么它的.cast()只能检查该对象是Set的实例,而不是Set&lt;String&gt;的实例(无论如何这是不可能的,因为对象在运行时不知道它们的泛型类型参数;如果你做了一个演员(Set&lt;String&gt;)x,它会给出一个未经检查的演员警告;所以如果你能够“绕过”通过在没有警告的情况下执行Set&lt;String&gt;.class.cast(x) 发出警告),因此它不能“安全地”返回类型Set&lt;String&gt;
  • 您可以调用它的.isInstance() 方法。通常,如果您有一个Class&lt;T&gt; clazzclazz.isInstance(x) 根据传递的对象是否是T 的实例返回真或假。但仅使用.cast(),无法在运行时检查对象的泛型类型参数,因此调用Class&lt;Set&lt;String&gt;&gt;.isInstance() 方法可能不会给出“正确”的答案。
  • 您可以通过调用.newInstance() 方法或通过获取构造函数并使用构造函数的.newInstance() 方法来创建一个新实例。好吧,在这种情况下,Set 是一个接口,不能被实例化;让我们考虑说,HashSet。使用Class&lt;HashSet&lt;String&gt;&gt;,您可以使用无参数构造函数调用.newInstance() 以获取HashSet&lt;String&gt;。在这种情况下,它是安全的,因为new HashSet()new HashSet&lt;String&gt;()new HashSet&lt;Integer&gt;() 在运行时没有区别。但是,如果你得到一个带参数的构造函数,如果在参数中使用类型 T 可能是不安全的,因为它无法检查传递的参数是否与这些类型匹配(因为它不知道T 在运行时)。

如您所见,Class&lt;Set&lt;String&gt;&gt; 无法安全地履行 Class 类的某些功能的约定。因此,您应该无法在没有警告的情况下获得Class&lt;Set&lt;String&gt;&gt;。如果您确定您的用例将代表SetClass 对象视为Class&lt;Set&lt;String&gt;&gt; 是安全的,那么您可以通过执行(Class&lt;Set&lt;?&gt;&gt;)(Class&lt;?&gt;)Set.class 手动强制它,但您会收到一条警告,这意味着您负责确保它的安全。

【讨论】:

    猜你喜欢
    • 2021-12-09
    • 1970-01-01
    • 1970-01-01
    • 2010-09-08
    • 1970-01-01
    • 2022-01-05
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多