超类与子类续1

参考《Java核心技术卷1》

多态与动态绑定

Employee.java

package inheritance;

import java.time.LocalDate;

public class Employee {
    private final String name; // 姓名
    private double salary; // 薪水
    private final 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;
    }
}

经理.java

package inheritance;

public class Manager extends Employee {
    private double bonus; // 奖金

    public Manager(String name, double salary, int year, int month, int day) {
        super(name, salary, year, month, day);
    }

    public double getSalary() {
        double baseSalary = super.getSalary(); // 获取基本工资
        return baseSalary + bonus; // 薪水=基本工资+奖金
    }

    public void setBonus(double bonus) {
        this.bonus = bonus;
    }
}

经理Test.java

package inheritance;

public class ManagerTest {
    public static void main(String[] args) {
        Manager boss = new Manager("张三", 8000, 2017, 12, 15);
        boss.setBonus(500);
        Employee[] staff = new Employee[3];
        staff[0] = boss;
        staff[1] = new Employee("李四", 5000, 2019, 10, 1);
        staff[2] = new Employee("王五", 4000, 2020, 3, 15);
        for (Employee e : staff) {
            System.out.printf("%s, %.2f\n", e.getName(), e.getSalary());
        }
    }
}

输出:

张三, 8500.00
李四, 5000.00
王五, 4000.00

这里的e被声明为Employee类型,却引用了Manager类型的对象!这是合法的。并且,观察执行结果,e.getSalary()会选出正确的getSalary方法。

进一步简化、改写代码:

package inheritance;

public class ManagerTest {
    public static void main(String[] args) {
        Manager boss = new Manager("张三", 8000, 2017, 12, 15);
        boss.setBonus(500);

        Employee e = new Employee("李四", 5000, 2019, 10, 1);
        System.out.printf("%s, %.2f\n", e.getName(), e.getSalary());
        // => 李四, 5000.00

        e = boss;
        System.out.printf("%s, %.2f\n", e.getName(), e.getSalary());
        // => 张三, 8500.00
    }
}

实际上,e既可以引用Employee类型的对象,也可以引用Manager类型的对象。

当e引用Employee对象时,e.getSalary()调用的是Employee类中的getSalary方法;当e引用Manager对象时,e.getSalary()调用的则是Manager类中的getSalary方法。虚拟机知道e实际引用的对象类型,因此能够调用正确的方法

一个对象变量(例如,变量e)可以指示多种实际类型,这一点称为多态(polymorphism)。在运行时能够自动地选择适当的方法,这称为动态绑定(dynamic binding)。

继承层次结构

秘书.java

package inheritance;

public class Secretary extends Employee {
    public Secretary(String name, double salary, int year, int month, int day) {
        super(name, salary, year, month, day);
    }

    @Override
    public double getSalary() {
        System.out.println("秘书类中定义的getSalary被调用了");
        return super.getSalary();
    }
}

总经理Test.java

package inheritance;

public class ExecutiveTest {
    public static void main(String[] args) {
        Employee[] staff = new Employee[3];
        staff[0] = new Secretary("小张三", 8000, 2024, 10, 10);
        staff[1] = new Programmer("李四儿", 20000, 2024, 10, 10);
        staff[2] = new Executive("小王五", 15000, 2024, 10, 10);

        for (Employee e : staff) {
            // 一个对象变量可以指示多种实际类型即"多态"
            System.out.printf("%s, %.2f\n", e.getName(), e.getSalary());
        }
        // 上面循环语句的等价顺序语句是什么?写完后请改成等价的顺序语句
    }
}

输出:

秘书类中定义的getSalary被调用了
小张三, 8000.00
程序员类中定义的getSalary被调用了
李四儿, 20000.00
总经理类中定义的getSalary被调用了
小王五, 15000.00

多态

package inheritance;

public class MyTest {
    public static void main(String[] args) {
        // 1 可将子类对象赋给超类变量
        Employee e;
        e = new Employee("张三", 1000, 2024, 9, 30); //"需要"一个员工类对象
        e = new Manager("李四", 1000, 2024, 9, 30); //把经理类放这边也可以

        // 2 当超类变量引用子类对象时可以调用哪些方法?
        Manager m = new Manager("李大头", 1000, 2024, 9, 30);
        Employee aEmployee = m; //m与aEmployee引用了同一个对象!
        //但"编译器"只将aEmployee看成是一个Employee对象
        m.setBonus(500); //m是Manager类变量,调用Manager类中定义的方法是合法的!
        //aEmployee.setBonus(500); //这句合法吗?如果不合法是为什么?

        // 3 子类变量不能引用超类对象
        //Manager manager = new Employee("李大头", 1000, 2024, 9, 30);
        //上面代码能运行吗?如果如果不能原因是什么?
        //怎样解决该问题?前提是什么?
    }
}

PrimaryStudent练习

https://liaoxuefeng.com/books/java/oop/basic/inherit/index.html

public class Main {
    public static void main(String[] args) {
        Person p = new Person("小明", 12);
        Student s = new Student("小红", 20, 99);
        // TODO: 定义PrimaryStudent,从Student继承,新增grade字段:
        Student ps = new PrimaryStudent("小军", 9, 100, 5);
        System.out.println(ps.getScore());
    }
}

class Person {
    protected String name;
    protected int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() { return name; }
    public void setName(String name) { this.name = name; }

    public int getAge() { return age; }
    public void setAge(int age) { this.age = age; }
}

class Student extends Person {
    protected int score;

    public Student(String name, int age, int score) {
        super(name, age);
        this.score = score;
    }

    public int getScore() { return score; }
}

class PrimaryStudent extends Student {
    protected int grade;

    public PrimaryStudent(String name, int age, int score, int grade) {
        super(name, age, score);
        this.grade = grade;
    }
}

 

posted @ 2024-10-31 11:21  xkfx  阅读(160)  评论(0编辑  收藏  举报