Java泛型:如何为泛型类型类指定类类型?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/18940376/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Java Generics: How to specify a Class type for a generic typed class?
提问by Neel
I have a POJO specified as: MyClass<U>
, where U
is the generic type parameter.
I am trying to write a utility method which accepts a class reference Class<T>
and populates a map of type Map<String, T>
(accepts the map to populate).
我有一个 POJO 指定为:MyClass<U>
,U
泛型类型参数在哪里。我正在尝试编写一个实用程序方法,它接受类引用Class<T>
并填充类型Map<String, T>
的映射(接受要填充的映射)。
This method is implemented like:
该方法的实现方式如下:
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;
}
This compiles fine. In my caller, I attempt to populate a map with any MyClass
instance (irrespective of type) as the value. Hence I use the following code:
这编译得很好。在我的调用者中,我尝试使用任何MyClass
实例(不考虑类型)作为值填充映射。因此我使用以下代码:
// Loses type information
Map<String, MyClass<?>> m = new HashMap<>();
populateMap(m, MyClass.class);
This does not compile. Compilation error:
这不编译。编译错误:
The method
populate(Map<String,T>, Class<T>)
in the type ... is not applicable for the arguments(Map<String,MyClass<?>>, Class<MyClass>)
populate(Map<String,T>, Class<T>)
类型中的方法...不适用于参数(Map<String,MyClass<?>>, Class<MyClass>)
How can I fix this?
我怎样才能解决这个问题?
采纳答案by Paul Bellora
In this case it should be safe to do an unchecked cast to Class<MyClass<?>>
:
在这种情况下,对 进行未经检查的强制转换应该是安全的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);
This is a crufty solution, especially if you have many call sites like this, but there's no getting around the fact that class literals are parameterized with raw types, making their use as factories of parameterized types like MyClass<T>
inherently awkward.
这是一个笨拙的解决方案,特别是如果您有许多这样的调用站点,但无法回避这样一个事实,即类文字是用原始类型参数化的,这使得它们作为参数化类型的工厂使用MyClass<T>
本身就很尴尬。
A potentially cleaner solution would decouple populateMap
from the use of class literals:
一个可能更清洁的解决方案将与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);
As an aside I recommend a more flexible signature (see What is PECS (Producer Extends Consumer Super)?for more info):
顺便说一句,我建议使用更灵活的签名(有关更多信息,请参阅什么是 PECS(生产者扩展消费者超级)?):
static void populateMap(Map<String, ? super T> map, Parser<T> parser)
回答by aditsu quit because SE is EVIL
Because of type erasure, there's no such thing as a Class object representing a generic type, you can only use a raw type such as MyClass (with no generic parameter).
由于类型擦除,没有 Class 对象表示泛型类型,您只能使用原始类型,例如 MyClass(没有泛型参数)。
One possible workaround is exceptionally ugly: declare or cast m as Map<String, MyClass>
and prepare to face a tsunami of warnings and errors (errors can be fixed by casting, and become multiple warnings).
For a probably better workaround, refer to Paul's answer :)
一种可能的解决方法非常丑陋:将 m 声明或Map<String, MyClass>
强制转换为并准备面对警告和错误的海啸(错误可以通过强制转换来修复,并变成多个警告)。
有关可能更好的解决方法,请参阅保罗的回答:)