How can elements be added to a wildcard generic collection?
为什么我会用这个Java代码获得编译器错误?
1 2 3 4 5 6 | 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<?扩展Fo>
- 第4行:"方法添加(捕获1-of?扩展foo)在类型列表中扩展foo>不适用于参数(subfoo)"
更新:感谢Jeff C,我可以将第3行改为"new arraylist
改为使用:
1 2 3 4 5 6 | 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 } |
一旦将foo声明为
我只是想通过总结用类型或通配符实例化的列表参数的属性来添加到这个旧线程中……
当一个方法有一个作为列表的参数/结果时,类型实例化或通配符的使用决定了
参数/返回类型:
List< Foo>
List< Foo> List< ? super Foo> List< ? super SubFoo> List< ? extends Foo> List< ? extends SuperFoo>
Foo 和子类型
Foo 和supertypes(至多Object )
参数/返回类型:
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 和supertypes(至多Object )
参数/返回类型:
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 和supertypes
Foo 和supertypes(至多Object )
解释/评论
- 外部调用方的需求驱动方法声明的设计,即公共API(通常是主要考虑因素)
- 内部方法逻辑的需求驱动对内部声明和构造的实际数据类型的任何附加决策(通常是次要考虑因素)
- 如果调用者代码总是专注于操纵foo类,则使用
List ,因为它最大限度地提高了读写的灵活性。 - 如果调用者可能有许多不同类型,集中于操作不同的类(不总是foo),并且foo类型层次结构中只有一个最上面的类,并且如果方法是内部写入列表,并且调用者列表操作正在读取,则使用
List extends UpperMostFoo> 。在这里,在返回List< ? extends UpperMostFoo> 之前,该方法可以在内部使用List< UpperMostFoo> 并向其添加元素。 - 如果有许多不同类型的调用者,专注于操作不同的类(不总是foo),并且如果需要对列表进行读写,并且foo类型层次结构中只有一个最低的类,那么使用
List< ? super LowerMostFoo> 是有意义的。
尝试:
1 2 3 4 5 | public List<Foo> getFoos() { List<Foo> foos = new ArrayList<Foo>(); foos.add(new SubFoo()); return foos; } |
泛型ArrayList构造函数需要有一个要参数化的特定类型,不能使用"?"通配符。将实例化更改为"new arraylist
"foos"变量的声明可以有通配符,但由于您知道确切的类型,因此在那里引用相同的类型信息更为合理。您现在所说的foo包含foo的某些特定子类型,但我们不知道是哪个。可能不允许添加子oo,因为子oo不是"foo的所有子类型"。将声明更改为'list
最后,我会将返回类型更改为"list
以下各项工作正常:
1 2 3 4 5 | public List<? extends Foo> getFoos() { List<Foo> foos = new ArrayList<Foo>(); foos.add(new SubFoo()); return foos; } |
要了解泛型的工作原理,请查看以下示例:
1 2 3 4 5 6 | List<SubFoo> sfoo = new ArrayList<SubFoo>(); List<Foo> foo; List<? extends Foo> tmp; tmp = sfoo; foo = (List<Foo>) tmp; |
问题是,它不是为局部/成员变量设计的,而是为函数签名设计的,这就是为什么它是如此向后的。