第四章:多态与动态绑定机制

多态

方法或对象具有多种形态。多态是建立在封装和继承基础之上

代码演示:方法的多态

虽然方法名相同,但是有着不同的作用(形态)
两个sum方法实现了重载,两个method方法实现了重写

public class Test {
    public static void main(String[] args) {
        A a = new A();
        B b = new B();
        a.method();     // 运行结果:父类的成员方法
        b.method();     // 运行结果:子类的成员方法
        System.out.println(b.sum(2,3));      // 运行结果:5
        System.out.println(b.sum(2,3,3));    // 运行结果:8
    }
}
class A {
    public void method() {
        System.out.println("父类的成员方法");
    }
}
class B extends A {
    @Override
    public void method() {
        System.out.println("子类的成员方法");
    }
    
    public static int sum(int num1,int num2) {
        return num1+num2;
    }
    public static int sum(int num1,int num2,int num3) {
        return num1+num2+num3;
    }
}

对象的多态

  1. 一个对象 编译类型运行类型 不同

  2. 等号左边是编译类型,等号右边是运行类型

  3. 运行期类型可能会发生变化

代码演示:对象的多态

同一个对象可以是Dog类,也可以是Cat类

public class Test {
    public static void main(String[] args) {
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();  
        animal.eat();	// 运行:Dog类型中的eat方法
        
        // animal运行类型是Cat
        animal = new Cat();
        animal.eat();	// 运行:Cat类型中的eat方法
    }
}

class Animal {                                                                                                                                                                                                                               
    public void eat() {
        System.out.println("动物吃食物");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫吃鱼");
    }
}

向上造型

  1. 向上造型的本质:父类的引用指向子类的对象

  2. 向上造型的语法:父类类型 引用名 = new 子类类型();

  3. 向上造型的特点
    a. 可以调用父类中所以成员(需遵守访问权限)
    b. 不可以调用子类的特有的成员
    c. 最终运行结果由子类的具体实现

注意:属性没有重写之说,属性的值由编译类型决定

代码演示:向上造型

public class Test {
    public static void main(String[] args) {

        Animal animal = new Dog();
        animal.eat();       // 运行结果:狗吃肉
        animal.sleep();     // 运行结果:动物睡觉觉
        
        // 注意:animal对象无法访问子类的特有的方法run()
    }
}

class Animal {
    public void sleep() {
        System.out.println("动物睡觉觉");
    }

    public void eat() {
        System.out.println("动物吃食物");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void run() {
        System.out.println("狗在跑步");
    }
}

向下转型

  1. 向下转型的语法:子类类型 引用名 = (子类类型) 父类引用;

  2. 向下转型的特点
    a. 只能强转父类的引用,不能强转父类的对象
    b. 要求父类引用必须指向的是当前目标类型的对象
    c. 当向下转型后,可以调用父子类类型中的所有成员(需遵守访问权限)

代码演示:向下转型和 instanceof关键字

public class Test {
    public static void main(String[] args) {
        // animal编译类型是Animal,运行类型是Dog
        Animal animal = new Dog();

        /**错误示范
            Cat cat = (Cat) animal; 程序报错:ClassCastException(类转换异常)
            为了解决在编译期确保类的成功转换,我们可通过instanceof关键字
            先判断类型转换异常,再执行转换

         */
        if(animal instanceof Cat) {
            Cat cat = (Cat) animal;
            cat.work();
        }else {
            Dog dog = (Dog) animal;
            dog.work();
            dog.eat();
            dog.sleep();
        }
    }
}

class Animal {
    public void sleep() {
        System.out.println("动物睡觉觉");
    }

    public void eat() {
        System.out.println("动物吃食物");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }

    public void work() {
        System.out.println("狗在看大门");
    }
}

class Cat extends Animal {
    public void work() {
        System.out.println("猫在捉老鼠");
    }
}

Java的动态绑定机制

当调用对象方法时,该方法和该对象的内存地址/运行类型绑定

当调用对象属性时,没有动态绑定机制,哪里声明,哪里使用

代码演示:动态绑定机制

public class Test {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());    // 运行结果:60
        /** a.sum() 的动态绑定机制
         *  对于调用方法,优先调用运行期类型中的方法(getI())
         */
        System.out.println(a.sum1());   // 运行结果:40
        /** a.sum1() 的动态绑定机制
         *  对于调用属性,没有绑定机制这么一说,直接调用A类的变量i
         */
    }
}
class A {
    public int i = 10;
    public int getI() {
        return i;
    }
    public int sum() {
        return getI() + 40;
    }
    public int sum1() {
        return i + 30;
    }
}
class B extends A {
    public int i = 20;
    public int getI() {
        return i;
    }
}

代码演示:多态数组

**代码分析**
1. 四个类:父类Person、子类StudentTeacher以及测试类(两个子类都继承了父类)
2. 父类具有姓名与年龄的共同属性,学生类与老师类分别具有分数与薪资的特有属性
3. 创建多态数组,通过向上造型的方式将每个对象的属性进行赋值并访问
4. 通过向下转型的方式将访问运行类型特有的成员方法
public class Test {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("赵四", 23);
        persons[1] = new Student("小华", 23, 100);
        persons[2] = new Student("小明", 12, 10);
        persons[3] = new Teacher("老张", 28, 3000);
        persons[4] = new Teacher("老陈", 26, 2000);
        
        for (int i = 0; i < persons.length; i++) {
            System.out.println(persons[i].say());
            if (persons[i] instanceof Student) {
                Student s = (Student) persons[i];	// 先向下转型
                s.study();							// 再调用方法
            } else if (persons[i] instanceof Teacher) {
                ((Teacher) persons[i]).teach();		// 一步到位
            } else if (persons[i] instanceof Person) {
            } else {
                System.out.println("类型有误,自行解决");
            }
        }
    }
}

class Person {
    private String name;
    private int age;

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

    public String getName() {
        return name;
    }

    public int getAge() {
        return age;
    }

    public String say() {
        return getName() + "\t" + getAge();
    }
}

class Student extends Person {
    private double score;

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

    public double getScore() {
        return score;
    }

    @Override
    public String say() {
        return "学生" + super.say() + " 分数:" + getScore();
    }

    public void study() {
        System.out.println("学生 " + getName() + "在学java...");
    }
}

class Teacher extends Person {
    private int salary;

    public Teacher(String name, int age, int salary) {
        super(name, age);
        this.salary = salary;
    }

    public int getSalary() {
        return salary;
    }

    @Override
    public String say() {
        return "老师 " + super.say() + " 薪资:" + getSalary();
    }

    public void teach() {
        System.out.println("老师:" + getName() + ",在教java...");
    }
}

代码演示:多态参数

多态数组:方法定义的形参类型是父类类型,实参类型是子类类型

**代码分析**
1. 一共有四个类分别是父类(Employee),子类(ManagerWorker),测试类(Test2. 员工类的私有属性name和salary,计算年工资getAnnual方法
3. 经理类特有属性奖金bonus和管理manage方法
4. 员工类特有方法work
5. 测试类中有showEmpAnnal(Employee e)的方法,获取员工的年薪
6. 测试类中另一个testWork(Employee e)的方法,分别调用经理的管理方法和员工工作的方法

对于个人易错点,没有将56理解清楚,导致无法以向上造型与向下转型的方式进行调用方法
public class Test {
    public static void main(String[] args) {
        Worker worker = new Worker("强哥", 3000);
        Manager manager = new Manager("小赵", 20000, 6000);
        Test test = new Test();
        test.showEmpAnnual(worker);				// 实参是子类类型
        test.showEmpAnnual(manager);
        test.testWork(worker);
        test.testWork(manager);
    }

    public void showEmpAnnual(Employee e) {		// 方法的形参是父类类型
        System.out.println(e.getAnnual());
    }

    public void testWork(Employee e) {
        if (e instanceof Worker) {
            ((Worker) e).work();
        } else if (e instanceof Manager) {
            ((Manager) e).work();
        } else {
            System.out.println("对象有误");
        }
    }
}

class Employee {
    private String name;
    private int salary;

    public Employee(String name, int salary) {
        this.name = name;
        this.salary = salary;
    }

    public String getName() {
        return name;
    }

    public int getSalary() {
        return salary;
    }

    public int getAnnual() {
        return getSalary() * 12;
    }
}

class Worker extends Employee {
    public Worker(String name, int salary) {
        super(name, salary);
    }

    public void work() {
        System.out.println("工人:" + getName() + ",正在搬砖");
    }

    @Override
    public int getAnnual() {
        return super.getAnnual();
    }
}

class Manager extends Employee {
    private int bonus;

    public Manager(String name, int salary, int bonus) {
        super(name, salary);
        this.bonus = bonus;
    }

    public int getBonus() {
        return bonus;
    }

    public void work() {
        System.out.println("经理:" + getName() + ",正在监工");
    }

    @Override
    public int getAnnual() {
        return super.getAnnual() + getBonus();
    }
}

`

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值