这周的重点是重载和重写。重载要求两方法的签名必须不同,而重写则要求两方法的签名必须相同。重载可以发生在同一个类中,也可以发生在父类和子类中;重写必须发生在父类和子类中。接口/抽象类不具有构造方法,只有将内部的抽象方法全部实现后的子类才能创造对象。每个子类都是父类,父类能做的事子类必须能做,还要做的更好。
ADT不变量替换前置条件
用ADT不变量取代复杂的前置条件,相当于将复杂的前置条件封装到ADT内部。如果对输入数据的检测代价较高,则将约束传递给用户,即前置条件。
接口
1.实际中更倾向于使用接口定义变量,因为对于接口的多种实现都满足条件。
2.接口中不能含有构造函数,因为接口不能被实例化。接口不能含有具体的实现(比如返回值不能为ArraySet类型)。
3.可以在接口中定义静态方法,在静态方法中返回实现接口的实例化对象。
继承、重载和重写
1.严格继承:子类只能添加新方法,不重写父类中的方法。
2.final修饰的类不可以被继承,final修饰的方法不能被重写,final修饰的属性不能被继承。
3.如果父类中的某个函数实现体为空,则说明其子类都具有这个功能,但是各有差异,没有共性,在每个子类中都需要重写。
4.用super调用父类中被重写的方法。在构造方法中调用父类的构造方法,super语句必须在第一句。
5.含有抽象方法的类是抽象类。接口是一种特殊的抽象类。
6.多态
特殊多态:相同的方法名,不同的参数列表或返回值类型(方法重载)。
参数化多态:泛型。
子类型多态:用接口(父类型)声明变量,用具体的实现赋值。
7.重载方法在编译阶段时决定具体调用哪个方法(静态类型检查),重写在运行时决定具体调用哪个方法(动态类型检查)。
8.重载必须有不同的参数列表;返回值、修饰词、异常可相同可不同;可以在本类或者子类中重载。
9.重载调用例子。具体调用哪个方法,取决于变量被声明的类型。
第二行:如果声明的是子类型,赋值也是子类型。方法调用时不满足子类方法参数要求,满足了父类方法参数要求,则调用父类方法。(重载时父类方法在子类中有备份)
10.重载和重写的区别
泛型
1.通配符:只能在使用时出现,不能在定义中出现。
2.运行时泛型会被擦除,不能使用instanceof()检查泛型种类。
3.不能创建泛型的数组。
子类型
1.子类型的规约不能弱化父类型的规约(从集合角度,子类是父类的真子集)。父类型能做的事子类型同样能做。
2.将子类型转化成父类型是安全的。因为任意的子类都是父类。
不可变类
1.写不可变类的要求
-没有mutator方法
-保证没有方法可以被重写
-成员域用private、final修饰
-防止表示暴露
-重写toString()、hashCode()、clone()、equals()等
2.一般将小的“值类型”设置成不可变类。如实验2的Position类、Piece类。
不可变类型的相等关系
1.相等是一种等价关系。等价关系的性质:自反、对称、传递。
2.用户角度:AF映射到同样的结果,则两个对象等价。
3.外部观察者角度:对两个对象调用任何相同的操作,都得到相同的结果,则认为两对象等价。
4.Java有两种操作判断相等:
-引用等价性(==)指向同一内存区域。一般用来判断基本数据类型。
-对象等价性(equals()),如果不被重写,和引用等价性相同。所以自定义ADT时要重写Object的equals。
5.尽量避免instanceof方法
重写equals方法时,使用继承避免调用instanceof
6.“相等”的对象,其hashCode()的结果必须相等。
7.哈希表工作原理
相等对象的哈希值一定相同,不同对象的哈希值可以相同,但是要尽量避免哈希冲突。
可变类型的相等关系
1.观察等价性:在不改变状态的情况下,两个对象是否看起来一致。
2.行为等价性:调用对象任何方法都展示出一致的结果。
3.可变类相等一般不需要重写equals方法,因为相等即意味着指向同一对象。
4.如果某个可变类对象包含在Set集合类中,当其发生改变时,集合类的行为不确定。就像照完身份证照片再整容。
重写equals方法参考:
List的contains()方法详解以及重写equals()方法时需要注意的地方