Java笔记三:继承(inheritance)
例如:
代码如下 | 复制代码 |
class Manager extends Employee { //Manager 类继承Employee类,同时添加新的方法setBonus和新的域bonus public void setBonus(double s) { bonus = s; } ... private double bonus; } |
1. 子类方法覆盖(override)超类方法
假设Manager类继承于Employee类,Employee有name、salary和hireDay三个域,Manager又新增了bonus一个域。Employee有方法getSalary(),现在Manager的计算薪水的方式不一样,需要重写getSalary(),以覆盖Employee类的此方法。
需要注意的是子类不能直接访问超类的私有域(假设salary为私有域),那么就不能使用下面这种方法:
public double getSalary()
{
return salary + bonus; //error. salary 不能被访问到
}
Java利用另一个方法解决上面这个问题,即使用超类的方法简介获取域的值。
public double getSalary()
{
return super.getSalary() + bonus;
}
注释:super不是对象引用,不能把它覆给另一个对象变量,它只是一个指示编译器调用超类方法的特有关键字。
super的另一个应用就是在构造器中。子类构造器需要调用超类的某些构造器以初始化一个些超类的域(尤其是私有域)。
代码如下 | 复制代码 |
public Manager(String n, double s, int year, int month, int day) |
2. 继承层次
由一个公共超类派生出来的所有类的集合被称为继承层次(inheritance hierarchy),在继承层次中由某个特定类到其祖先的路径被称为该类的继承链(inheritance chain)。
3. 多态(polymorphism)和动态绑定(dynamic binding)
一个对象变量可以引用多种实际类型的现象称多态;
在运行时能够自动地选择调用哪个方法的现象称为动态绑定。
例如:
代码如下 | 复制代码 |
Manager boss = new Manager("boss", 80000, 1987, 12, 15); Employee[] staff = new Employee[3]; staff[0] = boss; //多态:变量e既可以引用Manager对象,又可以引用Employee对象 Employee e; |
对象方法执行过程的详细:
① 编译器查看对象的声明类型和方法名,获取所有可能被调用的候选方法;
② 编译器查看那调用方法时提供的参数类型,如果与某个候选方法的参数类型完全相同,则选择这个方法。这个过程被称为重载解析(overloading resolution);
③ 前面两步已经获得需要调用的方法名字和参数类型,接下来如果是private方法、static方法、final方法或者构造器,那么编译器将可以准确地知道应该调用哪个方法,这种调用方式被称为静态绑定(static binding)。与此对应的是,调用的方法依赖于隐式参数的实际类型,并且在运行时实现动态绑定;
④ 哪个动态绑定调用方法时,虚拟机一定调用与隐式参数所引用对象的实际类型最合适的那个类的方法。
注:虚拟机为了避免每次都进行搜索方法,所以预先为每个类创建一个方法表(method table),其中列举了所有方法的签名和实际调用的方法。只需查表,所以更快。
4. 阻止继承:final类和方法
将类声明为final,则会其他类对该类进行继承。将类中的方法声明为final,子类就不能覆盖这个方法了。final类中的所有方法自动地称为final方法。
代码如下 | 复制代码 |
final class Executive extends Manager { ... }class Employee { ... public final String getName() { return name; } ... } |
注释:域也可以声明为final。对于final域来说,只是在构造对象之后不能再修改它的值而已。我们将方法或者类声明为final的主要原因是确保他们不会在子类中改变语义。有些程序员建议是除非我们有足够的理由使用多态性,否则应该将所有的方法声明为final。这样可以减少动态绑定过程带来的系统开销,提高程序性能。但是,随着Java虚拟机的发展,其处理能力越来越强,编译器已经可以很短的时间内知道类之间的继承关系,并且能够很快地检测出是否存在覆盖的方法。
5. 强制类型转换
•只能在继承层次内进行类型转换
•在将超类转换成子类之前,应该使用instanceof进行检查
代码如下 | 复制代码 |
Employee[] staff = new Employee[3]; staff[0] = new Manager(...); staff[1] = new Employee(...); staff[2] = new Employee(...); Manager boss; if(staff[1] instanceof Manager) { boss = (Manager) staff[1]; } |
6. 抽象类
抽象类和抽象方法都用abstract关键字声明。
包含一个或多个抽象方法的类必须声明为抽象类。
在抽象类中还可以有域和具体方法的实现。
抽象类不能被实例化,即不能创建抽象类的对象。
代码如下 | 复制代码 |
abstract class Person public String getName() private String name; |
需要注意的是虽然我们不能将抽象类实例化,但是可以定义一个抽象类的对象变量,但它只能引用非抽象子类的对象,例如:
//这里的Student类是Person类的子类
Person p = new Student("Raysmond","1024");7. 受保护访问
•private —— 仅对本类可见
•public —— 对所有类可见
•protected —— 对本包和所有子类可见
•默认情况下是对本包可见
8. 所类的超类——Object类
Java中所有类的超类是Object,这是不需要在类中声明的,Java中每一个类都由它派生出来。需要注意两点。
•可以使用Object类型的变量引用任何对象
Object obj = new Student("Raysmond","1024");•在Java中只有基本类型不是对象,其他数据类型,例如数组,都是对象,都拓展于Object类。
补充:Jsp教程,Java基础