【问题标题】:Collections subtypes - Liskov Substitution Principle集合子类型 - Liskov 替换原则
【发布时间】:2015-04-22 10:40:48
【问题描述】:

Java 不允许将Collection<Car> 作为Collection<Vehicle> 的子类型。这是因为Collection<Car> 不能用来代替每个Collection<Vehicle>,因为Collection<Vehicle> 可能包含其他车辆子类型的元素,例如摩托车,因此它违反了里氏替换原则?

【问题讨论】:

  • 这与使用泛型的不变性挑战以及随之而来的协方差响应更相关

标签: java collections liskov-substitution-principle subtyping


【解决方案1】:

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

然而,关于类型安全,它是这样工作的:

假设CarVehicle 的子类型,Collection<Car> 是允许类似操作的类型

Collection<Car> c=…;
Car car=c.iterator().next();

Collection&lt;Vehicle&gt; 没有。另一方面,Collection&lt;Vehicle&gt; 是一种允许类似操作的类型

Collection<Vehicle> c=…;
Vehicle v=…;
c.add(v);

Collection&lt;Car&gt; 没有。因此,这些Collection 类型都不是另一个的子类型。

【讨论】:

【解决方案2】:

不完全是。反过来:

Collection&lt;Car&gt; 仅包含 Cars 很好,即使 Collection&lt;Vehicle&gt; 可能包含其他类型的车辆。您仍然可以将Collection&lt;Car&gt; 提供给任何可以处理来自Collection&lt;Vehicle&gt; 的元素的人。

Collection&lt;Car&gt; 不能用于代替Collection&lt;Vehicle&gt;,因为您可以将Bicycle 放入Collection&lt;Vehicle&gt;(但不能放入Collection&lt;Car&gt;)。所以你不能把Collection&lt;Car&gt;给想取车的人。

【讨论】:

    【解决方案3】:

    Collection&lt;T&gt; 是一个类型构造函数,所以Collection&lt;Car&gt; 是一个类型,Collection&lt;Vehicle&gt; 是另一个类型。

    现在的问题是,如果在需要 Collection&lt;Vehicle&gt; 的地方可以使用 Collection&lt;Car&gt;,这是一个方差问题(这种情况下是协方差)。

    Liskov 替换原则在某种程度上超越了类型一致性,它不仅要求提供更多,要求更少,而且还保持超类型的合同,see Wikipedia

    【讨论】:

      【解决方案4】:

      请注意,Collection&lt;Car&gt; 与组件类型 Car 相比不变。因此,如果您想使用汽车、自行车、火车等车辆的集合,您应该采用 协变 集合Collection&lt;? extends Vehicle&gt;

      当然,如果您有一个 CarFactory 和一个应该将生产的汽车停放在某个地方的生产方法,那么 逆变 produce(Collection&lt;? super Car&gt;) 方法将是最有用的实现。

      【讨论】:

        猜你喜欢
        • 2010-12-03
        • 1970-01-01
        • 2016-08-20
        • 1970-01-01
        • 1970-01-01
        • 2014-06-05
        • 2011-01-16
        • 2019-10-29
        相关资源
        最近更新 更多