Java Generics:如何为泛型类指定Class类型?

时间:2013-09-22 04:38:31

标签: java generics types

我将POJO指定为:MyClass<U>,其中U是泛型类型参数。 我正在尝试编写一个实用程序方法,它接受类引用Class<T>并填充类型Map<String, T>的地图(接受填充的地图)。

此方法的实现方式如下:

static void populateMap(Map<String, T> map, Class<T> type) {

    ...

    // Parses into the specified type and returns an object of that type.
    T obj = parse(..., type);
    map.put (key, obj);
    ...

    return map;
}

编译好。在我的调用者中,我尝试使用任何MyClass实例(无论类型)填充地图作为值。因此我使用以下代码:

// Loses type information
Map<String, MyClass<?>> m = new HashMap<>();
populateMap(m, MyClass.class);

这不编译。编译错误:

  

类型...中的方法populate(Map<String,T>, Class<T>)不适用于参数(Map<String,MyClass<?>>, Class<MyClass>)

我该如何解决这个问题?

2 个答案:

答案 0 :(得分:4)

在这种情况下,对Class<MyClass<?>>进行未经检查的强制转换应该是安全的:

// This is okay because we're switching to a type with an unbounded wildcard -
// the behaviors of Class.newInstance and Class.cast are still safe.
@SuppressWarnings("unchecked") 
Class<MyClass<?>> classWithNarrowedType =
        (Class<MyClass<?>>)(Class<?>)MyClass.class;
populateMap(m, classWithNarrowedType);

这是一个非常简单的解决方案,特别是如果你有很多像这样的调用网站,但是没有解决类文字用原始类型参数化的事实,使它们作为参数化类型的工厂使用,如MyClass<T>本身别扭。

一个可能更清晰的解决方案会使populateMap与类文字的使用脱钩:

interface Parser<T> {

    T parse();
}

static void populateMap(Map<String, T> map, Parser<T> parser) { ... }

...

Map<String, MyClass<?>> m = new HashMap<>();
Parser<MyClass<?>> myClassParser = new Parser<MyClass<?>>() {
    @Override
    public MyClass<?> parse() {
        return parse(..., MyClass.class);
    }
};
populateMap(m, myClassParser);

另外,我建议使用更灵活的签名(有关详细信息,请参阅What is PECS (Producer Extends Consumer Super)?):

static void populateMap(Map<String, ? super T> map, Parser<T> parser)

答案 1 :(得分:2)

由于类型擦除,没有表示泛型类型的Class对象,您只能使用MyClass等原始类型(没有泛型参数)。

一种可能的解决方法非常难看:声明或投射m为Map<String, MyClass>并准备面对警告和错误的海啸(错误可以通过施放来修复,并成为多个警告)。
有关可能更好的解决方法,请参阅Paul的回答:)

另见Getting a java.lang.Class with generics