LSP原则(复习)

LSP原则:如果对于类型T的对象x,q(x) 成立,那么对于类型T的子类型S的对象y,q(y) 也成立。

Java中的编译器强制规则(静态类型检查):

1.子类型可以增加方法,但不可删
2.子类型需要实现抽象类型 (接口、抽象类)中所有未实现的方法
3.子类型中重写的方法必须有相同或子类型的返回值或者符合co-variant的参数
4.子类型中重写的方法必须使用同样类型的参数或者符合contra-variant的参数(此种情况Java目前按照重载overload处理)
5.子类型中重写的方法不能抛出额外的异常
也适用于指定的行为(方法):更强的不变量、更弱的前置条件、更强的后置条件
LSP是一种子类型关系的特殊定义,称为强行为子类型化。
LSP原则举例:
class Car extends Vehicle {
int fuel;
boolean engineOn;
//@ invariant speed < limit;
//@ invariant fuel >= 0;
//@ requires fuel > 0 && !engineOn;
//@ ensures engineOn;
void start() { … }
void accelerate() { … }
//@ requires speed != 0;
//@ ensures speed < \old(speed)
void brake() { … }
}
class Hybrid extends Car {
int charge;
//@ invariant charge >= 0;
//@ requires (charge > 0 
|| fuel > 0) && !engineOn;
//@ ensures engineOn;
void start() { … }
void accelerate() { … }
//@ requires speed != 0;
//@ ensures speed < \old(speed)
//@ ensures charge > \old(charge)
void brake() { … }
}

从代码一到代码二,子类满足相同的不变量(以及额外的不变量),start方法前置条件更弱,brake方法后置条件更强。

在编程语言中,LSP依赖于以下限制:

协变:

父类型→子类型:越来越具体specific;返回值类型:不变或变得更具体;异常的类型:也是如此。

数组是协变的,泛型不是协变的。

如何实现两个泛型类的协变?

可采用通配符实现两个泛型类的协变。
无限定通配符?使用的两种情况:情况1:方法的实现不依赖于类型参数(不调用其中的方法);情况2:或者只依赖于Object 类中的功能
无限定通配符,一般用于定义一个引用变量,其可以指向多个不同类型的变量:
SuperClass<?> sup0 = new SuperClass<String>();
sup0 = new SuperClass<People>();
sup0 = new SuperClass<Animal>();

<? super A> 下限通配符                 <? extends A> 上限通配符

public static double sumOfList(List<? extends Number> list) {
double s = 0.0;
for (Number n : list)
s += n.doubleValue();
return s;
}
List<Integer> li = Arrays.asList(1, 2, 3);
List<Double> ld = Arrays.asList(1.2, 2.3, 3.5);

注:List<? extends Number> list,意味着list可以匹配多种类型中的一种,但并不意味着同一个list可以存放所有的这些类型,无限定通配符和下限通配符同理。

一个类型变量如果有多个限定(类或接口),则它是所有限定类型的子类型;如果多个限定中有类(至多只允许一个类),要写到声明的最前面。
Class A { /* ... */ }
interface B { /* ... */ }
interface C { /* ... */ }
class D <T extends A & B & C> { /* ... */ }
限定的类型参数允许调用限定类型中的方法。

反协变(逆变):

父类型→子类型:越来越具体specific
参数类型:要相反的变化,要不变或越来越抽象
注:目前Java中遇到参数逆变、参数协变都当作overload处理。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值