【发布时间】:2021-12-22 18:58:30
【问题描述】:
我正在阅读有关 Java 泛型的内容,但以下部分似乎有问题:
public class Farm {
private List<Animal> animals;
public void addAnimals(Collection<Animal> newAnimals) {
animals.addAll(newAnimals);
}
}
farm.addAnimals(cats); // Compilation error
farm.addAnimals(dogs); // Compilation error
Cat 和 Dog 是 Animal 的子类。
为了使其工作,需要定义一个带有上限的通配符类型:
public void addAnimals(Collection<? extends Animal> newAnimals)
我不应该可以互换使用子类和超类而不需要根据 Liskov 替换的定义设置上限吗:
可替换性是面向对象编程中的一个原则,它规定对象(例如类)和子对象(例如扩展第一个类的类)必须在不破坏程序的情况下可互换。
【问题讨论】:
-
泛型不是协变的。因此,
Collection<Cat>不是Collection<Animal>。这不会破坏 LSP,因为 LSP 不关心泛型。我们使用the PECS mnoemonic。 -
List<Dog>、List<Cat>、Collection<Dog>、Collection<Cat>等不是Collection<Animal>的子类。 -
如果不清楚,请注意我们替换的类型不是
Cats、Dogs 和Animals,而是collections 那些东西。 -
@Sweeper 非常有意义,谢谢。我会研究 PECS。
-
嗯,来自重复链接的accepted and most upvoted answer 很好地解释了为什么编译器不允许这样的事情是一件好事。
标签: java generics solid-principles liskov-substitution-principle