定义子类
关键词extends表明正在构造的新类派生于一个已存在的类。这个已存在的类1称为超类、基类或父类;新类称为子类、派生类或孩子类。
1 | public class Manger extends Employee |
覆盖方法
超类中的有些方法对子类并不一定适用。为此,需要提供一个新的方法来覆盖超类中的这个方法。
当我们希望调用超类中的方法,而不是当前类的这个方法,可以用特殊的关键词super来解决。
继承绝对不会删除任何字段或方法。
子类构造器
当子类的构造器不能访问父类的私有字段时,则必须通过一个构造器来初始化这些私有字段。可以利用特殊的super语法调用这个构造器。使用super调用构造器的语句必须是子类构造器的第一条语句。
如果子类构造器没有显示地调用超类的构造器,将自动调用超类的无参数构造器。如果超类没有无参数构造器,并且在子类的构造器中又没有显示地调用超类的其他构造器,java编译器就会报告一个错误。
多态
一个对象变量可以指示多种实际类型的现象被称为多态。
在运行是能够自动地选择适当的方法,称为动态绑定。
替换原则:程序中出现超类对象的任何地方都可以使用子类对象替换。
在java程序设计语言中,对象变量是多态的。
理解方法调用
(1)编译器查看对象的声明类型和方法名。
(2)接下来,编译器要确定方法调用中提供的参数类型。方法的名字和参数列表称为方法的签名。
(3)如果是private方法,static方法,final方法或者构造器,那么编译器将可以准确地知道应该调用哪个方法,这称为静态绑定。
(4)程序运行并且采用动态绑定调用方法时,虚拟机必须调用与x所引用对象的实际类型对应的那个方法。
警告:在覆盖一个方法时,子类方法不能低于超类方法的可见性。特别是,如果超类方法时public,子类方法必须也要声明为public。
阻止继承
有时候,我们可能希望阻止人们利用某个类定义子类。不允许扩展的类被称为final类。如果在定义类的时候使用了final修饰符就表示这个类是final类。
类中的某个特定方法也可以被声明为final。如果这样做,子类就不能覆盖这个方法(final类中的所有方法自动地成为final方法)。
如果一个方法没有被覆盖并且很短,编译器就能对它进行优化处理,这个过程称为内联。
强制类型转换
只能在继承层次内进行强制类型转换。
在将超类强制转换成子类之前,应该使用instanceof进行检查。
抽象类
使用abstract关键字,则不需要实现该方法。
为了提高程序的清晰度,包含一个或多个抽象方法的类本身必须被声明为抽象的。
扩展抽象类可以有两种选择。一种是在子类中保留抽象类中的部分或所有抽象方法仍未定义,这样就必须将子类也标记为抽象类;另一种做法是定义全部方法,这样一来,子类就不是抽象的了。
即使不含抽象方法,也可以将类声明为抽象类。
抽象类不能实例化。
受保护访问
子类也无法访问父类的私有对象。
当希望允许子类的访问父类的某个字段。为此,需要将这些类方法或字段声明为受保护。
在java中保护字段只能由同一个包的类访问。
object类型变量
在java中,只有基本类型不是对象,例如,数值、字符和布尔类型的值都不是对象。
相等测试与继承
java语言规范要求equals方法具有以下特性:
(1)自反性
对于任何非空引用想,x.equals(x)应该返回true。
(2)对称性
对于任何引用x和y,当且仅当y.equals(x)返回true时,x.equals(y)返回true。
(3)传递性
对于任何引用x,y,z,如果x.equlas(y)返回true,y.equals(z)返回true,x.equals(z)也应该返回true。
(4)一致性
如果x和y引用的对象没有发生变化,反复调用x.equals(y)应该返回同样的结果。
(5)对于任何非空引用x,x.equals(null)应该返回fasle
hasCode方法
散列码是由对象导出的一个整型值。散列码是没有规律的。如果x和y是两个不同的对象,x.hasCode()与y.hasCode()基本上不会相同。
如果重新定义了equals方法,就必须为用户可能插入散列表的对象重新定义hasCode方法。
泛型数组列表
一旦能够确认数组列表的大小将保持恒定,不再发生变化,就可以调用trimToSize方法。这个方法将存储块的大小调整为保存当前元素数量所需要的存储空间。垃圾回收器将回收多余的存储空间。
一旦削减了数组列表的大小,添加新元素就需要花时间再次移动存储块,所以应该在确认不会再向数组列表添加任何元素时再调用trimToSize。
参数数量可变的方法
1 | System.out.printf("%d",n); |
这两条语句都调用同一个方法,不过一个调用有两个参数,一个有三个。
printf方法是这样定义的:
1 | public class PrintStream |
继承的设计技巧
(1)将公共操作和字段放在超类中。
(2)不要使用受保护的字段。
(3)使用继承实现“is-a”关系。
(4)除非所有继承的方法都有意义,否则不要使用继承。
(5)在覆盖方法时,不要改变预期的行为。
(6)使用多态,而不要使用类型信息。
(7)不要滥用反射。