通过使用泛型,我们可以在编译期间检测到任何可能的情况。 例如,
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 如何知道它在运行时检索的对象类型是字符串对象还是 person 对象(上面编译器生成的转换)。但这对泛型有效,这可能会导致运行时错误。
List<Object> test = new ArrayList<Object>();
test.add("hello");
test.add(new Integer(34));
最后,Joshua Bloch 在第 115 页(第 23 项,effective java)中提到
Set<Object>
是参数化类型,表示可以包含任何类型对象的集合,
Set<?>
是一个通配符类型,表示一个只能包含某种未知类型的对象的集合
和 Set
是一种原始类型,它选择退出通用类型系统。
我确实明白他上面这句话的意思。一些澄清会有所帮助
最佳答案
编译器在从泛型方法中检索项目时插入强制转换操作;这是 JVM 知道处理 list.get(0)
结果的唯一方法作为 String
.这就是为什么堆污染(将错误类型的对象插入泛型集合)会导致 ClassCastException
的原因。在运行时。
关于通配符:
-
Set<Object>
的通用类型恰好是Object
.您可以插入和检索Object
它的实例,但你不能传递Set<Integer>
一个期待Set<Object>
的方法,因为该方法可能计划添加一个非Integer
反对集合。 -
Set<?>
具有未指定的通用类型。一个方法可以从中检索任何东西作为Object
(因为一切都是Object
)并且可以像hashCode
一样调用通用方法或toString
, 但它不能向集合中添加任何内容。 -
Set
,正如您提到的,是原始类型,不应在新代码中使用。
关于java - 如何在 Java 的泛型(Erasure)中检索类型信息?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/18605074/