用通配符创建新的通用对象 [英] Creating new generic object with wildcard

查看:131
本文介绍了用通配符创建新的通用对象的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

请解释此通用代码通配符编译时的错误:

  //没有编译时错误。 
列表< ;?扩展Number> x = new ArrayList<>();

//编译时错误。
列表< ;?扩展Number> x = new ArrayList <?扩展Number>();


解决方案

使用通配符实例化泛型类型是无效的。类型列表<? extends Number> 表示 $ C $ C>。创建这种类型的实例是没有意义的,因为通过实例化您创建了特定的内容:

  new ArrayList< ? extends Number>(); //编译器:等等,我准确地创建了什么? 

具有通配符的通用类型只对变量和方法参数有意义,因为它允许更多的自由度被分配/传递给它们。

  //编译器:好的,因此传入List< Integer>或List< Double>都很好
public void eatSomeNumbers(List< ;? extends Number> numbers){
for(Number number:numbers){
System.out.println(om nom+数字+nom);
}
}

请务必记住随附的限制使用通配符。

 列表< ;?扩展Number> numList = ... 
numList.add(new Integer(3)); //编译器:不,可能是List< Double>至于你的第一个例子,钻石是Java 7中的一个新特性,它允许编译器<<

em>根据分配给它的变量的类型推断新的通用实例的类型。在这种情况下:

 列表< ;?扩展Number> x = new ArrayList<>(); 

编译器很可能推断出 new ArrayList< Number>() code>这里,但是推断什么都不重要,只要它是给定变量的有效赋值即可。这就是引入钻石操作符的原因 - 指定新对象的泛型类型是多余的,只要一些泛型类型可以使它成为有效的赋值/参数。



如果您记得Java中的泛型是纯粹的编译时语言功能,这一推理才有意义,因为 type erasure ,并且在运行时没有意义。通配符仅仅因为这个限制而存在。相比之下,C#泛型类型信息在运行时会出现 - 通用通配符不存在于该语言中。

Please explain this generic code wildcard compile time error:

//no compile time error.
List<? extends Number> x = new ArrayList<>(); 

//compile time error.  
List<? extends Number> x = new ArrayList<? extends Number>();

解决方案

It's invalid syntax to instantiate a generic type with wildcards. The type List<? extends Number> means a List of some type that is or extends Number. To create an instance of this type doesn't make sense, because with instantiation you're creating something specific:

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

Generic types with wildcards only make sense for variables and method parameters, because this allows greater freedom in what can be assigned/passed into them.

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

Make sure to keep in mind the limitations that come with using wildcards.

List<? extends Number> numList = ...
numList.add(new Integer(3));//compiler:"Nope, cause that might be a List<Double>"

As for your first example, the diamond is a new feature in Java 7 that allows the compiler to infer the type of the new generic instance, based on the type of the variable it's assigned to. In this case:

List<? extends Number> x = new ArrayList<>();

The compiler is most likely inferring new ArrayList<Number>() here, but what's inferred hardly matters, as long as it's a valid assignment to the given variable. This was the reason for the diamond operator being introduced - that specifying the generic type of a new object was redundant, as long some generic type would make it a valid assignment/argument.

This reasoning only makes sense if you remember that generics in Java are a purely compile-time language feature, because of type erasure, and have no meaning at runtime. Wildcards exist only because of this limitation. By contrast, in C# generic type information sticks around at runtime - and generic wildcards don't exist in that language.

这篇关于用通配符创建新的通用对象的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆