-
覆盖方法
超类中有些方法对于子类并不适用,为此子类需要覆盖超类的方法。
子类和超类方法签名(方法名+参数列表)相同,则为覆盖方法。
覆盖方法的返回类型(可协变返回类型)
返回类型不是方法签名的一部分,覆盖方法时要保证返回类型的兼容性,允许子类覆盖方法返回类型是超类返回类型的子类型。
内联
一个方法没有被覆盖并且很短,编译器会对其进行优化,避免动态绑定带来的系统开销。
-
重载方法
方法名称相同,参数列表不相同的方法为重载方法,一个类中就可以存在这样的关系,而覆盖是子类方法和超类方法之间的关系。
-
私有域的访问问题
尽管每个子类对象都拥有超类的私有域,但是在子类的方法中不能直接访问这个私有域,必须通过访问器访问。
例如:
Employee.java
public class Employee{
private double salary;
...
public LocalDate getHireDay(){
return hireDay;
}
}
Manager.java
public class Manager extends Employee{
public double getSalary(){
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
/* error:子类方法不能访问超类的私有域
public double getSalary(){
double baseSalary = salary;
return baseSalary + bonus;
}
*/
}
-
super与this
this:返回对象的引用;
super:返回的不是对象引用,不能将super赋值给一个对象变量,只是一个指示编译器调用超类方法的特殊关键字。
-
方法调用
假设存在x.f(param),x为C类的一个对象。则会先筛选C类中所有名为f的方法和C类的超类的public的f方法(C不能直接访问超类的私有域和私有方法);
编译器查看参数类型,若找到匹配的,找不到可以使用类型转换,则直接选择这个方法(重载过程);
若出现private、static、final方法,则直接是静态绑定,因为这些都是本类才能调用的方法,不依赖于对象。而调用方法依赖于隐式参数的实际类型,则是动态绑定;
运用了动态绑定时,首先在实际类型的类里找方法,若找不到再去实际类型的超类里面找。
方法表
为了减小查找方法的开销,虚拟机使用了方法表;
假设D是C的子类,则调用d.f(param)方法时,首先去D的方法表中找;
若查找不到,则到C的隐式参数方法表中查找(依赖于隐式参数的方法,即非private、sstatic、final)。
-
超类与子类方法可见性
子类覆盖超类方法时,子类方法可见性不能低于超类方法可见性,如超类使用了public,则子类也要使用public。因为如果不这么做,c引用了子类D的一个对象d,调用c.fun(param)(可见性为public),而D类对fun的可见性为private,则必然会出错。
-
阻止继承——使用final
希望阻止人们利用某个类定义子类,不允许被拓展的类被称为final类。
final类中所有的方法也默认被声明为final(即使没有显式写出来),但域并没有被默认声明为final。
子类不能覆盖final方法,因此final方法也是静态绑定的。
将类或方法声明为final的主要目的
防止子类覆写方法,确保他们在子类中语义不变。
-
强制类型转换
将一个子类引用赋给超类变量不需要强制转换;
将一个超类引用赋给子类变量需要类型转换。
例如如下超类赋给子类(Manager extends Empolyee):
Employee[] employees = new Employee[3];
Manager managerOld = new Manager();
//子类引用赋值给超类变量不需要强制类型转换
employees[0] = managerOld;
employees[1] = new Employee();
/**
*尽管employee[0]引用的实际类型是Manager
*但编译器并不知道
*表面还是超类引用
*赋值给子类变量需要强制类型转换
*/
Manager managerNew = (Manager)employees[0];
/**
*养成良好习惯,提前判断引用的实际类型,防止向下类型转换的“谎报”错误
*/
if(employee[1].instanceof Manager){
//由于employees[1]实际类型是Employee,因此不会执行
Manager boss = employees[1];
}
- 特点
向下类型转换时需要使用强制类型转换;
只能在继承层次内进行强制类型转换;
将超类转换为子类前,需要使用instanceof检查实际类型;
如果只是需要子类的覆盖方法,可以不转换,因为动态绑定可以准确调用到子类的覆盖方法;
只有需要使用子类特定方法或域时才需要强制类型转换;
-
受保护访问
任何被声明为private的域和方法都不能被其他类访问,包括子类;
使用受访问保护的protected让子类可以访问超类某个域,但是例如Manager可以访问Manager对象某个protected域,但是不能访问Employee对象的protected域。