首页 > 解决方案 > java.util 中的堆栈类违反了 Liskov 替换原则?

问题描述

来自https://docs.oracle.com/javase/7/docs/api/java/util/Stack.html的文档

public class Stack<E> extends Vector<E>

这不是违反里氏替换原则吗?LSP 简单地说就是同一个超类的对象应该能够在不破坏任何东西的情况下相互交换。

例如:假设我有一个将 Vector 作为输入的函数。如果在调用一个函数时我开始向它传递一个堆栈,那么它可能会中断,因为堆栈阻止了元素的随机访问。

import java.util.*;

class Book {}

class TextBook extends Book {}

public class Sample {
    public static void process(Vector<Book> books) {
        # This should not be allowed for Stack, Stack is FILO
        System.out.println(books.get(1));
    }

    public static void main(String[] args) {
        Vector<Book> books = new Vector<>();
        books.add(new Book());
        books.add(new Book());
        books.add(new Book());
        process(books);
        System.out.println("ok");

        Stack<Book> bookz = new Stack();
        bookz.add(new Book());
        bookz.add(new Book());
        bookz.add(new Book());
        process(bookz);
        System.out.println("ok");
    }
}

标签: java

解决方案


JDK 的实现Stack是严格加法的:它只在实现中添加了少数方法,Vector's而没有带走任何东西。出于这个原因,总是可以将 a 分配(替换)Stack给一个类型的变量,Vector而不限制客户端代码可以做什么。因此,这并不违反里氏替换原则。

然而,它的设计被认为是有缺陷的,但根据不同的原则:继承仅适用于子类确实是超类的子类型的情况。. 从有效的Java

Java 平台库中有许多明显违反此原则的地方。例如,堆栈不是向量,因此 Stack 不应扩展 Vector。


推荐阅读