为什么我用这个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是一个接口.
我用这段代码得到的错误:
在第3行:"无法实例化ArrayList <?extends Foo>"
在第4行:"方法添加(捕获#1-of?extends Foo)在类型List
更新:感谢Jeff C,我可以更改第3行来说"new ArrayList
请改用:
1 public List extends Foo> getFoos() 2 { 3 Listfoos = new ArrayList (); /* Or List */ 4 foos.add(new SubFoo()); 5 return foos; 6 }
一旦声明foos List extends Foo>
,编译器就不知道添加SubFoo是安全的.怎么ArrayList
分配给foos
怎么办?这将是一个有效的赋值,但添加SubFoo会污染集合.
我只是想通过总结用类型或通配符实例化的List参数的属性来添加这个旧线程....
当方法的参数/结果是List时,使用类型实例化或通配符确定
可以作为参数传递给方法的List类型
可以从方法结果填充的List类型
可以写入方法列表的元素类型
从方法中的列表中读取元素时可以填充的类型
List< Foo>
可以作为参数传递给方法的List类型:
List< Foo>
可以从方法结果填充的List类型:
List< Foo>
List< ? super Foo>
List< ? super SubFoo>
List< ? extends Foo>
List< ? extends SuperFoo>
可以在方法中写入列表的元素类型:
Foo
和亚型
在方法中从列表中读取元素时可以填充的类型:
Foo
和超类型(最多Object
)
List< ? extends Foo>
可以作为参数传递给方法的List类型:
List< Foo>
List< Subfoo>
List< SubSubFoo>
List< ? extends Foo>
List< ? extends SubFoo>
List< ? extends SubSubFoo>
可以从方法结果填充的List类型:
List< ? extends Foo>
List< ? extends SuperFoo>
List< ? extends SuperSuperFoo>
可以在方法中写入列表的元素类型:
没有!无法添加.
在方法中从列表中读取元素时可以填充的类型:
Foo
和超类型(最多Object
)
List super Foo>
可以作为参数传递给方法的List类型:
List< Foo>
List< Superfoo>
List< SuperSuperFoo>
List< ? super Foo>
List< ? super SuperFoo>
List< ? super SuperSuperFoo>
可以从方法结果填充的List类型:
List< ? super Foo>
List< ? super SubFoo>
List< ? super SubSubFoo>
可以在方法中写入列表的元素类型:
Foo
和超类型
在方法中从列表中读取元素时可以填充的类型:
Foo
和超类型(最多Object
)
外部调用者的需求驱动方法声明的设计,即公共API(通常是主要考虑因素)
内部方法逻辑的需求驱动内部声明和构造的实际数据类型的任何其他决策(通常是次要考虑因素)
使用List
如果呼叫者代码始终专注于操纵Foo类,因为它的读取和写入最大的灵活性
使用List extends UpperMostFoo>
是否可能有许多不同类型的来电显示,集中操作不同的类(并不总是富),并有在Foo类型不同层次的单一最上层阶级,如果该方法是在内部写列表和来电列表操作在看书.List< UpperMostFoo>
在返回之前,该方法可以在内部使用并向其添加元素List< ? extends UpperMostFoo>
如果可能有许多不同类型的调用者,专注于操作不同的类(并不总是Foo),如果需要读取和写入列表,并且在Foo类型层次结构中有一个最低级别,那么使用它是有意义的 List< ? super LowerMostFoo>
尝试:
public ListgetFoos() { List foos = new ArrayList (); foos.add(new SubFoo()); return foos; }
通用的ArrayList构造函数需要具有要参数化的特定类型,不能使用'?' 那里有通配符.将实例化更改为"new ArrayList
'foos'变量的声明可以有通配符,但由于你知道精确的类型,因此在那里引用相同的类型信息更有意义.你现在所说的foos拥有一些特定的Foo子类型,但我们不知道哪个.可能不允许添加SubFoo,因为SubFoo不是"Foo的所有子类型".将声明更改为'List
最后,我将返回类型更改为"List