类型.getClass()
不是您想的那样。.getClass()
返回Class extends |X|>
,其中|X|
是对其调用的表达式的静态类型的擦除。在这种情况下,measure
具有静态类型T
,具有擦除Measure
,所以measure.getClass()
具有type Class extends Measure>
,即具有type ,即type参数是的未知子类型Measure
,并且.sendNewMeasure(measure.getClass(), measure)
编译器无法保证measure
(of typeT
)是该未知类型的实例。
基本上,问题是.getClass()
丢失类型信息。它的返回类型没有直接链接到被调用的事物的类型,因为Java类型系统无法表达“被调用的事物的真实运行时类型”的概念。但是,从直观上讲,您知道具有当前签名的方法的调用.sendNewMeasure(measure.getClass(), measure)
是类型安全的,因为的类型measure.getClass()
实际上应该是的实际运行时类是Class
where ,并且您知道这显然是同一类型的实例,因此存在某种类型的参数,此参数(不一定与相同)是对其进行调用的U
measure
measure
U
U
T
.sendNewMeasure()
类型检查的,但是问题是如何在不使用未经检查的操作的情况下说服编译器。
问题是所返回的类型measure.getClass()
与的类型未充分链接measure
。重新链接它们的一种方法是使用类,使用类的方法将对象转换为其类型(将始终成功).cast()
。但它并不能帮助与类型的表达式要做到这一点Class extends Measure>
,因为导致的.cast()
就是? extends Measure
刚刚降级到Measure
,所以我们还没有这两种类型之间的联系。我们需要类型的真实名称,而不是通配符,以便我们维护此链接。将通配符转换为命名类型的方法是capture,这需要将其传递给通用方法:
publicvoid onNewMeasure(NewMeasureEvent event) { T measure = event.getMeasure(); helper(measure.getClass(), measure); } private void helper(Class clazz, Measure measure) { U castedMeasure = clazz.cast(measure); APIInterface.getInstance().sendNewMeasure(clazz, castedMeasure); }