[英]How can I use a Class object as a parameterized type?
So Google turns up a lot of questions about getting the .class
of a parameterized type, but I'm trying to go the other way. 因此Google提出了许多有关获取参数化类型的.class
的问题,但我正尝试采用另一种方法。
I have a list of Classes, and I need to make a map that uses the Class
as a key, and an ArrayList
of objects of type Class as the value. 我有一个Classes列表,我需要制作一个使用Class
作为键的映射,并使用Class
类型的对象的ArrayList
作为值。 Something like this: 像这样:
Class[] classes = getArrayOfClasses();
HashMap<Class, ArrayList<?>> map = new HashMap<Class, ArrayList<?>>();
for(Class c : classes) {
map.put(c, new ArrayList<c>()); // here is where the problem is
}
The problem of course is that it needs a parameterized type, not a class. 当然,问题在于它需要一个参数化类型,而不是一个类。 One possible workaround is to just use map.put(c, new ArrayList<Object>())
, but then I have to know the type and cast every object I pull. 一种可能的解决方法是只使用map.put(c, new ArrayList<Object>())
,但是随后我必须知道类型并map.put(c, new ArrayList<Object>())
我拉出的每个对象。
MyClass myObj = (MyClass) map.get(MyClass.class).get(0);
I also tried making an initialization function like this: 我还尝试过这样的初始化函数:
private <T> ArrayList<T> makeArrayList(Class<T> c) {
return new ArrayList<T>();
}
This had the syntax that I hoped would work, but it still left me with an ArrayList
of Object
that had to be cast. 它具有我希望可以使用的语法,但是仍然给我留下了必须转换的Object
ArrayList
。
So is there a way I can just make the ArrayList
parameterized with the Class's type? 那么有什么方法可以使ArrayList
的类类型成为参数?
Unfortunately, due to the nature of Java's generics (they work by erasure), generics aren't available at runtime. 不幸的是,由于Java泛型的本质(它们通过擦除工作),泛型在运行时不可用。
This means that there is no real way to make map.put(c, new ArrayList<c>());
这意味着没有真正的方法来制作map.put(c, new ArrayList<c>());
work. 工作。
I recommend doing this instead: Wrap your list in a dedicated object, and give that object the following accessor method: 我建议改为这样做:将列表包装在专用对象中,并为该对象提供以下访问器方法:
public <T> getList(Class<T> key) {
List<?> list = map.get(key);
return (List<T>) list;
}
This is going to produce a warning, but as long as the map was constructed properly, you'll be ok. 这将产生警告,但是只要正确构建了地图,您就可以了。
Alternatively, you can do a run time check of all objects to make sure the type match up. 另外,您可以对所有对象进行运行时检查,以确保类型匹配。
public <T> getList(Class<T> key) {
List<?> list = map.get(key);
for(Object o : list){
assert(key.isInstance(o));
}
return (List<T>) list;
}
There is absolutely no difference in the compiled bytecode between: 编译后的字节码之间绝对没有区别:
new ArrayList();
new ArrayList<T>();
new ArrayList<String>();
new ArrayList<Integer>();
The type parameter has no effect on the compiled code; type参数对编译后的代码无效; it only affects the compiler's type-checking. 它仅影响编译器的类型检查。 So, if the type parameter is not available at compile-time, it is useless, as compile-time is the only time where it could be useful. 因此,如果类型参数在编译时不可用,则它是无用的,因为编译时是唯一有用的时间。
You should just write new ArrayList<Object>()
or new ArrayList<Integer>()
even new ArrayList<CompletelyBogusUnrelatedClass>()
; 您应该只写new ArrayList<Object>()
或new ArrayList<Integer>()
甚至new ArrayList<CompletelyBogusUnrelatedClass>()
; it doesn't matter, because all of them are compatible with ArrayList<?>
, which is the value type of your map. 没关系,因为它们都与ArrayList<?>
兼容,后者是地图的值类型。
As for your method that creates and returns an ArrayList
, it should just be written like this: 至于创建并返回ArrayList
,应该这样编写:
private static <T> ArrayList<T> makeArrayList() {
return new ArrayList<T>();
}
(That's right, this method returns an ArrayList
of whatever element type you want without even knowing what that type is ! This is a clear demonstration that the type parameter is not needed at runtime.) (是的,此方法返回所需的任何元素类型的ArrayList
甚至不知道该类型是什么 !这清楚地证明了在运行时不需要type参数。)
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.