猿问

无法使用通配符泛型为Java集合添加值

无法使用通配符泛型为Java集合添加值

为什么此代码不编译(Parent是接口)?

List<? extends Parent> list = ...Parent p = factory.get();   // returns concrete implementationlist.set(0, p);   
// fails here: set(int, ? extends Parent) cannot be applied to (int, Parent)



素胚勾勒不出你
浏览 540回答 3
3回答

幕布斯6054654

它这样做是为了安全。想象一下,如果成功的话:List<Child>&nbsp;childList&nbsp;=&nbsp;new&nbsp;ArrayList<Child>();childList.add(new&nbsp;Child());List<?&nbsp;extends&nbsp;Parent>&nbsp;parentList&nbsp;=&nbsp;childList; parentList.set(0,&nbsp;new&nbsp;Parent());Child&nbsp;child&nbsp;=&nbsp;childList.get(0);&nbsp;//&nbsp;No!&nbsp;It's&nbsp;not&nbsp;a&nbsp;child!&nbsp;Type&nbsp;safety&nbsp;is&nbsp;broken...意义List<? extends Parent>是“是某种类型的列表,它是Parent..我们不知道哪种类型-可能是List<Parent>..List<Child>,或List<GrandChild>.“这使取任何物品都是安全的。走出.的.List<T>API和转换自T到Parent,但打电话是不安全的在……里面到List<T>API转换自Parent到T..因为转换可能无效。

当年话下

List<?&nbsp;super&nbsp;Parent>“生产者-延伸,消费者-超级”。你的List是…的消费者Parent物品。

人到中年有点甜

这是我的理解。假设我们有一个泛型类型,有两个方法type&nbsp;L<T> &nbsp;&nbsp;&nbsp;&nbsp;T&nbsp;get(); &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;set(T);假设我们有一个超级类型P,而且它有子类型C1, C2 ... Cn..(为了方便起见,我们说P是自身的一个子类型,实际上是Ci)现在我们也有n混凝土类型L<C1>, L<C2> ... L<Cn>,就好像我们已经手动写了n类型:type&nbsp;L_Ci_&nbsp;&nbsp;&nbsp;&nbsp;Ci&nbsp;get(); &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;set(Ci);我们不需要手动写,这就是重点。确实有不这些类型之间的关系L<Ci>&nbsp;oi&nbsp;=&nbsp;...;L<Cj>&nbsp;oj&nbsp;=&nbsp;oi;&nbsp;//&nbsp;doesn't&nbsp;compile.&nbsp;L<Ci>&nbsp;and&nbsp;L<Cj>&nbsp;are&nbsp;not&nbsp;compatible&nbsp;types.对于C+模板来说,这就是故事的结尾。它基本上是宏扩展-基于一个“模板”类,它生成许多具体的类,它们之间没有类型关系。对于Java来说,还有更多。我们也有一种L<? extends P>,它是任何一个超级类型的L<Ci>L<Ci>&nbsp;oi&nbsp;=&nbsp;...;L<?&nbsp;extends&nbsp;P>&nbsp;o&nbsp;=&nbsp;oi;&nbsp;//&nbsp;ok,&nbsp;assign&nbsp;subtype&nbsp;to&nbsp;supertype什么样的方法应该存在于L<? extends P>?作为一个超级类型,它的任何方法都必须由它的子类型来预测。这种方法将起作用:type&nbsp;L<?&nbsp;extends&nbsp;P> &nbsp;&nbsp;&nbsp;&nbsp;P&nbsp;get();因为它的任何一个子类型L<Ci>,有一种方法Ci get(),它与P get()-重写方法具有相同的签名和协变返回类型。这是行不通的set()不过-我们找不到X,所以void set(X)可以被void set(Ci)对任何Ci..因此set()方法不存在于L<? extends P>.还有一个L<? super P>相反的方向。它有set(P),但不是get()..如果Si是一种超级类型的P,&nbsp;L<? super P>是一种超级类型的L<Si>.type&nbsp;L<?&nbsp;super&nbsp;P> &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;set(P);type&nbsp;L<Si> &nbsp;&nbsp;&nbsp;&nbsp;Si&nbsp;get(); &nbsp;&nbsp;&nbsp;&nbsp;void&nbsp;set(Si);set(Si)“重写”set(P)不是通常意义上的,但是编译器可以看到set(P)上的有效调用。set(Si)
随时随地看视频慕课网APP

相关分类

Java
我要回答