简体   繁体   English

误解Java泛型

[英]Misunderstanding Java generics

I am facing a confusing issue in my code. 我的代码中遇到了一个令人困惑的问题。

I have one method which signature is 我有一个签名方法

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

In another class, I have this method, which calls the previous one : 在另一个类中,我有这个方法,它调用前一个:

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

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

The error I get is Wrong argument type, found 'T', required <? extends com.blablabla.Measure> 我得到的Wrong argument type, found 'T', required <? extends com.blablabla.Measure>Wrong argument type, found 'T', required <? extends com.blablabla.Measure> Wrong argument type, found 'T', required <? extends com.blablabla.Measure> but I don't get why, as the measure object is of type T which extends Measure. Wrong argument type, found 'T', required <? extends com.blablabla.Measure>但我不明白为什么,因为测量对象是T类型,它扩展了Measure。

Is there any way to fix this, and most importantly, why is it not working ? 有没有办法解决这个问题,最重要的是,为什么它不起作用?

Thanks ! 谢谢 !

EDIT : 编辑:

This is the implementation of the sendNewMeasure method : 这是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);
}

EDIT 2 : And this is the find method signature, the one I cannot change: 编辑2:这是find方法签名,我无法改变:

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

The type of .getClass() is not what you think it is. .getClass()的类型不是你想象的那样。 .getClass() returns Class<? extends |X|> .getClass()返回Class<? extends |X|> Class<? extends |X|> , where |X| Class<? extends |X|> ,其中|X| is the erasure of the static type of the expression it's called on. 是它所调用的表达式的静态类型的擦除。 In this case, measure has static type T , which has erasure Measure , so measure.getClass() has type Class<? extends Measure> 在这种情况下, measure有静态类型T ,它有擦除Measure ,所以measure.getClass()有类型Class<? extends Measure> Class<? extends Measure> , ie the type parameter is an unknown subtype of Measure , and .sendNewMeasure(measure.getClass(), measure) there is no way the compiler can guarantee that measure (of type T ) is an instance of this unknown type. Class<? extends Measure> ,即类型参数是Measure的未知子类型,而.sendNewMeasure(measure.getClass(), measure)编译器无法保证measure (类型T )是此未知类型的实例。

Basically, the problem is that .getClass() loses type information. 基本上,问题是.getClass()丢失了类型信息。 Its return type is not directly linked to the type of the thing it is called on, because the Java type system cannot express the concept of "the real runtime type of the thing it's called on". 它的返回类型并不直接与它所调用的东西的类型相关联,因为Java类型系统不能表达“它被调用的东西的真实运行时类型”的概念。 However, intuitively, you know that the call to the method with the current signature .sendNewMeasure(measure.getClass(), measure) is type-safe, because the type of measure.getClass() should really be Class<U> where U is the real runtime class of measure , and you know that measure is obviously an instance of that same type U , so there exists some type argument, this U (which is not necessarily the same as T ) for which the call to .sendNewMeasure() type-checks, but the question is how to convince the compiler of this without using unchecked operations. 然而,直觉,你知道,调用与当前签名的方法.sendNewMeasure(measure.getClass(), measure)是类型安全的,因为类型measure.getClass()确实应该Class<U>其中U是真正的运行时measure类,你知道该measure显然是同一类型U一个实例,因此存在一些类型参数,这个U (不一定与T相同)调用.sendNewMeasure()类型检查,但问题是如何在不使用未经检查的操作的情况下说服编译器。

The problem is that the type returned by measure.getClass() is not sufficiently linked to the type of measure . 问题是measure.getClass()返回的类型没有充分链接到measure类型。 One way to re-link them is to use the class to cast the object to its type (which will always succeed), using the class's method .cast() . 重新链接它们的一种方法是使用类将方法转换为类型(总是会成功),使用类的方法.cast() But it doesn't help to do this with an expression of type Class<? extends Measure> 但是使用Class<? extends Measure>类型的表达式来做这件事并没有用Class<? extends Measure> Class<? extends Measure> , because the resulting of .cast() is ? extends Measure Class<? extends Measure> ,因为.cast()? extends Measure ? extends Measure which just degrades to Measure , so we still don't have a link between the two types. ? extends Measure刚刚降级的Measure ? extends MeasureMeasure ,因此我们仍然没有这两种类型之间的链接。 We need a real name for the type, not a wildcard, for us to maintain this link. 我们需要该类型的真实姓名,而不是通配符,以便我们维护此链接。 The way to turn a wildcard into a named type is capture , which requires passing it into a generic method: 将通配符转换为命名类型的方法是捕获 ,这需要将其传递给泛型方法:

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);
}

From Java API for 来自Java API for

Class<?> getClass()
[...] The actual result type is Class<? extends |X|> [...]实际结果类型是Class<? extends |X|> Class<? extends |X|> where |X| Class<? extends |X|> where | X | is the erasure of the static type of the expression on which getClass is called. 是调用getClass的表达式的静态类型的擦除。

So the result of measure.getClass() is not Class<T> but Class<? extends T> 因此, measure.getClass()的结果不是Class<T>而是Class<? extends T> Class<? extends T>
Your signature should be: 你的签名应该是:

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

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

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM