返回具有泛型类型的Class实例

时间:2015-04-15 20:58:59

标签: java generics type-erasure generic-type-argument

这是一个简单的示例,演示了我遇到的与类型擦除相关的问题。我有一个这样的课:

public abstract class AbstractHandler<T> {

    ...
    public abstract Class<T> handledType();
}

然后我有了这个实现:

public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {

    @Override
    public Class<Map<String, List<Thing>>> handledType() {
        //what do I return here?!
    }
}

我无法返回Map<String, List<Thing>>.class,因为这在句法上甚至没有效果。我尝试将子类型中的泛型类型参数设为HashMap<String, List<Thing>>,然后返回new HashMap<String, List<Thing>>().getClass(),但这不起作用,因为Class<T>#getClass()的返回类型为Class<? extends T>。我从Guava看了TypeTokengetRawType方法似乎很有希望,但它返回Class<? super T>

我暂时有一个解决方法,如下所示:

public class ThingListMap {
    private Map<String, List<Thing>> thingListMap;

    ...
}

我只使用ThingListMap作为泛型类型参数。

另一种可能的解决方法是执行强制转换:

public Class<Map<String, List<Thing>>> handledType() {
    return (Class<Map<String, List<Thing>>>) new HashMap<String, List<Thing>>().getClass();
}

有更优雅的方法吗?

编辑:为了回答其中一个答案,我无法更改handledType方法的签名,因为我不拥有或控制其来源。

2 个答案:

答案 0 :(得分:7)

出于某种原因,Java不允许您将Map.class直接投射到Class<Map<String, List<Thing>>>。无论如何,这是一个未经检查的演员。

但将它投两次是合法的,首先是Class<?>,然后是Class<Map<String, List<Thing>>>

return (Class<Map<String, List<Thing>>>) (Class<?>) Map.class;

作为未经检查的演员,您可能想要添加@SuppressWarnings("unchecked")

答案 1 :(得分:4)

番石榴的方法是使用TypeToken。你的班级将成为

public abstract class AbstractHandler<T> {
    public TypeToken<T> handledType();
}

public class ConcreteHandler extends AbstractHandler<Map<String, List<Thing>>> {
    @Override
    public TypeToken<Map<String, List<Thing>>> handledType() {
        return new TypeToken<Map<String, List<Thing>>>() {};
    }
}