2013-09-22 448 views
5

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

实现此方法是这样的:

​​

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

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

这不会编译。编辑错误:

The method populate(Map<String,T>, Class<T>) in the type ... is not applicable for the arguments (Map<String,MyClass<?>>, Class<MyClass>)

我该如何解决这个问题?

+0

别你认为在声明地图的时候你需要实际的类型而不是泛型通配符? –

+0

你应该在这个类型的地方使用T。你可以粘贴完整的课程吗? – Lokesh

+0

@JunedAhsan不,我应该能够创建一个包含任何类型的MyClass实例的地图。这就是我指定通配符的原因。 – Neel

回答

3

在这种情况下,它应该是安全的做一个未经检查的强制转换为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) 
2

由于类型擦除,不存在表示泛型类型的类对象,所以只能使用诸如MyClass之类的原始类型(没有泛型参数)。

一个可能的解决方法是格外丑陋的:声明或铸造m作为Map<String, MyClass>并准备面对海啸的警告和错误(错误可以通过投射修复,并成为多个警告)。
对于一个可能更好的解决方法,是指保罗的答案:)

另见Getting a java.lang.Class with generics

+0

“你只能使用像MyClass这样的原始类型”为什么不使用像MyClass 这样的无界通配符参数化类型?顺便说一下,这是一种具体化的类型。 – newacct

+0

@newacct我不认为你可以调用'MyClass '一个具体化的类型;即使泛型被通用化了,它也有一个通配符。至于为什么你只能得到一个原始类型的类,而不是通配符的类(它可能有相同的结果)......这就是他们设计语言的方式。但正如Paul Bellora所表明的那样,将这个班级转换成所需的类型是一个窍门。 – aditsu

+0

我的意思是“可定义类型”http://docs.oracle.com/javase/specs/jls/se7/html/jls-4.html#jls-4.7“... *这是一种参数化类型,其中所有类型参数是无界通配符“。但是,我认为这只是他们设计的方式。 – newacct