ShapeSaver.class
的类型是
Class<ShapeSaver>
。当将其传递给
genericsHell()
时,编译器需要检查
Class<ShapeSaver>
是否是
Class<? extends ShapeProcessor<?>
的子类型,这可以归结为
ShapeSaver
是否是
ShapeProcessor<?>
的子类型。子类型关系不成立,方法调用失败。
对于@Bohemian的解决方案应该也是如此。在
T
推断后,子类型检查发生在
T
的限制检查中。它也应该失败。这似乎是一个编译器错误,它以某种方式错误地解释了
Raw
可分配给
Raw<X>
的规则,就好像
Raw
是
Raw<X>
的子类型。另请参见
Enum.valueOf throws a warning for unknown type of class that extends Enum?
你问题的一个简单解决方案是声明:
void genericsHell(Class<? extends ShapeProcessor> a)
确实,ShapeSaver
是ShapeProcessor
的子类型,并且调用可以编译。
这不仅仅是一个解决方法。有一个很好的理由。严格来说,对于任何Class<X>
,X
必须是原始类型。例如,Class<List>
是可以的,Class<List<String>>
则不行。因为真正表示List<string>
的类不存在,只有一个代表List
的类。
忽略那些警告你不应该使用原始类型的建议。考虑到Java类型系统的设计,我们有时必须使用原始类型。即使Java的核心API(Object.getClass()
)也使用原始类型。
你可能想做像这样的事情:
genericsHell(ShapeSaver<Circle>.class);
很遗憾,这是不被允许的。Java本可以引入类型字面量和泛型一起使用,但它没有这么做,这给很多库带来了很多问题。java.lang.reflect.Type
非常混乱且无法使用。每个库都必须引入自己的类型系统表示来解决这个问题。
你可以借用一个,例如从Guice中借用,然后就能够...
genericsHell( new TypeLiteral< ShapeSaver<Circle> >(){} )
------------------
(学会在阅读代码时跳过ShaveSaver<Circle>
周围的垃圾)
genericsHell()
方法体中,你将拥有完整的类型信息,而不仅仅是类。
ShapeSaver
分配给通用的ShapeProcessor
可能会导致运行时异常。但我不确定具体细节。 - OverZealous.class
导致信息丢失的类似问题。 - Paul Bellora