1

通过使用泛型,我们在编译期间检测到任何可能的情况。例如,

List<String> list = new ArrayList<String>();
//list.add(new Integer(45)); This will cause compilation error.
list.add("car");
list.add("bus");
list.add("bike");
String vehicle = list.get(0); //compiler-generated cast

当我们在 Java 1.5 之前使用原始类型而不是泛型时,它需要显式转换。例如,

List list2 = new ArrayList();
    list.add("car");
    list.add("bus");
    list.add("bike");
    String vehicle = (String)list.get(0); //explicit casting is necessary

但是对于泛型,会发生类型擦除。即类型信息在运行时丢失。如果是这样,JVM 如何知道它在运行时检索的对象类型是字符串对象还是人员对象(上面的编译器生成的转换)。但这对泛型有效,这可能会导致运行时错误。

List<Object> test = new ArrayList<Object>();
            test.add("hello");
            test.add(new Integer(34));

最后,Joshua Bloch 在第 115 页(第 23 项,有效 java)中提到,它 Set<Object>是表示可以包含任何类型对象的集合的参数化类型, Set<?>是表示只能包含某些未知类型对象的集合的通配符类型,并且Set是原始类型,它选择退出泛型类型系统。

我明白他上面所说的意思。一些澄清会有所帮助

4

4 回答 4

5

当从泛型方法中检索项目时,编译器会插入强制转换操作;这是 JVM 知道将结果list.get(0)视为String. 这就是为什么堆污染(将错误类型的对象插入到泛型集合中)会导致ClassCastException运行时出现错误。

关于通配符:

  • Set<Object>的泛型类型正是Object. 您可以从中插入和检索Object实例,但不能将 a 传递Set<Integer>给期望 a 的方法Set<Object>,因为该方法可能计划将非Integer对象添加到集合中。
  • Set<?>具有未指定的泛型类型。一个方法可以从中检索任何东西作为一个Object(因为一切都是一个),并且可以像或Object一样调用它的通用方法,但它不能向集合中添加任何东西。hashCodetoString
  • Set,正如您所提到的,是原始类型,不应在新代码中使用。
于 2013-09-04T03:50:15.913 回答
1

我不太确定,但我理解的类型信息在运行时丢失是在运行时没有办法知道集合是某种特定类型的。如果将 a 添加String到集合中,它将是String唯一的,但集合并不强制所有元素都应该是类型String

于 2013-09-04T03:54:58.410 回答
0

Java 编译器将泛型实现为称为擦除的前端转换。类型擦除适用于泛型的使用。当使用泛型时,它们被转换为编译时检查和运行时类型转换

由于类型擦除机制,此代码:

List<String> a = new ArrayList<String>();
a.add("foo");
String x = a.get(0);

被编译成这个:

List a = new ArrayList();
a.add("foo");
String x = (String) a.get(0);

请注意在类型擦除后插入到编译的编译代码中的额外转换。

PS:@chrylis 已经为您的第二部分问题提供了很好的解释。

于 2013-09-04T04:07:09.933 回答
0

好吧,这里的这个 stackoverflow 问题可以帮助你。

Eclipse 可能正在使用此方法来查找类中的字段及其泛型类型(如果有)。请看一看。

于 2013-09-04T04:16:14.127 回答