里氏替换原则在继承关系中子类对父类方法的重写(覆盖)或重载时应遵循的规则

什么是里氏替换原则:只要父类能出现的地方子类就可以出现,而且 替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

简而言之,子类在重写或重载父类的方法时,对方法的返回值或输入参数应该是"小于等于"(或更具体)于父类的方法。这里的"小于等于"指的是继承关系中子类方法的行为不应该超出父类方法的行为范围。

为了更好地理解,让我们来解释一下含义:

  1. 覆写(Override)的情况: 当子类覆写父类的方法时,子类的方法应该具有相同的方法名、相同的输入参数,但方法体可以重新实现。在这种情况下,方法的返回值类型(也称为方法的协变类型)应该是父类方法返回值类型的子类型(即小于等于父类返回值类型)。这是为了确保子类的行为不会超过父类的行为范围。

  2. 重载(Overload)的情况: 重载是指在同一个类中,方法名相同但输入参数不同的情况。在继承关系中,子类可以重载父类的方法,但是子类重载的方法应该有更宽松的输入参数要求,即子类的输入参数类型应该是父类的输入参数类型的父类型(即宽于或等于父类输入参数类型)。这是为了确保子类方法可以适用于更广泛的输入。

总结起来,LSP要求子类覆写的方法不应该做超出父类方法行为范围的事情,而子类重载的方法应该具有更广泛的输入参数要求。这样可以保证在使用子类对象替代父类对象时,不会出现意外的行为,同时保持了代码的可靠性和一致性。

总结一下:

1、覆写是返回值的范围应该变小(确保行为范围),重载是入参的范围应该变大。

2、同时类的覆写和类的重载本身与返回值没有关系。

子类中方法的前置条 件必须与超类中被覆写的方法的前置条件相同或者更宽松

这句话在讲述里氏替换原则(Liskov Substitution Principle,LSP)中的另一个关键概念,即子类中覆写(重写)方法的前置条件(preconditions)与父类中被覆写方法的前置条件相比应该保持相同或者更宽松。

前置条件指的是方法执行前需要满足的一些条件,以确保方法的正常执行。里氏替换原则要求:

  1. 相同的前置条件: 子类中覆写父类方法时,子类方法的前置条件必须与父类方法的前置条件相同。这意味着在调用子类方法之前,所需的条件和约束应该与调用父类方法时相同,以确保代码的稳定性和可预测性。

  2. 更宽松的前置条件: 子类方法的前置条件可以比父类方法更宽松。这是为了增强子类的灵活性和适用性。如果子类方法的前置条件比父类方法宽松,那么意味着子类方法可以在更多的情况下被调用,而不会破坏程序的正确性。

总之,这一原则确保了子类的方法在被调用时,能够满足至少与父类方法相同的前置条件,以及更宽松的前置条件,**从而避免了在子类中破坏父类行为的情况。**这有助于保持代码的合理性和可维护性。

demo:

java 复制代码
public class Father {
    public Collection doSomething(Map map) {
        System.out.println("父类被执行...");
        return map.values();
    }
}

public class Son extends Father {
    //子类的范文更小,所以最后没有满足 里氏替换原则
    public Collection doSomething(HashMap map) { 
        System.out.println("子类被执行...");
        return map.values();
    }
}


public class Client {
    public static void invoker() {
        Father f = new Father();
        HashMap map = new HashMap();
        f.doSomething(map);
    }

    public static void main(String[] args) {
        invoker(); //父类被执行...
    }
}

public class Client {
    public static void invoker() {
        Son f = new Son();
        HashMap map = new HashMap();
        f.doSomething(map);
    }

    public static void main(String[] args) {
        invoker(); //子类被执行...  没有满足 里氏替换原则
    }
}
相关推荐
言慢行善6 分钟前
sqlserver模糊查询问题
java·数据库·sqlserver
专吃海绵宝宝菠萝屋的派大星11 分钟前
使用Dify对接自己开发的mcp
java·服务器·前端
大数据新鸟29 分钟前
操作系统之虚拟内存
java·服务器·网络
Tong Z31 分钟前
常见的限流算法和实现原理
java·开发语言
凭君语未可34 分钟前
Java 中的实现类是什么
java·开发语言
He少年36 分钟前
【基础知识、Skill、Rules和MCP案例介绍】
java·前端·python
克里斯蒂亚诺更新1 小时前
myeclipse的pojie
java·ide·myeclipse
迷藏4941 小时前
**eBPF实战进阶:从零构建网络流量监控与过滤系统**在现代云原生架构中,**网络可观测性**和**安全隔离**已成为
java·网络·python·云原生·架构
迷藏4941 小时前
**发散创新:基于Solid协议的Web3.0去中心化身份认证系统实战解析**在Web3.
java·python·web3·去中心化·区块链
qq_433502181 小时前
Codex cli 飞书文档创建进阶实用命令 + Skill 创建&使用 小白完整教程
java·前端·飞书