《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.2 覆盖方法

子类继承了超类中的所有方法和域。但是,超类Empolyee中的有些方法对子类Manager并不一定适用。具体来说,Manager类中的getSalary方法应该返回薪水和奖金的总和(超类中没有奖金)。为此,需要提供一个新的方法来覆盖(override)

超类中的这个方法:

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

在Manager类中若改写成如下:

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

不能运行,原因是Manager类的getSalary方法不能直接的访问超类的私有域(私有域只能本类访问)。也就是说,尽管每个Manager对象都拥有一个名为salary的域,但在Manager类的getSalary方法并不能直接的访问salary域,只有Employee类的方法才能访问私有部分。如果Manager类的方法一定要访问私有域,就必须借助公共接口,Employee类中的getSalary就是这么一个接口。

现在,将对salary域的访问替换成调用getSalary方法。

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

但是,发现还是不能运行。问题出在了调用getSalary的语句上,这是因为Manager类也有一个getSalary方法(就是正在实现的这个方法),所以这条语句会导致程序无限次的调用自己直到崩溃。

我们希望调用的是超类中的getSalary方法,而不是当前这个类的。为此,可以使用关键字super:

super.getSalary();

这条语句才是调用的Employee类中的getSalary方法。所以Manager类的getSalary方法的正确书写格式为:

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

 

5.1.3 子类构造器

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

由于Manager类的构造器不能访问Employee类的私有域,所以必须利用Employee类的构造器对这部分私有域进行初始化,我们可以通过super实现对超类构造器的调用。使用super调用超类构造器必须放在子类构造器的第一条语句。

如果子类构造器没有显式的调用超类的构造器,则将自动地调用超类无参数构造器。如果超类没有不带参数的构造器(但是含有带参数的构造器),并且在子类中又没有显式的调用超类其他构造器,则java编译器会报错。(因为如果类中没有构造器,编译器会自动的为该类添加一个默认的无参数构造器,若已有构造器,则不会自动添加)《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.5 多态

一个对象变量可以指示多种实际类型的现象被称为多态(polymorphism)。在运行时能够自动地选择调用哪个方法的现象称为动态绑定。(如果是private、static、final 或者 构造器方法,编译器将可以准确的知道调用哪个方法,这种调用方式称静态绑定)

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

在这个例子中,staff[0] 和 boss 引用同一个对象,但编译器将staff[0]看做是Employee对象,这就意味着,可以这样调用

boss.setBonus(5000); // OK

但不能这样调用

staff[0].setBonus(5000); //Error

这是因为staff[0]的声明类型为Employee类,而setBonus不是Employee中的方法。

警告:在Java中,子类数组的引用可以转换成超类数组的引用,而不需要强制类型转换。例如

Manager[] managers = new Manager[10];

Employee[] staff = managers;

这么转换完全是合法的,编译器不会报错。但是,要切记,managers和staff引用的是同一个数组,若

staff[0] = new Employee(...);

编译器接纳了个这个赋值操作。但是,staff[0] 和 managers[0] 引用的是同一个对象,似乎我们把一个普通员工擅自归入经理行列中了,这是一种很忌讳发生的情形,当调用managers[0].setBonus(5000)的时候,将会导致调用一个不存在的实例域,进而扰乱相邻存储空间的内容。

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.7 阻止继承(扩展):final类和方法

final类不能被继承,final方法不能被重写,final类中的所有方法自动的成为final方法(不包括域)。

例如,String类是final类

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.8 强制类型转换

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

  • 只能在继承层次内进行类型转换
  • 在将超类转换成子类之前,应该使用instanceof进行检查

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.9 抽象类

抽象类可以包括抽象方法、具体方法、具体数据

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

含有抽象方法的类必须定义为抽象类。

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类

5.1.10 受保护访问

protected可以让子类和本包(安全性差)获得该域的访问权限。

《Java核心技术卷Ⅰ》读书笔记——5.1 类、超类和子类