我有一个返回给定类型的方法:
T foo(Class<T> valueType) {...};
String s = foo(Java.lang.String.class);
我正在尝试将泛型类型作为我的类发送,但是会出现编译器错误。例如,假设我想返回一个字符串的ArrayList:
ArrayList<String> list = foot(ArrayList<String>.class)
参数“String”给出错误。无论如何我可以指定要返回的泛型类型吗?
答案 0 :(得分:1)
运行时class
字段值不依赖于您应用的泛型类型,并且此语法是非法的。有关here的更多信息。
答案 1 :(得分:0)
这对你有用(编辑过)吗?
ArrayList list = foot(ArrayList.class)
答案 2 :(得分:0)
只需转换方法的输入或输出:
ArrayList<String> list = foot((Class<ArrayList<String>>)(Class<?>)ArrayList.class);
或
ArrayList<String> list = (ArrayList<String>)foot(ArrayList.class);
基本上,Class
类与泛型不兼容,因为它表示运行时事物,而泛型在编译时工作。在运行时,程序中只有ArrayList
的一个类对象。即使您将其称为Class<ArrayList<String>>
或Class<ArrayList<Integer>>
或Class<ArrayList>
,它仍然是同一个对象。那应该是什么类型的?没有简单的答案适用于所有事情。
Java语言决定类文字ArrayList.class
应该只有Class<ArrayList>
类型。但是当你想要一个Class<ArrayList<String>>
类型的表达式时,这会导致问题,所以你必须弯曲类型。
答案 3 :(得分:0)
假设您只关心静态类型,这个技巧可能会有用:
@SuppressWarnings("unchecked")
public static <T>
Class<T> appropriateClass(T... args) {
return (Class<T>) args.getClass().getComponentType();
}
Class<ArrayList<String>> c = appropriateClass();
ArrayList<String> list = foo(c);
其实我并不为这个伎俩感到骄傲。但你可能想尝试一下。
如果你测试它:
System.out.println(c); // prints "class java.util.ArrayList"
所以它等同于像(Class<ArrayList<String>>) (Class<?>) ArrayList.class
这样丑陋的演员。
如果您确实需要在运行时为ArrayList<String>
和ArrayList
添加不同的令牌,则应使用Sean Patrick Floyd提到的TypeToken
技术。
答案 4 :(得分:0)
类型Erasure看起来很难看。从本质上讲,Java会对通用<…>
子句进行编译时检查,然后从运行时对象中删除,永远丢失信息。讨厌,嗯?由于.class
元对象在运行时被引用,因此它们也会遭受擦除。
ArrayList<String>.class
在编译时被删除,为ArrayList.class
。
如果您希望使用泛型类型安全,则必须传入两个参数,例如
ArrayList<String> foo = foot(ArrayList.class, String.class)