里氏替换原则
定义
如果对每一个类型T1的对象o1,都有类型为T2的对象o2,
使得以T1定义的所有程序P在所有的对象o1都替换成o2时,程序P的
行为没有发生变化,那么类型T2是类型T1的子类型。
定义扩展
一个软件实体如果都使用一个父类的话,那一个定使用其子类,
所有引用父类的地方必须能透明地使用其子类的对象,子类对象能
替换父类对象,而程序逻辑不变。
引申意义
子类可以扩展父类的功能,但不能改变父类的原有功能。
含义1
子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。
含义2
子类可以增加自己特有的方法
含义3
当子类的方法重载父类的方法时,方法的前置条件(方法的输入,入参)
要比父类的输入方法更宽松
含义4
当子类的方法实现父类的方法时(重写,重载或实现抽象方法),
方法的后置条件(方法的输出,返回值)要比父类的更严格或相等
优点
1. 约束继承泛滥,是开闭原则的一种体现。
2. 加强程序的健壮性,同时变更时也可以做到非常好的兼容性,提高
程序的维护性,扩展性。降低需求变更时引入的风险。
代码演示
在演示开闭原则的代码中,就很好的遵守了里氏替换原则,
下面使用另外一段代码演示里氏替换原则:
public class Rectangle {
private long height;
private long weight;
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public long getWeight() {
return weight;
}
public void setWeight(long weight) {
this.weight = weight;
}
}
public class Square extends Rectangle{
private long length;
public long getLength() {
return length;
}
public void setLength(long length) {
this.length = length;
}
@Override
public long getHeight() {
return getLength();
}
@Override
public void setHeight(long height) {
setLength(height);
}
@Override
public long getWeight() {
return getLength();
}
@Override
public void setWeight(long weight) {
setLength(weight);
}
}
//test1
public class SimpleTest {
public static void main(String[] args) {
Rectangle rectangle = new Rectangle();
rectangle.setHeight(18);
rectangle.setWeight(20);
resize(rectangle);
}
private static void resize(Rectangle rectangle) {
while (rectangle.getWeight() >= rectangle.getHeight()) {
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("weight:" + rectangle.getWeight() + ",height:" + rectangle.getHeight());
}
System.out.println("Resize end, weight:" + rectangle.getWeight() + ",height:" + rectangle.getHeight());
}
}
//test2
public class SimpleTest {
public static void main(String[] args) {
Square square = new Square();
square.setLength(20);
resize(square);
}
private static void resize(Rectangle rectangle) {
while (rectangle.getWeight() >= rectangle.getHeight()) {
rectangle.setHeight(rectangle.getHeight() + 1);
System.out.println("weight:" + rectangle.getWeight() + ",height:" + rectangle.getHeight());
}
System.out.println("Resize end, weight:" + rectangle.getWeight() + ",height:" + rectangle.getHeight());
}
}
在代码中,test1的测试结果是:
weight:20,height:19
weight:20,height:20
weight:20,height:21
Resize end, weight:20,height:21
test2的测试结果是:(截取了一段,方法执行了一个死循环)
weight:4599496,height:4599496
weight:4599497,height:4599497
weight:4599498,height:4599498
weight:4599499,height:4599499
weight:4599500,height:4599500
显然该代码不符合里氏替换原则:因为在Square在继承了Rectangle的时候重写了父类中的非抽象方法,违反了含义1:子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法。