我有类似于下面所示的类,并且需要在第(*(行实例化一个Container对象。
public abstract class Foo {
...
}
public class Bar extends Foo {
...
}
public class Container {
public Container(ArrayList<Foo> fooList) {
this.fooList = fooList;
}
...
private ArrayList<Foo> fooList;
}
public static void main(String[] args) {
ArrayList<Bar> barList = new ArrayList<Bar>();
(*) Container container = new Container(barList);
}
然而,我得到以下编译错误:
error: incompatible types: ArrayList<Bar> cannot be converted to ArrayList<Foo>
有解决办法吗?我需要Container能够接受扩展Foo的不同子类的ArrayList。
更改Container
类和main()
方法,如下所示。
class Container {
public Container(List<Foo> fooList) {
this.fooList = fooList;
}
private List<Foo> fooList;
}
public class Solution {
public static void main(String[] args) {
List<Foo> barList = new ArrayList<>();
barList.add(new Bar());
Container container = new Container(barList);
}
}
如果由于任何原因无法更改Container
类,唯一的解决方案是:
public static void main(String[] args) {
ArrayList<Foo> barList = new ArrayList<Foo>();
barList.add(new Bar());
Container container = new Container(barList);
}
然而,这是一个相当糟糕的设计,原因有三:
- Container类强制使用
ArrayList
而不是List
接口的其他实现 - Container类强制使用
Foo
实例列表,不接受Foo
的子类列表 - Container类可以存储
Foo
的任何描述符,并且它是不可配置的
第一个问题可以通过将ArrayList
更改为List
来解决。
public class Container {
public Container(List<Foo> fooList) {
this.fooList = fooList;
}
private List<Foo> fooList;
}
第二个问题可以通过使用Generics 来解决
public class Container {
public Container(List<? extends Foo> fooList) {
this.fooList = fooList;
}
private List<? extends Foo> fooList;
}
最后一个问题可以通过参数化Container
类本身来解决:
public class Container<T extends Foo> {
public Container(List<? extends T> fooList) {
this.fooList = fooList;
}
private List<? extends T> fooList;
}
public static void main(String[] args) {
ArrayList<Bar> barList = new ArrayList<>();
Container<Foo> container = new Container<>(barList);
}
如果您想确保特定的列表实现将具有快速的O(1)
通过索引获取操作,那么您只能接受同时实现List
和RandomAccess
接口的类。
public class Container {
public <L extends List<? extends Foo> & RandomAccess> Container(L fooList) {
this.fooList = fooList;
}
private List<? extends Foo> fooList;
}