2015-09-07 54 views
7

我读到,自从Java 7以来,像在第一个语句中一样在右侧创建集合是错误的样式,因为编译器可以从左侧推断出类型。为什么类型没有被推断,当离开泛型运算符

List<Integer> myList = new ArrayList<Integer>(); 

我的问题是初始化列表这样的情况下,编译器未找到的类型和我得到一个未经检查的类型警告:

List<Integer> myList = new ArrayList(); 

回答

12

编译器不推断的类型,因为你实例化一个原料ArrayList。但它足够聪明,可以警告您在使用此(原始)对象时可能会出现问题。

值得一提的是这个警告背后的原因。由于type erasure,关于List的参数信息(<Integer>)将在运行时完全消失,此时变量将保存类型为Object的元素。考虑这个片段:

List rawList = new ArrayList(); //raw list 
rawList.add(new String("hello")); 
rawList.add(new Double(12.3d)); 
List<Integer> intList = rawList; // warning! 

这段代码会编译,但会产生很少的警告。有一个原始列表(rawList),您可以添加任何非原始类型的列表,包括String,Double,等等。但是,当将此集合分配到列表中,该列表被指定为只包含整数时,则这是问题。在运行时,当您试图从intList中获取某个元素时,您会得到ClassCastException,该元素应该是Integer,但实际上是String或其他东西。

长话短说 - 不要混合原始类型与泛型!

在你的情况下,编译将可能人推断的类型,如果你已经使用了钻石:

List<Integer> list = new ArrayList<>(); //¯\_(ツ)_/¯ 
            ↑↑ 
9

因为你已经忘记了尖括号(称为钻石运营商)。

List<Integer> myList = new ArrayList<>(); 

这是语法上等同于

List<Integer> myList = new ArrayList<Integer>(); 

但不同于

List<Integer> myList = new ArrayList(); 

在你说的是,右侧是一个原始类型含义ArrayList中可以容纳每个对象的第3 (不仅是整数)。泛型只是编译时间,并被编译为保存类型转换。

+0

为什么这给编译器更多的信息比列表 myList = new ArrayList(),因为在左边的通用信息可用 – PKuhn

+0

因为两者在语义上是不同的。在钻石中省略这种类型只是句法上的含义。 – lschuetze

2

您可以使用钻石操作符推断声明类型为JLS (§15.9)规定。

一个类的实例创建表达式指定一个类被实例化,接着可能类型参数(§4.5.1)或金刚石(“<>”)如果被实例化的类是通用的(§8.1.2 ),然后是构造函数的实际值参数列表(可能为空)。

List<Integer> myList = new ArrayList<>();