使用通配符创建新的通用对象
请解释这个通用代码通配符编译时错误:
//no compile time error. List x = new ArrayList(); //compile time error. List x = new ArrayList();
使用通配符实例化generics类型是无效的语法。 类型List extends Number>
List extends Number>
表示某个类型的List
,它是或扩展Number
。 创建这种类型的实例没有意义,因为在实例化时你正在创建特定的东西:
new ArrayList extends Number>();//compiler:"Wait, what am I creating exactly?"
具有通配符的通用类型仅对变量和方法参数有意义,因为这允许在可以分配/传递给它们的内容中有更大的自由度。
//compiler:"Okay, so passing in a List or a List are both fine" public void eatSomeNumbers(List extends Number> numbers) { for (Number number : numbers) { System.out.println("om nom " + number + " nom"); } }
请务必记住使用通配符时出现的限制。
List extends Number> numList = ... numList.add(new Integer(3));//compiler:"Nope, cause that might be a List"
至于您的第一个示例,菱形是Java 7中的一项新function,它允许编译器根据分配给它的变量的类型推断新通用实例的类型。 在这种情况下:
List extends Number> x = new ArrayList<>();
编译器很可能在这里推断出new ArrayList
,但推断的内容几乎不重要,只要它是对给定变量的有效赋值。 这就是引入菱形运算符的原因 – 指定新对象的generics类型是多余的,因为一些generics类型会使它成为有效的赋值/参数。
如果您记得Java中的generics是纯粹的编译时语言特性,因为类型擦除 ,并且在运行时没有意义,这种推理才有意义。 通配符只是因为这种限制而存在。 相比之下,在C#generics类型信息在运行时粘附 – 并且该语言中不存在通用通配符。
使用
List extends Number> x = new ArrayList();
代替。