为什么我用这个Java代码会出现编译器错误?
1 public List<? extends Foo> getFoos()
2 {
3 List<? extends Foo> foos = new ArrayList<? extends Foo>();
4 foos.add(new SubFoo());
5 return foos;
6 }
其中'SubFoo'是实现Foo的具体类,而Foo是一个接口。
我在这段代码中遇到的错误:
更新:感谢Jeff C,我可以将第3行更改为“new ArrayList&lt; Foo&gt;();”。但我仍然遇到第4行的问题。
答案 0 :(得分:29)
请改用:
1 public List<? extends Foo> getFoos()
2 {
3 List<Foo> foos = new ArrayList<Foo>(); /* Or List<SubFoo> */
4 foos.add(new SubFoo());
5 return foos;
6 }
一旦将foos声明为List<? extends Foo>
,编译器就不知道添加SubFoo是安全的。如果已将ArrayList<AltFoo>
分配给foos
,该怎么办?这将是一个有效的任务,但添加SubFoo会污染集合。
答案 1 :(得分:15)
只是想通过总结用类型或通配符实例化的List参数的属性来添加这个旧线程....
当方法的参数/结果是List时,使用类型实例化或通配符确定
List< Foo>
List< Foo>
List< Foo>
List< ? super Foo>
List< ? super SubFoo>
List< ? extends Foo>
List< ? extends SuperFoo>
Foo
&amp;亚型Foo
&amp;超类型(最多Object
)List< ? extends Foo>
List< Foo>
List< Subfoo>
List< SubSubFoo>
List< ? extends Foo>
List< ? extends SubFoo>
List< ? extends SubSubFoo>
List< ? extends Foo>
List< ? extends SuperFoo>
List< ? extends SuperSuperFoo>
Foo
&amp;超类型(最多Object
)List<? super Foo>
List< Foo>
List< Superfoo>
List< SuperSuperFoo>
List< ? super Foo>
List< ? super SuperFoo>
List< ? super SuperSuperFoo>
List< ? super Foo>
List< ? super SubFoo>
List< ? super SubSubFoo>
Foo
&amp;超型Foo
&amp;超类型(最多Object
)List<Foo>
,因为它最大限度地提高了读写的灵活性List<? extends UpperMostFoo>
,专注于操作不同的类(并不总是Foo),并且在Foo类型层次结构中存在单个最上层的类,并且如果该方法是内部的写入列表并且调用者列表操作正在读取。在返回List< UpperMostFoo>
List< ? extends UpperMostFoo>
并向其添加元素
List< ? super LowerMostFoo>
答案 2 :(得分:6)
尝试:
public List<Foo> getFoos() {
List<Foo> foos = new ArrayList<Foo>();
foos.add(new SubFoo());
return foos;
}
泛型ArrayList构造函数需要具有要参数化的特定类型,不能使用'?'那里有通配符。将实例化更改为“new ArrayList&lt; Foo&gt;()”将解决第一个编译错误。
'foos'变量的声明可以有通配符,但由于你知道精确的类型,因此在那里引用相同的类型信息更有意义。你现在所说的foos拥有一些特定的Foo子类型,但我们不知道哪个。可能不允许添加SubFoo,因为SubFoo不是“Foo的所有子类型”。将声明更改为'List&lt; Foo&gt; foos ='解决了第二次编译错误。
最后,我会将返回类型更改为“List&lt; Foo&gt;”因为此方法的客户端将无法对当前定义的返回值执行太多操作。您应该很少在返回类型中使用通配符。如果需要,可以使用参数化方法签名,但更喜欢有界类型仅出现在方法参数中,因为这会将其留给可以传递特定类型并相应地操作的调用者。
答案 3 :(得分:2)
以下工作正常:
public List<? extends Foo> getFoos() {
List<Foo> foos = new ArrayList<Foo>();
foos.add(new SubFoo());
return foos;
}
答案 4 :(得分:1)
要了解泛型如何工作,请查看此示例:
List<SubFoo> sfoo = new ArrayList<SubFoo>();
List<Foo> foo;
List<? extends Foo> tmp;
tmp = sfoo;
foo = (List<Foo>) tmp;
问题是,这不是为本地/成员变量而设计的,但对于功能签名而言,这就是为什么它如此向后倾斜。