Java中的继承和抽象类
继承
在面向对象程序设计中,继承(inheritance)是一个重要的概念。继承的基本思想是,可以基于已有的类创建新的类。继承已存在的类就是复用这些类的方法,而且可以增加一些新的方法和字段,使新类能够适应新的情况。
已有的类称为超类(superclass),继承它的新类称为子类(subclass)。子类能够拥有超类的方法,而且还能新增一些自己特有的方法。在《Java 核心技术·卷Ⅰ》中以员工和经理举例(P160),代码如下
先定义一个员工类Employee,它属于超类
package inheritance;
import java.time.*;
public class Employee {
private String name;
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
{
this.name = name;
this.salary = salary;
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继承员工类,因为经理也是员工
package inheritance;
public class Manager extends Employee {
private double bonus;
/**
* @param name the employee's name
* @param salary the salary
* @param year the hire year
* @param month the hire month
* @param day the hire day
*/
public Manager(String name, double salary, int year, int month, int day)
{
super(name, salary, year, month, day);
bonus = 0;
}
public double getSalary()
{
double baseSalary = super.getSalary();
return baseSalary + bonus;
}
public void setBonus(double bonus)
{
this.bonus = bonus;
}
}
经理比普通员工多了奖金收入。
package inheritance;
/**
* This program demonstrates inheritance.
* @version 1.21 2022-02-06
* @author syuez
*/
public class ManagerTest {
public static void main(String[] args)
{
//construct a Manager object
var boss = new Manager("Syuez", 80000, 1990, 8, 7);
boss.setBonus(5000);
var staff = new Employee[3];
// fill the staff array with Manager and Employee objects
staff[0] = boss;
staff[1] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
staff[2] = new Employee("Tommy Tester", 40000, 1990, 3, 15);
// print out information about all Employee objects
for(Employee e : staff)
System.out.println("name=" + e.getName() + ",salary=" + e.getSalary());
}
}
这个示例中,还使用了多态(polymorphism),for(Employee e : staff)中的e既可以引用Employee类型的对象,也可以引用Manager类型的对象。
当e引用Employee对象时,e.getSalary()调用的是Employee类中的getSalary方法;当e引用Manager对象时,e.getSalary()调用的是Manager类中的getSalary方法。虚拟机知道e实际引用的对象类型,因此能够正确地调用相应的方法。
抽象类
在此之前,我一直不太明白抽象类的意义是什么,直到我看了书上的示例代码时明白了(这真是一本好书啊)。
这里接上继承的例子,定义了一个更具有普遍意义的抽象类Person
package abstractClasses;
public abstract class Person {
public abstract String getDescription();
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
抽象类Person很简单,除了定义具体的字段和方法之外,还定义了一个抽象方法getDescription(),使用abstract关键字描述的抽象方法不需要具体实现。抽象方法充当占位方法的角色,它们在子类中具体实现。即使不含抽象方法,也可以将类声明为抽象类。
分别定义一个Employee类和Student类来继承抽象类Person
package abstractClasses;
import java.time.*;
public class Employee extends Person {
private double salary;
private LocalDate hireDay;
public Employee(String name, double salary, int year, int month, int day)
{
super(name);
this.salary = salary;
hireDay = LocalDate.of(year, month, day);
}
public double getSalary()
{
return salary;
}
public LocalDate getHireDay()
{
return hireDay;
}
@Override
public String getDescription()
{
return String.format("an employee with a salary of $%.2f",salary);
}
public void raiseSalary(double byPercent)
{
double raise = salary * byPercent / 100;
salary += raise;
}
}
package abstractClasses;
public abstract class Person {
public abstract String getDescription();
private String name;
public Person(String name)
{
this.name = name;
}
public String getName()
{
return name;
}
}
package abstractClasses;
/**
* This program demonstrates abstract classes.
* @version 1.01 2022-02-07
* @author syuez
*/
public class PersonTest {
public static void main(String[] args)
{
var people = new Person[2];
// fill the pepole array with Student and Employee objects
people[0] = new Employee("Harry Hacker", 50000, 1989, 10, 1);
people[1] = new Student("Maria Morris", "computer science");
// print out names and descriptions of all Person objects
for(Person p : people)
System.out.println(p.getName() + "," + p.getDescription());
}
}
p.getDescription()可能让人疑惑,这不是调用了一个没有定义的方法吗?由于不能构造抽象类Person的对象,所以变量p永远不会引用Person对象,而是引用诸如Employee或Student这样的具体子类对象,而这些对象中都定义了getDescription()方法。
是不是和继承中的e异曲同工呢?e体现了多态,变量e可以是任意一个子类对象变量,而p又代表了超类也可以调用不同子类对象中的方法。