定义:如果对于每一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。
定义扩展:一个软件实体如果适用一个父类的话,那一定适用于其子类,所有引用父类的地方必须能透明地使用其子类的对象,子类对象能够替换父类对象,而程序逻辑不变。
引申意义:子类可以扩展父类的功能,但不能改变父类原有的功能。
含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
含义2:子类可以增加自己特有的方法。
含义3:当子类的方法重载父类的方法时,方法的前置条件(即方法的输入/入参)要比父类的输入参数更宽松。
含义4:当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的输出/返回值)要比父类更严格或相等。
优点1:约束继承泛滥,开闭原则的一种体现
优点2:加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高程序的维护性、扩展性。降低需求变更时引入的风险。
示例
长方形与正方形(1)
代码实现
- 创建Rectangle类
import lombok.Data;
/**
* @author lijiayin
*/
@Data
public class Rectangle {
private Long width;
private Long length;
}
- 创建Square类
import lombok.Data;
/**
* @author lijiayin
*/
@Data
public class Square extends Rectangle {
private Long sideLength;
@Override
public Long getWidth() {
return sideLength;
}
@Override
public Long getLength() {
return sideLength;
}
@Override
public void setWidth(Long width) {
this.sideLength = width;
}
@Override
public void setLength(Long length) {
this.sideLength = length;
}
}
- 测试Rectangle类
/**
* @author lijiayin
*/
public class Test {
public static void resize(Rectangle rectangle){
while (rectangle.getLength() <= rectangle.getWidth()){
rectangle.setLength(rectangle.getLength() + 1);
System.out.println("width:" + rectangle.getWidth() + ", length:" + rectangle.getLength());
}
System.out.println("完成resize,width:" + rectangle.getWidth() + ", length:" + rectangle.getLength());
}
public static void main(String[] args) {
Rectangle rectangle = new Rectangle();
rectangle.setLength(9L);
rectangle.setWidth(10L);
resize(rectangle);
}
}
-
测试结果
测试结果.png - 测试Square类
/**
* @author lijiayin
*/
public class Test {
public static void resize(Rectangle rectangle){
while (rectangle.getLength() <= rectangle.getWidth()){
rectangle.setLength(rectangle.getLength() + 1);
System.out.println("width:" + rectangle.getWidth() + ", length:" + rectangle.getLength());
}
System.out.println("完成resize,width:" + rectangle.getWidth() + ", length:" + rectangle.getLength());
}
public static void main(String[] args) {
Square square = new Square();
square.setSideLength(10L);
resize(square);
}
}
-
测试结果
测试结果
进入无限循环中,不能替换父类Rectangle,破坏了里氏替换原则
长方形与正方形(2)
代码实现
- 创建Quadrangle接口,只有get方法
/**
* @author lijiayin
*/
public interface Quadrangle {
Long getWidth();
Long getLength();
}
- 修改Rectangle类
import lombok.Data;
/**
* @author lijiayin
*/
@Data
public class Rectangle implements Quadrangle{
private Long width;
private Long length;
}
- 修改Square类
import lombok.Data;
/**
* @author lijiayin
*/
@Data
public class Square implements Quadrangle {
private Long sideLength;
@Override
public Long getWidth() {
return sideLength;
}
@Override
public Long getLength() {
return sideLength;
}
}
-
修改测试类
测试类.png
由于没有set方法,因此编译不通过,约束了继承泛滥,满足了里氏替换原则,该方法只能用于Rectangle类。