使用通配符创建新的通用对象

请解释这个通用代码通配符编译时错误:

//no compile time error. List x = new ArrayList(); //compile time error. List x = new ArrayList(); 

使用通配符实例化generics类型是无效的语法。 类型List List表示某个类型List ,它是或扩展Number 。 创建这种类型的实例没有意义,因为在实例化时你正在创建特定的东西:

 new ArrayList();//compiler:"Wait, what am I creating exactly?" 

具有通配符的通用类型仅对变量和方法参数有意义,因为这允许在可以分配/传递给它们的内容中有更大的自由度。

 //compiler:"Okay, so passing in a List or a List are both fine" public void eatSomeNumbers(List numbers) { for (Number number : numbers) { System.out.println("om nom " + number + " nom"); } } 

请务必记住使用通配符时出现的限制。

 List numList = ... numList.add(new Integer(3));//compiler:"Nope, cause that might be a List" 

至于您的第一个示例,菱形是Java 7中的一项新function,它允许编译器根据分配给它的变量的类型推断新通用实例的类型。 在这种情况下:

 List x = new ArrayList<>(); 

编译器很可能在这里推断出new ArrayList() ,但推断的内容几乎不重要,只要它是对给定变量的有效赋值。 这就是引入菱形运算符的原因 – 指定新对象的generics类型是多余的,因为一些generics类型会使它成为有效的赋值/参数。

如果您记得Java中的generics是纯粹的编译时语言特性,因为类型擦除 ,并且在运行时没有意义,这种推理才有意义。 通配符只是因为这种限制而存在。 相比之下,在C#generics类型信息在运行时粘附 – 并且该语言中不存在通用通配符。

使用

  List x = new ArrayList(); 

代替。