-1

作为我的问题的前言,请注意我知道擦除类型是什么。我觉得有必要说明这个有用的答案,不要埋在基本的解释中。

我想获取类 List 的类对象。对于非泛型类型,我会使用像 String.class 这样的类文字,但对于 List,即使我可以获得正确的行为,我仍然会收到警告说我做错了。

据我了解, List 的类对象将是 type Class<List>,但即使写下该类型,

Class<List> c = null;

给出警告:“参数化类 'List' 的原始使用”。由于类型擦除,类对象无法了解列表元素,所以我的下一个猜测是

Class<List<?>> c = null;

作为一种类型被接受。接下来我必须获取类对象,但是尝试写下类文字的每一种方式都失败了:

Class<List<?>> l = List.class;

给出一个硬类型错误,而

Class<List<?>> l = List<?>.class;

说“无法从参数化类型中选择”。

Class<List<?>> l = (Class<List>)List.class;

失败并出现与没有强制转换相同的硬类型错误(预期因为强制转换是多余的),并且

Class<List<?>> l = (Class<List<?>>)List.class;

说“不可转换的类型”。

接下来,我尝试了以下无效代码片段以从编译器错误中了解一些信息:

List<?> l = new ArrayList<>();
int x = l.getClass();

现在编译器给出了一个类型错误Class<? extends java.util.List>——暂时忽略“扩展”部分,这很明显,因为getClass()可以返回一个子类,这告诉我.getClass()只想谈论原始 List 类型,而不是List<?>或类似的。在某种程度上,这对我来说似乎是正确的,因为类对象代表任何 List 实例,而不是“类型未知的列表”。但是,我现在又回到了原点,因为仅仅写下原始类型就会发出警告,所以我显然不应该这样做(我知道原始类型可用于处理遗留代码,但我在这里不这样做)。

我知道我可以像这样丢弃有关类对象的所有静态类型信息:

Class<?> c = List.class;

但这通常是不可行的,实际上我正在尝试解决需要该类型信息的更大问题。

虽然我知道我可以轻松禁用警告或使用类似的肮脏技巧,但我想知道获取 List 的类对象的正确方法是什么。

4

1 回答 1

3

你不可能赢得这场战争。

没有 , 的实例之类的Class<List<?>>东西。这是一个有效的type,但没​​有具体的值可以分配给它(除了null),因为List.class和分别new ArrayList<>().getClass()具有类型Class<List>Class<? extends List>

由于类型擦除,类实例本质上是原始类型的。

可以做未经检查的演员表:

Class<List<?>> clazz = (Class<List<?>>) (Class<?>) List.class;

但这也会产生警告;因为你可以做其他不安全的演员,比如:

Class<List<?>> clazz1 = (Class<List<?>>) (Class<?>) ArrayList.class;

您可能会遇到一个奇怪的情况,其中两个实例Class<List<?>>不相等,或者例如有时 aClass<List<?>>可以实例化(使用clazz.newInstance()),而其他时候则不能。


现在,如果您需要某种泛型类型标记,您可以使用 Guice 所做的类似操作:

TypeLiteral<ArrayList<?>> typeLiteral =
    new TypeLiteral<ArrayList<?>>() {};

由于捕获超类的方式,可以在运行时从中获取(注意- 这的匿名子类)。如果您不想依赖 Guice(或其他提供类似结构的库),您可以很容易地自己实现这一点,使用.ArrayList<?>{}TypeLiteraltypeLiteral.getClass().getGenericSuperclass()

但是,这是否是您可以采取的方法取决于您未公开的问题。关键的一点是泛型和反射不能很好地结合在一起。

于 2020-01-23T13:28:51.397 回答