我有一个返回给定类型的方法:
T foo(Class<T> valueType) {...};
String s = foo(Java.lang.String.class);
我正在尝试将泛型类型作为我的类发送,但出现编译器错误。例如,假设我想返回一个字符串的 ArrayList:
ArrayList<String> list = foot(ArrayList<String>.class)
参数“String”给出错误。无论如何我可以指定要返回的泛型类型吗?
运行时class
字段值不依赖于你应用的泛型类型,这种语法是非法的。更多关于这个here。
假设您在这里只关心静态类型,这个技巧可能很有用:
@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
您应该使用TypeToken
Sean Patrick Floyd 提到的技术。
Type Erasure 抬起了丑陋的脑袋。本质上,Java 对通用<…>
子句进行编译时检查,然后将它们从运行时对象中删除,从而永远丢失信息。恶心,嗯?由于.class
元对象在运行时被引用,它们也遭受擦除。
ArrayList<String>.class
在编译时被擦除,为ArrayList.class
.
如果你想要泛型的类型安全,你必须传入两个参数,例如
ArrayList<String> foo = foot(ArrayList.class, String.class)
这对你有用吗(已编辑)?
ArrayList list = foot(ArrayList.class)
只需转换方法的输入或输出:
ArrayList<String> list = foot((Class<ArrayList<String>>)(Class<?>)ArrayList.class);
或者
ArrayList<String> list = (ArrayList<String>)foot(ArrayList.class);
基本上,Class
该类不适用于泛型,因为它代表运行时事物,而泛型则在编译时工作。在运行时,程序中只有一个类对象ArrayList
。即使你称它为Class<ArrayList<String>>
or Class<ArrayList<Integer>>
or Class<ArrayList>
,它仍然是同一个对象。那么它应该是什么类型的呢?没有适用于所有事情的简单答案。
Java 语言决定类文字ArrayList.class
应该只有 type Class<ArrayList>
。但是当你想要一个类型的表达式时,这会导致问题Class<ArrayList<String>>
,所以你必须改变类型。