简体   繁体   English

在不丢失类型信息的情况下获取类 List 的类对象的正确方法是什么?

[英]What is the correct way to obtain the class object for class List without losing type information?

As a preface to my question, please note that I know what type erasure is.作为我问题的前言,请注意我知道擦除是什么类型。 I feel the need to state this so useful answers don't get buried in basic explanations.我觉得有必要说明这个有用的答案,不要被基本解释所掩盖。

I would like to obtain the class object for class List.我想获取类 List 的类对象。 For a non-generic type, I would use a class literal like String.class, but for List, even though I can obtain the correct behavior, I still get warnings that I am doing it wrong.对于非泛型类型,我会使用像 String.class 这样的类文字,但是对于 List,即使我可以获得正确的行为,我仍然会收到警告说我做错了。

From my understanding, the class object for List would be of type Class<List> , but even writing down that type,根据我的理解, List 的类对象的类型为Class<List> ,但即使写下该类型,

Class<List> c = null;

gives a warning: "Raw use of parameterized class 'List'".给出警告:“参数化类'List'的原始使用”。 Due to type erasure, the class object cannot have knowledge about list elements, so my next guess would be由于类型擦除,类对象无法了解列表元素,所以我的下一个猜测是

Class<List<?>> c = null;

which as a type gets accepted.作为一种类型被接受。 Next I have to obtain the class object, but every way of trying to write down a class literal fails:接下来,我必须获取类对象,但是尝试写下类文字的每种方法都失败了:

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

gives a hard type error, while给出了一个硬类型错误,而

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

says "Cannot select from parameterized type".说“无法从参数化类型中选择”。

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

Fails with the same hard type error as without the cast (expected since the cast is redundant), and与没有演员的情况相同的硬类型错误失败(预期,因为演员是多余的),和

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

says "inconvertible types".说“不可转换的类型”。

Next, I tried the following invalid code snippet to learn something from the compiler error:接下来,我尝试了以下无效代码片段以从编译器错误中了解一些信息:

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

Now the compiler gives a type error for Class<? extends java.util.List>现在编译器给出了Class<? extends java.util.List> Class<? extends java.util.List> -- ignoring the "extends" part for a moment, which is obvious since getClass() could return a subclass, this tells me that .getClass() only wants to talk about the raw List type, not List<?> or similar. Class<? extends java.util.List> -- 暂时忽略“extends”部分,这很明显,因为getClass()可以返回一个子类,这告诉我.getClass()只想谈论原始 List 类型,而不是List<?>或类似的。 In a way, that seems correct to me, since the class object represents any List instance, not "lists whose type is unknown".在某种程度上,这对我来说似乎是正确的,因为类对象表示任何 List 实例,而不是“类型未知的列表”。 However, I'm back to square one now because just writing down the raw type gives a warning, so I'm obviously not expected to do that (I understand that raw types can be used to deal with legacy code, but I'm not doing that here).但是,我现在又回到了原点,因为只是写下原始类型会发出警告,所以我显然不希望这样做(我知道原始类型可用于处理遗留代码,但我在这里不这样做)。

I understand that I could throw away all static type information about the class object like this:我知道我可以像这样丢弃关于类对象的所有静态类型信息:

Class<?> c = List.class;

But this is often not feasible, and indeed I'm trying to solve a larger problem where I need that type information.但这通常是不可行的,实际上我正在尝试解决需要该类型信息的更大问题。

While I know that I can easily disable warnings or use similar dirty tricks, I would like to know what the correct way is to obtain the class object for List.虽然我知道我可以轻松禁用警告或使用类似的肮脏技巧,但我想知道获取 List 的类对象的正确方法是什么。

There is no way you can win this war.你没有办法赢得这场战争。

There is no such thing as an instance of Class<List<?>> , or whatever.没有Class<List<?>>的实例之Class<List<?>>东西,或者其他什么。 That's a valid type , but there is no concrete value that you can assign to that (other than null ), because List.class and new ArrayList<>().getClass() have type Class<List> and Class<? extends List>这是一个有效的type ,但没有可以分配给它的具体值(除了null ),因为List.classnew ArrayList<>().getClass()具有Class<List>Class<? extends List> Class<? extends List> respectively.分别Class<? extends List>

Class instances are inherently raw-typed, because of type erasure.由于类型擦除,类实例本质上是原始类型的。

You can do unchecked casts:可以进行未经检查的强制转换:

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

but that will also generate warnings;但这也会产生警告; and since you can do other unsafe casts, like:并且因为您可以执行其他不安全的转换,例如:

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

you might end up in an odd situation where two instances of Class<List<?>> are unequal, or for example that sometimes a Class<List<?>> can be instantiated (using clazz.newInstance() ), and other times not.您可能最终会遇到一个奇怪的情况,其中Class<List<?>>两个实例不相等,或者例如有时Class<List<?>>可以被实例化(使用clazz.newInstance() ),而其他时候不是。


Now, if you need some sort of generic type token, you can use something like what Guice does:现在,如果您需要某种通用类型标记,您可以使用 Guice 所做的类似的事情:

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

It is possible to obtain the ArrayList<?> from that at runtime, because of the way the superclass is captured (note the {} - this is an anonymous subclass of TypeLiteral ).能够得到ArrayList<?>从在运行时,由于超类被捕获的方式(注意{} -这是一个匿名子类TypeLiteral )。 You can implement this yourself quite easily if you don't want to take a dependency on Guice (or other libraries which offer similar constructs), using typeLiteral.getClass().getGenericSuperclass() .如果您不想依赖 Guice(或其他提供类似结构的库),您可以很容易地自己实现,使用typeLiteral.getClass().getGenericSuperclass()

But whether that is an approach you can take depends on your undisclosed problem.但是,这是否是您可以采用的方法取决于您未公开的问题。 The key takeaway is that generics and reflection just don't play nicely together.关键的一点是泛型和反射不能很好地结合在一起。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 最简单的方法来转换类 <T> 到一个班级 <E extends Enum<E> &gt;不丢失类型信息 - Simplest way to cast a Class<T> to a Class<E extends Enum<E>> without losing type information 获得专门的儿童班的正确方法是什么? - What is the correct way to obtain a specialized child class? 无法使用原始类型而无法获取泛型类的类对象 - Unable to obtain a class object of a generic type without using raw types Jackson Class 的序列化与通用属性丢失通用属性的类型信息 - Jackson Serialization of Class with Generic Property losing type information of the generic property 在丢失信息的情况下转换为父类-存储对象的一部分 - Casting to parent class with losing information - store parts of an object 获取数组类型的Class对象的最佳方法是什么? - What's the best way to get a Class object for an array type? 匿名类的对象类型是什么 - What is the object type of an anonymous class 类对象作为列表的类型 - Class object as List's type 在没有完全加载类的情况下,Java中是否有任何方法可以在运行时访问有关类型的信息? - Is there any way in Java to access information about a type at runtime without fully loading the class? 使用@JsonTypeInfo 和@JsonSubTypes,反序列化没有基础Class 和类型信息的具体子类的Object - Using @JsonTypeInfo and @JsonSubTypes, Deserialize an Object of Concrete Subclass Without Base Class and Type Information
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM