因此Google提出了很多关于获取参数化类型的.class
的问题,但我正试图采用其他方式。
我有一个类列表,我需要创建一个使用Class
作为键的映射,以及一个类型为Class的ArrayList
对象作为值。像这样:
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
}
问题当然是它需要参数化类型,而不是类。一种可能的解决方法是只使用map.put(c, new ArrayList<Object>())
,但是我必须知道类型并转换我拉的每个对象。
MyClass myObj = (MyClass) map.get(MyClass.class).get(0);
我也尝试过这样的初始化函数:
private <T> ArrayList<T> makeArrayList(Class<T> c) {
return new ArrayList<T>();
}
这有我希望可以使用的语法,但它仍然留给我一个ArrayList
Object
必须被投射。
那么我有没有办法让ArrayList
参数化为类的类型?
答案 0 :(得分:2)
不幸的是,由于Java的泛型(它们通过擦除工作)的性质,泛型在运行时是不可用的。
这意味着没有真正的方法让map.put(c, new ArrayList<c>());
工作。
我建议改为:将列表包装在专用对象中,并为该对象提供以下访问方法:
public <T> getList(Class<T> key) {
List<?> list = map.get(key);
return (List<T>) list;
}
这会产生警告,但只要地图构造得当,你就可以了。
或者,您可以对所有对象进行运行时检查,以确保类型匹配。
public <T> getList(Class<T> key) {
List<?> list = map.get(key);
for(Object o : list){
assert(key.isInstance(o));
}
return (List<T>) list;
}
答案 1 :(得分:1)
编译后的字节码绝对没有区别:
new ArrayList();
new ArrayList<T>();
new ArrayList<String>();
new ArrayList<Integer>();
type参数对编译的代码没有影响;它只影响编译器的类型检查。因此,如果类型参数在编译时不可用,则它是无用的,因为编译时是唯一有用的时间。
你应该写new ArrayList<Object>()
或new ArrayList<Integer>()
甚至new ArrayList<CompletelyBogusUnrelatedClass>()
;它并不重要,因为它们都与ArrayList<?>
兼容,ArrayList
是地图的值类型。
至于创建并返回private static <T> ArrayList<T> makeArrayList() {
return new ArrayList<T>();
}
的方法,它应该像这样写:
ArrayList
(那是对的,这个方法返回你想要的任何元素类型的{{1}} ,甚至不知道那个类型是什么!这清楚地证明了类型参数在运行时不需要。)