繁体   English   中英

下限通配符

[英]Lower bound wildcards

我正在尝试了解以下代码片段,在stackoverflow上搜索关于lowerboundupperbound的链接

只是想在以下几行中克服困惑,

si = s //好吗? 对象数组可以隐式地转换为整数数组?

 List<? extends Number> l = new ArrayList<>();
 List<? extends Integer> i = new  ArrayList<>();
 l = i;//OK i is a subtype of l

 List<? super Number> s = new ArrayList<>();
 List<? super Integer> si = new  ArrayList<>();

 si = new ArrayList<Integer>();//OK understand integer matches the pattern of ? super Integer
 s = new ArrayList<Object>();//OK understand that object is superclass of Number

 si=s//OK why?  arrays of objects can be implicitly casted to arrays of integers?

 //consider this
 List<Integer> integers = new ArrayList<Integer>();
 List<Object> objects = new ArrayList<Object>();
 integers = objects; //NOT OK Type mismatch: cannot convert from List<Object> to List<Integer>

 //consider this
 Integer ten = 10; //integer ten
 Object none = new Object();//some none
 ten = none;//NOT OK  none cannot be implicitly casted to ten  

任何帮助表示赞赏

请记住,gnerics是为了编译器而不是运行时信息。

当你执行si = s你将一个属于Number的超类的List分配给一个变量,该变量可以引用一个Integer超类的List。

如果它是Number的列表,它仍然是Something的一个列表,它是Integer的超类。

我们知道它实际上是一个对象的Arraylist,因为你之前已经分配过。

我们也知道Object的ArrayList扩展了Object的List。

对象列表是一个超类数的列表,这就是前一个赋值的工作原因。

我们也知道List of Object是一个Integer超类的列表,但它与编译器无关,它只关心Number的任何超类也是Integer的超类。

我想知道你是否清楚为什么要使用<? super Number> <? super Number>而不是<? extends Number> <? extends Number> ...

声明一个带<? extends Number>的类型 <? extends Number> guarantee <? extends Number>到任何采用该类型的东西,它至少会尊重Number的合约。 但是给出这种类型列表的一段代码不能将新成员添加到列表中。 考虑以下代码:

void appendInteger (List <? extends Number> list) {
   list.add (new Integer (3)); // Compiler error on this line
}

你可以用appendInteger (new ArrayList <Double> ());调用它appendInteger (new ArrayList <Double> ()); 现在, DoubleInteger扩展了Number ,因此编译后将接受该参数。 但是你可以看到,如果允许附加,那么违反调用代码中声明的合同。 因此,编译器不允许任何代码添加或替换使用<? extends T>声明的任何结构中的成员<? extends T> <? extends T> 上述方法将导致编译器错误。

简而言之,对于上限的通配符类型,您可以读取项目,但不能将成员放入结构中。

相反,使用List <? super Number> List <? super Number>表示列表中的对象不比Number 更具体 考虑这种方法:

void getInteger (java.util.List <? extends Number> list) {
    Number n = list.get (0); // Compiler error on this line
}

代码不知道list元素的类型。 所以编译器也会用这个方法呕吐。 您可以使用Number的继承路径中的任何类型的对象在list添加或替换成员。 但要读取列表成员,您必须将它们视为Object类型或使用类型转换:

Object v = list.get (0);  // this will work
Number n = (Number) list.get (0);  // this will also work

有了这些知识,再看一下si = s涉及的对象。 请记住,您无法从这些结构中读取项目,只能添加或替换成员。 您可以放置​​在s任何对象也可以在si接受。 因此,将s分配给si是可以接受的。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM