用extends关键字表明正在构造的新类派生于一个已存在的类。
这个已存在的类称为超类(super class)、基类(base class)或父类(parent class)
新类称为子类(subclass)、派生类(derived class)或孩子类(child class)
class Employee {
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String n, double s, int year, int month, int day){
name = n;
salary = s;
hireDay = LocalDate.of(year, month, day);
}
public String getName() {
return name;
}
public double getSalary() {
return salary;
}
public LocalDate getHireDay() {
return hireDay;
}
public void raiseSalary(double byPercent) {
double raise = salary * byPercent / 100;
salary += raise;
}
}
让Manager类继承Employee类(inheritance)
public class Manager extends Employee {
private double bonus; // Manager 比 Employee多了bonus字段
public void setBonus(double bonus) {
this.bonus = bonus;
}
}
Manager类自动继承了超类Employee中的getName等方法和name、salary等字段
设计类时,应当通用的方法抽取到超类
覆盖方法超类的一些方法对子类并不一定适用,需要提供新的方法来覆盖(override)超类的方法
public class Manager extends Employee {
private double bonus;
// ...
// Manager的getSalary方法应该返回工资和奖金的总和
public double getSalary() {
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
}
下面说明两种错误做法:
- 直接return salary + bonus;
只有Employee方法能直接访问Employee类的私有字段。(private只有同类才能访问)
- double baseSalary = getSalary();
希望调用Employee类的公共方法getSalary,但这里由于覆盖了方法,将无限次调用自身
想调用超类Employee中的getSalary方法,可以用super关键字来调用超类的方法
子类构造器public Manager(String name, double salary, int year, int month, int day) {
super(name, salary, year, month, day);
bonus = 0;
}
使用super调用超类的构造器,必须放在子类构造器的第一行
若子类构造器未显式调用超类的构造器,将自动调用超类的无参构造器
若超类没有无参构造器,且在子类的构造器中未显式调用超类的其他构造器,Java编译器就会报错
****this和super的对比****
关键字this两个含义:
- 指示隐式参数的引用调用该类的其他构造器(需放在构造器的第一行)
关键字super两个含义:
- 调用超类的方法调用超类的构造器(需放在构造器的第一行)
public class Test {
public static void main(String[] args) {
var staff = new Employee[3];
Manager boss = new Manager("Carl", 8000, 1987, 12, 15);
boss.setBonus(5000);
staff[0] = boss;
staff[1] = new Employee("Tom", 5000, 1989, 10, 1);
staff[2] = new Employee("Mitch", 4000, 1990 ,3 ,15);
for (Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary() + ",hireDay=" + e.getHireDay());
}
}
这边在输出staff[0]的薪水时,e.getSalary()应该能够执行正确的getSalary方法。
尽管这边e声明为Employee类型,但实际上e既可以引用Employee类型的对象,也可以引用Manager类型的对象。虚拟机知道e实际引导的对象类型。
一个对象变量可以指示多种实际类型的现象称为多态(polymorphism)
在运行时能够自动地选择适当的方法,称为动态绑定(dynamic binding)
若程序运行并且用动态绑定调用方法,虚拟机必须调用与x所引用对象的实际类型对应的方法。假设x的实际类型是D,D是C类的子类。若D类定义了方法f(string),就会调用这个方法;否则将在D类的超类中寻找f(string)。
若是private方法、static方法、final方法或者构造器,编译器可以准确知道调用哪个方法,这称为静态绑定(static binding)



