提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档
文章目录
前言
第九章
一、可复用性
1、里氏替换原则(LSP)
2、协变
指从父类型到子类型,即越来越具体
满足LSP原则的子类返回值和抛出异常必须满足协变
返回值协变:(不变或变具体)
抛出异常协变:(不抛出或更具体)
2、逆变
从子类型到父类型,即变得抽象
满足LSP原则的子类方法参数必须满足逆变
3、数组协变和泛型不支持协变
数组 是支持协变的。即如果S是F的子类型,则S的数组可以看作F的数组的子类型,但是会有隐患:
adt是父类型,adt2和adt3是adt的子类型。第一行说明数组支持协变,第二行正常运行,而第三行编译不报错,但是运行时会报错,原因在于a0数组其实内在是adt2的数组,编译时解释为adt父类型的数组,而adt3是adt的子类型,所以编译的时候不会报错;而到了运行时,由于数组本质上是adt2的数组,所以添加不了adt3为元素,会抛出异常。
泛型 则是直接不支持协变:
编译通过不了,直接报错。也就是说,S是F的子类型,但是List<S>和List<F>之间没有父子关系。所以说,泛型是类型不变的。
4、类型擦除
Java泛型是一个伪泛型,这是因为Java在编译期间所有泛型信息都会被擦除掉。Java泛型基本上都是在编译器这个层次上实现的,在生成字节码中是不包括泛型中的类型信息,使用泛型的时候添加上类型参数,在编译器编译的时候会去掉,这个过程称为类型擦除。
编译时,会有如下变化:
由于类型擦除的特性,我们的泛型于是有下面几种用法:
第一种用法是利用类型擦除,使得x和y虽然不是同一种类型,但是仍然能够运行;第二种是显式地指定泛型类型,那么只能两个参数都是String类型了。
5、通配符的使用
泛型本身并不支持协变和逆变,但可以结合无解通配符“ ?”来模拟协变和逆变
上界通配符:<? super T>
下界通配符:<? extends T>
例子:
二、Delegation委派
1、Comparator和Comparable接口
Comparator是外部比较器,Comparable是内部比较器,Collections和Arrays的sort()方法在没有Comparator对象作为参数时,默认用Comparable中compareTo()方法进行比较,若有外部比较器对象作为参数,则是使用Comparator中的compare()方法进行比较。
Comparator的使用就是委派Delegation机制的体现。需要新建一个类实现Comparator接口,重写compare();使用时,创建一个此类的对象作为外部比较器传递给sort()方法。
Comparable不是委派机制,而是直接在需要的比较ADT中实现Comparable接口,重写compareTo()方法即可
2、CRP原则
Composite Reuse Principle(组合复用原则)就是在一个新的对象里面使用一些已有的对象,使之成为新对象的一部分;新的对象通过向这些对象的委派达到复用已有功能的目的(重用机制——委派)。也就是说,CRP原则更倾向于使用委派而不是继承来实现复用。
注意:“委托”发生在object层面,而“继承”发生在class层面
3、委派方式
依赖 Dependency:临时性的delegation
关联 Association:永久性的delegation
依赖的Delegation关系通过方法的参数传递建立起来,每次都要传入参数,方法结束关系就结束了
关联主要有两种:
(1)组合Composition: 更强的association,但难以变化
在rep成员变量定义时或者构造方法处委派,关系一经确立不能再修改(与类绑定的),对象消失时委派的对象也不复存在
(2)聚合Aggregation: 更弱的association,可动态变化
在带参构造或者专门set方法里通过客户端传递过来的参数确立委派关系,对象消失时,委派对象依然存在。如果提供set方法那么这种关系还能修改。选择性、灵活性更强。
三、框架
框架:一组具体类、抽象类、及其之间的连接关系
白盒框架,通过代码层面的继承进行框架扩展
黑盒框架,通过实现特定接口/delegation进行框架扩展
总结
无