Java 集合子类型-Liskov替换原则

Java 集合子类型-Liskov替换原则,java,collections,liskov-substitution-principle,subtyping,Java,Collections,Liskov Substitution Principle,Subtyping,Java不允许将Collection作为Collection的子类型。这是因为集合不能代替每个集合,因为集合可能包含其他车辆子类型的元素,如摩托车,因此它违反了Liskov替换原则?不完全如此。反过来说: 即使集合可能包含其他类型的车辆,但集合仅包含汽车s也可以。您仍然可以将集合提供给任何可以处理集合中元素的人 但是集合不能代替集合,因为可以将自行车放入集合(但不能放入集合)。因此,您不能将收集提供给想要收集车辆的人。通常,收集由于存在“可选操作”,因此违反了Liskov替换原则,即变异方法可能

Java不允许将
Collection
作为
Collection
的子类型。这是因为
集合
不能代替每个
集合
,因为
集合
可能包含其他车辆子类型的元素,如摩托车,因此它违反了Liskov替换原则?

不完全如此。反过来说:

即使
集合
可能包含其他类型的车辆,但
集合
仅包含
汽车
s也可以。您仍然可以将
集合
提供给任何可以处理
集合
中元素的人


但是
集合
不能代替
集合
,因为可以将
自行车
放入
集合
(但不能放入
集合
)。因此,您不能将
收集
提供给想要收集车辆的人。

通常,
收集
由于存在“可选操作”,因此违反了Liskov替换原则,即变异方法可能无法用于特定实现

但是,就类型安全而言,它是这样工作的:

假设
Car
Vehicle
的一个子类型,则
集合
是一种允许以下操作的类型

Collection<Car> c=…;
Car car=c.iterator().next();
Collection<Vehicle> c=…;
Vehicle v=…;
c.add(v);
集合c=…; Car-Car=c.iterator().next(); 哪个
集合
没有。另一方面,
Collection
是一种允许执行以下操作的类型

Collection<Car> c=…;
Car car=c.iterator().next();
Collection<Vehicle> c=…;
Vehicle v=…;
c.add(v);
集合c=…; 车辆v=…; c、 添加(v); 哪个
集合
没有。因此,这两种
Collection
类型都不是另一种类型的子类型。

Collection
是类型构造函数,因此
Collection
是一种类型,
Collection
是另一种类型

现在的问题是,如果
集合
可以用于需要
集合
的地方,那么这是一个方差问题(这种情况下是协方差)


Liskov替代原则在某种程度上超越了类型一致性,它不仅要求提供更多,要求更少,而且还要求保持超类型的契约。

请注意,
集合
在组件类型
汽车
上是不变的。因此,如果你想使用汽车、自行车、火车等车辆的集合,你应该使用协变集合
collection这与使用泛型的不变性挑战和协变响应更相关,请参见关于集合变异方法是否违反LSP的辩论。