Behavioral subtyping and Liskov Substitution Principle (LSP)

  子类型多态:客户端可以用统一的方式处理不同类型的对象。如果对于类型 T 的对象 x,q(x) 成立,那么对于类型 T 的子类型 S 的对象 y,q(y) 也成立。如下所示,Cat() 是 Animal() 的子类型:

  Liskov替换原则(LSP):

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

1)子类型可以增加方法,但不能减少方法;

2)子类型需要实现抽象类型(接口、抽象类)中所有未实现的方法;

3)子类型中重写的方法必须使用同样类型的参数或符合反协变的参数(此种情况Java目前按重载处理);

4)子类型中重写的方法必须有相同或子类型的返回值或者符合协变的参数;

5)子类型中重写的方法不能抛出额外的异常。

对于指定的方法要求:

1)相同或更强的不变量;

2)相同或更弱的前置条件;

3)相同或更强的后置条件。

  

注意:数组是协变的,对于 T[ ] 数组,可以保存类型T及其子类型数据,即使是同一个数组 T[ ],也可存多个不同类型的数据。但当该数组被实例化为其子类型的数组后,就只能存对应子类型元素了:

 

 

 

  泛型的类型擦除:

  泛型信息只存在于编译阶段,在运行时会被”擦除”。定义泛型类型时,会自动提供一个对应的原始类型(非泛型类型),原始类型的名字就是去掉类型参数后的泛型类型名。擦除时类型变量会被擦除,替换为限定类型,如果没有限定类型则替换为Object类型;若有多个限定类型,则替换为第一个限定的类型。

  泛型中的LSP:

泛型是类型不变的,ArrayList<String> 是 List<String> 的子类型,但 List<String> 不是List<Object> 的子类型,这两个之间没有关系。若想实现两个泛型类之间的协变,可以采用通配符 “?”。List<Number> 是 List<?> 的子类型,也是 List<? extends Object>、List<? super Integer> 的子类型。

 

 

1)无限定通配符<?>: 当方法的实现不依赖于类型参数(不调用其中的方法)或只依赖于Object类中的功能时,可以使用无限定通配符。

无限定通配符一般用于定义一个引用变量,其可以指向多个不同类型的变量:

 

2)下限通配符<? super A>:以 A 为下限,可以指向 A 或 A 类型的超类;

3)上限通配符<? extends A>:以 A 为上限,可匹配指向 A 或 A 的子类型。

但注意,这也只能使之匹配多种类型中的一种,对于同一个集合类的对象,其不可存放多种类型,只能存放这些类型中的一种。

限定的类型参数允许调用限定类型中的方法,如:限定<T extends Integer>,则允许限定的类型参数 T 类调用 Integer 类方法。

 

posted @ 2022-06-12 22:28  地瓜丸  阅读(34)  评论(0)    收藏  举报