GitHub (opens new window)

里氏替换原则

PPG007 ... 2021-12-30 About 2 min

# 里氏替换原则

Liskov Substitution Principle (LSP)。

# 继承

继承的优点:

继承的缺点:

里氏替换原则

所有使用父类的地方必须能够替换成子类且不会出现错误或异常。

# 里氏替换原则四层含义

  1. 子类必须完全实现父类的方法,如果子类不能完整地实现父类的方法,或者父类的某些方法在子类中发生畸变,建议断开父子继承关系,采用依赖、聚合、组合等关系替代继承。
  2. 子类可以有自己的个性。
  3. 覆盖或实现父类的方法时输入的参数可以被放大。
  4. 覆写或实现父类的方法时输出的结果可以被缩小。

父类代码如下:

public class Father {
    public Collection process(HashMap map){
        System.out.println("父类被执行");
        return map.values();
    }
}
1
2
3
4
5
6

子类代码如下:

public class Son extends Father{

    public Collection process(Map map){
        System.out.println("子类被执行");
        return map.values();
    }
}
1
2
3
4
5
6
7

子类完成了方法的重载而不是重写,且重载方法放大了参数范围,子类方法列表:

image-20210831160159572

主函数:

public class Client {
    public static void main(String[] args) {
        Father father = new Father();
        father.process(new HashMap());

        Son son = new Son();
        son.process(new HashMap());
    }
}
1
2
3
4
5
6
7
8
9

在主函数中的两个 process 方法都会输出父类被执行

如果调转过来,父类参数范围更大:即父类方法接收 Map,子类方法接收 HashMap,则子类的 process 方法将会替代继承到的方法被执行,此时方法仍然是重载而不是重写,输出子类被执行,这样虽然完成了子类替换,但是效果与父类不同,违背了里氏替换原则。

注意

子类中方法的参数必须与超类中覆写的方法的参数相同或更宽松。