考虑以下无效的Java代码:
class Example {
private static class Base {}
private static class Child extends Base{
public void do(){}
}
public void foo(List<Base>) {}
public static void main(String[] args) {
List<Child> list = new ArrayList<>();
fillListInPlaceWithChildren(list);
foo(list); //compile error, List<Child> does not extend List<Base>
list.stream().forEach(Child::do);
}
}
这不会编译,因为List<Child>
不是List<Base>
的子类,因此无法传递给foo函数。据我所知,要解决这类问题,我有两个选择:
让foo接受List<? extends Base>
:
class Example {
private static class Base {}
private static class Child extends Base{
public void do(){}
}
public void foo(List<? extends Base>) {}
public static void main(String[] args) {
List<Child> list = new ArrayList<>();
fillListInPlaceWithChildren(list);
foo(list);
list.stream().forEach(Child::do);
}
}
让list
成为List<Base>
,并在需要时将元素转换为Child
的实例
class Example {
private static class Base {}
private static class Child extends Base{
public void do(){}
}
public void foo(List<Base>) {}
public static void main(String[] args) {
List<Base> list = new ArrayList<>();
fillListInPlaceWithChildren(list);
foo(list);
list.stream().forEach((item) -> ((Child)item).do());
}
}
哪种选择被认为是最佳做法,为什么?或者它们都有不同的用例?
答案 0 :(得分:1)
我总是建议使用更高级别的抽象。如果您可以使用List<Base> list
代替List<Child>
列表,请使用它!。
但在这种情况下foo
设定了合同。 foo应该接受来自List<? extend Base>
的所有列表,还是只接受List<Child>
才有意义?
问题在于答案。
答案 1 :(得分:1)
您无法将List<Child>
传递给需要List<Base>
的方法,因为它可能会导致一些问题。如果您传入List<Child>
?
void foo(List<Base> list) {
list.add(new Base());
}
如果您不依赖仅包含Base
个实例的列表。使用List<? extends Base>
比在代码中添加类型转换更安全,同时也减少了阅读代码的人的意外。