通常,我看到人们这样使用类文字:
Class<Foo> cls = Foo.class;
但是如果类型是泛型的,比如List呢?这很好,但有一个警告,因为List应该参数化:
Class<List> cls = List.class
那么为什么不添加一个<?>?这将导致类型不匹配错误:
Class<List<?>> cls = List.class
我想这样做是可行的,但这只是一个简单的语法错误:
Class<List<Foo>> cls = List<Foo>.class
我怎么能得到一个类<列表<Foo>>静态,例如使用类文字?
在第一个例子Class<List> cls = List. Class中,我可以使用@SuppressWarnings(“unchecked”)来消除因非参数化使用List而引起的警告,但我宁愿不这样做。
有什么建议吗?
你可以使用一个helper方法来去除整个类中的@SuppressWarnings("unchecked")。
@SuppressWarnings("unchecked")
private static <T> Class<T> generify(Class<?> cls) {
return (Class<T>)cls;
}
然后你可以写
Class<List<Foo>> cls = generify(List.class);
其他用法示例包括
Class<Map<String, Integer>> cls;
cls = generify(Map.class);
cls = TheClass.<Map<String, Integer>>generify(Map.class);
funWithTypeParam(generify(Map.class));
public void funWithTypeParam(Class<Map<String, Integer>> cls) {
}
然而,由于它很少真正有用,而且该方法的使用不利于编译器的类型检查,所以我不建议在它可以公开访问的地方实现它。
你不能由于类型擦除。
Java泛型只不过是对象强制转换的语法糖。为了演示:
List<Integer> list1 = new ArrayList<Integer>();
List<String> list2 = (List<String>)list1;
list2.add("foo"); // perfectly legal
在运行时保留泛型类型信息的唯一实例是通过反射询问类的成员时使用Field.getGenericType()。
这就是Object.getClass()有这个签名的原因:
public final native Class<?> getClass();
重要的部分是Class<?>。
换句话说,摘自Java泛型常见问题解答:
Why is there no class literal for concrete parameterized types?
Because parameterized type has no exact runtime type representation.
A class literal denotes a Class
object that represents a given type.
For instance, the class literal
String.class denotes the Class
object that represents the type
String and is identical to the
Class object that is returned when
method getClass is invoked on a
String object. A class literal can
be used for runtime type checks and
for reflection.
Parameterized types lose their type
arguments when they are translated to
byte code during compilation in a
process called type erasure . As a
side effect of type erasure, all
instantiations of a generic type share
the same runtime representation,
namely that of the corresponding raw
type . In other words, parameterized
types do not have type representation
of their own. Consequently, there is
no point in forming class literals
such as List<String>.class ,
List<Long>.class and List<?>.class
, since no such Class objects exist.
Only the raw type List has a Class
object that represents its runtime
type. It is referred to as
List.class.
为了阐明cletus的答案,在运行时删除所有泛型类型的记录。泛型只在编译器中处理,用于提供额外的类型安全。它们实际上只是允许编译器在适当的位置插入类型转换的简写。例如,以前你必须做以下事情:
List x = new ArrayList();
x.add(new SomeClass());
Iterator i = x.iterator();
SomeClass z = (SomeClass) i.next();
就变成了
List<SomeClass> x = new ArrayList<SomeClass>();
x.add(new SomeClass());
Iterator<SomeClass> i = x.iterator();
SomeClass z = i.next();
这允许编译器在编译时检查代码,但在运行时它看起来仍然像第一个示例。
参数化类型没有Class字面量,但是有正确定义这些类型的Type对象。
看到java.lang.reflect.ParameterizedType
——http://java.sun.com/j2se/1.5.0/docs/api/java/lang/reflect/ParameterizedType.html
谷歌的Gson库定义了一个TypeToken类,允许简单地生成参数化类型,并使用它以通用友好的方式规范具有复杂参数化类型的json对象。在你的例子中,你可以用:
Type typeOfListOfFoo = new TypeToken<List<Foo>>(){}.getType()
我打算发布到TypeToken和Gson类javadoc的链接,但堆栈溢出不会让我发布多个链接,因为我是一个新用户,你可以很容易地使用谷歌搜索找到它们