误解Java泛型

时间:2015-12-30 09:49:14

标签: java generics

我的代码中遇到了一个令人困惑的问题。

我有一个签名是

的方法
public <T extends Measure> void sendNewMeasure(Class<T> type, T measure);

在另一个类中,我有这个方法,它调用前一个方法:

public <T extends Measure> void onNewMeasure(NewMeasureEvent<T> event) {
    T measure = event.getMeasure();

    APIInterface.getInstance().sendNewMeasure(measure.getClass(), measure);
}

我得到的错误是Wrong argument type, found 'T', required <? extends com.blablabla.Measure>,但我不明白为什么,因为测量对象是T类型,它扩展了Measure。

有没有办法解决这个问题,最重要的是,为什么它不起作用?

谢谢!

编辑:

这是sendNewMeasure方法的实现:

public <T extends Measure> void sendNewMeasure(Class<T> type, T measure) {
    String measureType = measure.getJSONMeasureTypeName();

    List<T> measures = T.find(type, measure.timestamp, true, false);

    measures.add(measure);
    sendMeasures(siteId, sensorId, measureType, measures);
}

编辑2:这是查找方法签名,我无法改变:

public static <T> List<T> find(Class<T> type, int timestamp, boolean includeStart, boolean inclueEnd);

2 个答案:

答案 0 :(得分:5)

.getClass()的类型不是您认为的类型。 .getClass()返回Class<? extends |X|>,其中|X|是要调用的表达式的静态类型的擦除。在这种情况下,measure具有静态类型T,其具有擦除Measure,因此measure.getClass()具有类型Class<? extends Measure>,即类型参数是未知的子类型Measure.sendNewMeasure(measure.getClass(), measure)编译器无法保证measure(类型T)是此未知类型的实例。

基本上,问题是.getClass()丢失了类型信息。它的返回类型并不直接与它所调用的东西的类型相关联,因为Java类型系统无法表达&#34;它所调用的事物的真实运行时类型的概念&#34;。但是,直观地说,您知道使用当前签名.sendNewMeasure(measure.getClass(), measure)对方法的调用是类型安全的,因为measure.getClass()的类型应该是Class<U>,其中U是真实的运行时类measure,你知道measure显然是同一类型U的一个实例,所以存在一些类型参数,这个U(这是对T类型检查的调用不一定与.sendNewMeasure())相同,但问题是如何在不使用未经检查的操作的情况下说服编译器。

问题是measure.getClass()返回的类型与measure的类型没有充分关联。重新链接它们的一种方法是使用类使用类的方法.cast()将对象强制转换为其类型(总是会成功)。但是使用Class<? extends Measure>类型的表达式来做这件事并没有帮助,因为.cast()的结果是? extends Measure,它只会降级为Measure,所以我们仍然两种类型之间没有联系。我们需要该类型的真实姓名,而不是通配符,以便我们维护此链接。将通配符转换为命名类型的方法是 capture ,这需要将其传递给泛型方法:

public <T extends Measure> void onNewMeasure(NewMeasureEvent<T> event) {
    T measure = event.getMeasure();

    helper(measure.getClass(), measure);
}

private <U extends Measure> void helper(Class<U> clazz, Measure measure) {
    U castedMeasure = clazz.cast(measure);
    APIInterface.getInstance().sendNewMeasure(clazz, castedMeasure);
}

答案 1 :(得分:3)

来自Java API for

  

Class<?> getClass()
  [...]   实际结果类型为Class<? extends |X|>其中| X |是擦除调用getClass的表达式的静态类型。

因此measure.getClass()的结果不是Class<T>而是Class<? extends T> 你的签名应该是:

public <T extends Measure> void sendNewMeasure(Class<? extends T> type, T measure);