我将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>)
我该如何解决这个问题?
答案 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的回答:)