里氏替换原则是指子类可以扩展父类的功能,但是不能改变父类的原有功能。
- 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
- 子类可以添加自己特有的功能
- 当子类重载父类的方法时,方法的前置条件要比父类方法的输入参数更宽松
- 当子类的方法实现父类的方式时,方法的后置条件要比父类更严格或和父类一样
现在来描述一个经典的业务场景,用正方形、矩形和四边形的关系说明里氏替换原则,
我们都知道正方形是一个特殊的长方形,所以就可以创建一个rectangle类
public class Rectangle {
private long height;
private long width;
public long getHeight() {
return height;
}
public void setHeight(long height) {
this.height = height;
}
public long getWidth() {
return width;
}
public void setWidth(long width) {
this.width = width;
}
}
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 super.getHeight();
}
@Override
public void setHeight(long height) {
super.setHeight(height);
}
@Override
public long getWidth() {
return super.getWidth();
}
@Override
public void setWidth(long width) {
super.setWidth(width);
}
}
在测试类中创建resize()方法,长方形的宽应该大于等于高,我们让高一直增加
public static void resize(Rectangle rectangle){
while (rectangle.getWidth()>=rectangle.getHeight()){
rectangle.setHeight(rectangle.getHeight()+1);
System.out.println();
}
}
public static void main(String[] args) {
Rectangle rectangle= new Rectangle();
rectangle.setHeight(10);
rectangle.setWidth(20);
resize(rectangle);
}
我们发现高比宽还大了,这在长方形中一种非常正常的情况。现在我们换成它的子类,修改代码:
public static void main(String[] args) {
Square square = new Square();
square.setLength(10);
resize(square);
}
上述代码运行时出现了死循环,违背了里氏替换原则,将父类替换为子类后,程序运行结果没有达到预期,因此我们代码设计是存在一定风险的,里氏替换原则只出现在父类与子类之间,约束继承泛滥。