我有一个这样的签名方法:
private Map m(Map data, Class type)
当我这样调用时,它工作正常:
Map abc= null;
m(abc, String.class);
但是当我的参数T是一个Set时它不起作用:
Map> abc= null;
m(abc, Set.class);
有没有办法让它发挥作用?
解决方法:
你将不得不做一些非常难看的事情,使用这样的未经检查的演员:
m(abc, (Class>) (Class>) Set.class);
这归结为类型擦除.在运行时Class< Set< String>>与Class< Set< Integer>>相同,因为我们没有具体的泛型,所以没有办法知道你拥有的是一组“字符串集”与一个类的类“整数集”.
前段时间我问了一个相关的问题,还应该给你一些指示:
国际海事组织的这种混乱是因为仿制药在事后被拴上了,而且没有具体化.当编译器告诉你泛型类型不匹配时,我认为这是语言的失败,但你甚至没有简单的方法来表示特定的类型.例如,在您的情况下,您最终会遇到编译时错误:
m(abc, Set.class);
^
required: Map,Class
found: Map>,Class
reason: inferred type does not conform to equality constraint(s)
inferred: Set
equality constraints(s): Set,Set
where T is a type-variable:
T extends Object declared in method m(Map,Class)
现在,你完全有理由认为“哦,我应该使用Set< String> .class then”,但这不合法.这是语言中泛型实现的抽象泄漏,特别是它们受到类型擦除的影响.从语义上讲,Set< String> .class表示一组字符串的运行时类实例.但实际上在运行时我们无法表示一组字符串的运行时类,因为它与包含任何其他类型的对象的集合无法区分.
因此,我们有一个与编译时语义不一致的运行时语义,并且知道为什么Set< T> .class不合法需要知道泛型在运行时没有被统一.这种不匹配导致了像这样的奇怪的变通方法.
问题的复杂性在于,类实例最终也与类型标记混为一谈.由于您无法在运行时访问泛型参数的类型,因此解决方法是传入Class< T>类型的参数.从表面上看,这非常有用,因为你可以传递像String.class这样的东西(类型为Class< String>)并且编译器很高兴.但是这种方法在你的情况下会崩溃:如果T本身代表一个具有自己的泛型类型参数的类型怎么办?现在使用类作为类型标记是没有用的,因为没有办法区分Class< Set< String>>和类< Set>因为从根本上说,它们在运行时都是Set.class,因此共享同一个类实例.因此,使用类作为运行时类型令牌的IMO不能作为通用解决方案.
由于语言的这个缺点,有一些库使得检索泛型类型信息变得非常容易.此外,他们还提供类更好地表示某事物的“类型”:
标签:java,generics
来源: https://codeday.me/bug/20190519/1136995.html