通过使用泛型,我们可以在编译过程中检测到任何可能的情况。例如,
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
当我们在Java1.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如何知道它在运行时检索的对象类型,不管是字符串对象还是person对象(上面生成的编译器)。但是这对于泛型是有效的,这可能会导致运行时错误。
List<Object> test = new ArrayList<Object>();
test.add("hello");
test.add(new Integer(34));
最后,约书亚·布洛赫在第115页(第23项,有效java)中提到,Set<Object>
是参数化类型,表示可以包含任何类型对象的集合;Set<?>
是表示只能包含某些未知类型对象的集合的通配符类型,而Set
是原始类型,选择退出泛型类型系统。
我明白他所说的话是甚麽意思。一些澄清会有帮助。
发布于 2013-09-04 03:50:15
编译器在从泛型方法检索项时插入强制转换操作;这是JVM知道将list.get(0)
的结果作为String
处理的唯一方法。这就是为什么堆污染(将错误的对象类型插入到泛型集合中)在运行时会导致ClassCastException
的原因。
关于通配符:
Set<Object>
的泛型类型正是Object
。您可以从它中插入和检索Object
实例,但不能将Set<Integer>
传递给需要Set<Object>
的方法,因为该方法可能正在计划向集合中添加一个非Integer
对象。Set<?>
具有未指定的泛型类型。一个方法可以以Object
的形式从它中检索任何东西(因为所有东西都是Object
),并且可以在它上调用通用方法,比如hashCode
或toString
,但是它不能向集合添加任何东西。Set
是原始类型,不应该在新代码中使用。发布于 2013-09-04 03:54:58
我不太确定,但我理解类型信息在运行时中丢失的是,在运行时没有办法证明集合是特定类型的。如果将String
添加到集合中,则它将仅为String
,但集合并不强制所有元素都应类型为String
。
发布于 2013-09-04 04:07:09
泛型由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已经对你的问题第二部分给出了很好的解释。
https://stackoverflow.com/questions/18605074
复制相似问题