继承

  • 覆盖方法

超类中有些方法对于子类并不适用,为此子类需要覆盖超类的方法。

子类和超类方法签名(方法名+参数列表)相同,则为覆盖方法。

覆盖方法的返回类型(可协变返回类型)

返回类型不是方法签名的一部分,覆盖方法时要保证返回类型的兼容性,允许子类覆盖方法返回类型是超类返回类型的子类型。

内联

一个方法没有被覆盖并且很短,编译器会对其进行优化,避免动态绑定带来的系统开销。

  • 重载方法

方法名称相同,参数列表不相同的方法为重载方法,一个类中就可以存在这样的关系,而覆盖是子类方法和超类方法之间的关系。


  • 私有域的访问问题

尽管每个子类对象都拥有超类的私有域,但是在子类的方法中不能直接访问这个私有域,必须通过访问器访问。

例如:

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赋值给一个对象变量,只是一个指示编译器调用超类方法的特殊关键字。


  • 方法调用

  1. 假设存在x.f(param),x为C类的一个对象。则会先筛选C类中所有名为f的方法和C类的超类的public的f方法(C不能直接访问超类的私有域和私有方法);

  2. 编译器查看参数类型,若找到匹配的,找不到可以使用类型转换,则直接选择这个方法(重载过程);

  3. 若出现private、static、final方法,则直接是静态绑定,因为这些都是本类才能调用的方法,不依赖于对象。而调用方法依赖于隐式参数的实际类型,则是动态绑定;

  4. 运用了动态绑定时,首先在实际类型的类里找方法,若找不到再去实际类型的超类里面找。

方法表

为了减小查找方法的开销,虚拟机使用了方法表;

假设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域。

你可能感兴趣的:(继承)