Liskov Substitution Principle (LSP)与子类型多态

1.    子类型多态:

    客户端可用统一的方式处理同类型的对象 

    

2.    LSP:


例如:

    

(1)java编译器的规则(静态类型检查):

    a.    子类型可以增加方法,但不可删 

    b.    子类型需要实现抽象类型中的所有未实现方法

    c.    子类型中重写的方法必须有相同或子类型的返回值 

    d.    子类型中重写的方法必须使用同样类型的参数

    e.    子类型中重写的方法不能抛出额外的异常 

    对于继承而来的指定方法:

    -要有更强的不变量

    -更弱的前置条件 

    -更强的后置条件

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

    -前置条件不能强化 

    -后置条件不能弱化 

    -不变量要保持 

    -子类型方法参数:逆变 

    -子类型方法的返回值:协变 

    -异常类型:协变 

    a. Covariance(协变):

    从父类型到子类型,specific越来越具体,返回值类型越来越具体,异常的类型也是如此。

    例如:返回值类型:

    

    异常类型:

    

    b.    Contravariance(反协变,逆变)

    父类型到子类型:specific越来越具体,然而参数类型要相反地变化,即不变或越来

    越抽象(前置条件弱化)。

    例如:

    

    c.    更多举例:

        数组是协变的:T[]可以包含type T以及T的任何子类:

        

        发生run-time error的原因:

        在run-time,java已经知道这个数组实际上被integers的数组实例化。仅仅是引用为

        Number[]。

        因此,要区分Type of an object vs. Type of a reference 


(3)泛型中的LSP。

        对于泛型来说:

        例如:

        ArrayList<String>是List<String>的子类,

        List<String>不是List<Object>的子类

        类型参数的类型信息在代码编译完成之后是被忽略的,

        因此类型信息在run-time并不可得到,这被称为类型擦除(type erasure)。

        泛型不是可协变的。   

        例如:

        

        出现了编译错误。

        因此:

        

(4)泛型中的通配符与LSP。

List<Number>是List<?>的子类型。

List<Number>是List<? extends Object>的子类型

List<Object>是List<? super String>的子类型



在Java.util.collections中:

有静态方法:

来使List<Number>内元素拷入List<Object>

因为此时 List<? super T>是List<? extends  T>的一个子类






猜你喜欢

转载自blog.csdn.net/qq_38969070/article/details/80724145