Java学习笔记 --- 面向对象之多态

一、基本介绍

方法或对象具有多种形态,是面向对象的三大特征,多态是建立在封装和继承之上的

二、多态的具体体现

1、方法的多态:

重写和重载就体现多态

案例演示:

package com.javase.poly_;

public class PloyMethod {
    public static void main(String[] args) {
        //方法重载体现多态
        A a = new A();
        //我们传入不同的参数,调用不同的方法
        System.out.println(a.sum(10, 20));
        System.out.println(a.sum(10, 20, 30));

        //方法重写体现多态
        B b = new B();
        a.say();
        b.say();
        //虽然是同一方法,但根据对象不一样调用结果是不一样的。
    }
}

class B {//父类
    public void say() {
        System.out.println("B say 方法被调用...");
    }
}

class A extends B {//子类
    public int sum(int n1, int n2) {
        return n1 + n2;
    }
    public int sum(int n1, int n2, int n3) {
        return n1 + n2 + n3;
    }
    public void say() {
        System.out.println("A say 方法被调用...");
    }
}

2、对象的多态

1.一个对象的编译类型和运行类型可以不一致。

2.编译类型在定义对象时,就确定了,不能改变

3.运行类型是可以变化的。

4.编译类型看定义时 = 号的左边,运行类型看 = 号的右边。

案例演示:

Animal类

package com.javase.poly_.objectpoly_;

public class Animal {
    public void cry() {
        System.out.println("动物叫...");
    }
}

Dog类:

package com.javase.poly_.objectpoly_;

public class Dog extends Animal{
    public void cry() {
        System.out.println("小狗汪汪叫...");
    }
}

Cat类:

package com.javase.poly_.objectpoly_;

import com.javase.super_.A;

public class Cat extends Animal {
    public void cry() {
        System.out.println("小猫喵喵叫...");
    }
}

输出:

package com.javase.poly_.objectpoly_;

public class PolyObject {
    public static void main(String[] args) {
        //animal编译类型是 Animal ,运行类型是Dog
        Animal animal = new Dog();
        animal.cry();//因为animal运行类型是Dog,所以会调用Dog里面的cry方法
        animal = new Cat();
        animal.cry();//因为animal运行类型变成了Cat,所以会调用Cat里面的cry方法
    }
}

Java学习笔记 --- 面向对象之多态_第1张图片

三、多态的注意事项和细节讨论

多态的前提是:两个对象(类)存在继承关系

1、多态的向上转型

本质上,父类的引用指向了子类对象。

在语法上:父类类型  引用名 = new 子类类型();

编译类型看左边,运行类型看右边,可以调用父类中的所有成员,但必须遵守访问权限,不能调用子类中特有成员,最终运行效果看子类的具体实现。

案例演示:

package com.javase.poly_.detail_;

public class Animal {
    public void eat() {
        System.out.println("吃");
    }
    public void run() {
        System.out.println("跑");
    }
}
package com.javase.poly_.detail_;

public class Cat extends Animal {
    public void eat() {//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse() {//特有方法
        System.out.println("猫抓老鼠");
    }
}

输出:

package com.javase.poly_.detail_;

public class PolyDetail {
    public static void main(String[] args) {
        Animal animal = new Cat();
        Object obj = new Cat();//Object也是Cat父类

        //最终运行效果看子类的具体实现,即调用方法时,从子类开始查找方法
        animal.eat();//猫吃鱼
        animal.run();//跑
    }
}

2、 多态的向下转型

在语法上:子类类型 引用名 = (子类类型)父类引用

只能强转父类引用,不能强转父类对象

要求父类的引用必须指向的是当前目标类型的对象

当向下转型后,可以调用子类类型中所有的成员

案例演示:

package com.javase.poly_.detail_;

public class Animal {
    public void eat() {
        System.out.println("吃");
    }
    public void run() {
        System.out.println("跑");
    }
}
package com.javase.poly_.detail_;

public class Cat extends Animal {
    public void eat() {//方法重写
        System.out.println("猫吃鱼");
    }
    public void catchMouse() {//特有方法
        System.out.println("猫抓老鼠");
    }
}

输出

package com.javase.poly_.detail_;

public class PolyDetail {
    public static void main(String[] args) {
        Animal animal = new Cat();

        //多态的向下转型
        Cat cat = (Cat) animal;//编译类型是Cat 运行类型也是Cat
        cat.catchMouse();//可以调用子类里面的特有方法
    }
}

 3、属性没有重写,属性的值看编译类型

package com.javase.poly_.detail_;

public class PolyDetail01 {
    public static void main(String[] args) {
        //编译类型是Base 运行类型是 Sun
        Base b = new Sun();
        System.out.println(b.n1);//属性的值看编译类型,结果为10
        Sun sun = new Sun();
        System.out.println(sun.n1);//20
    }
}

class Base {
    int n1 = 10;
}

class Sun extends Base {
    int n1 = 20;
}

4、instanceOf比较操作符,用于判断对象的运行类型是否为某个类型或某个类型的子类型。

package com.javase.poly_.detail_;

public class PolyDetail02 {
    public static void main(String[] args) {
        BB bb = new BB();
        System.out.println(bb instanceof BB);//true
        System.out.println(bb instanceof AA);//true

        //用于判断对象的运行类型是否为某个类型或某个类型的子类型
        //编译类型AA 运行类型BB
        AA aa = new BB();
        System.out.println(aa instanceof AA);//true
        System.out.println(aa instanceof BB);//true

        Object o = new Object();
        System.out.println(o instanceof AA);//false
    }
}

class AA{}

class BB extends AA {
}

四、入门练习

1.请说出下面的每条语音,哪些是正确的,哪些是错误的,为什么?

package com.javase.poly_.exercise_;

public class PolyExercise01 {
    public static void main(String[] args) {
        double d = 13.4;//正确
        long l = (long) d;//正确
        System.out.println(l);//13.4
        int in = 5;//正确
        boolean b = (boolean) in;//错误,boolean不能转换成int类型
        Object obj = "hello";//正确 向上转型
        String objStr = (String) obj;//正确 向下转型
        System.out.println(objStr);//hello

        Object objPri = new Integer(5);//正确 向上转型
        String str = (String) objPri;//错误 指向Integer的父类引用,转成String
        Integer str1 = (Integer) objPri;//正确 向下转型
    }
}

2.输出结果是什么:Java学习笔记 --- 面向对象之多态_第2张图片

输出:

20

20

true

10

20

五、动态绑定机制

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

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

package com.javase.poly_.dynamic_;

public class DynamicBinding {
    public static void main(String[] args) {
        A a = new B();
        System.out.println(a.sum());//40 -> 30
        System.out.println(a.sum1());//30 -> 20
    }
}

class A {
    public int i = 10;

    //动态绑定机制
    public int sum() {
        //调用的子类B的getl()
        return getl() + 10;
    }
    public int sum1() {
        //当调用对象属性时,没有动态绑定机制,哪里声明,那里使用。
        return i + 10;
    }
    public int getl() {
        return i;
    }
}

class B extends A {
    public int i = 20;

//    public int sum() {
//        return i + 20;
//    }
//    public int sum1() {
//        return i + 10;
//    }
    public int getl() {
        return i;
    }
}

六、多态的应用

1、多态数组

数组的定义类型为父类类型,里面保存的实际元素类型为子类型。

案例演示:

Person类

package com.javase.poly_.polyarr_;

public 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 void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

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

    public String say() {
        return "name=" + name + " age=" + age;
    }
}

Student 类 

package com.javase.poly_.polyarr_;

public 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;
    }

    public void setScore(double score) {
        this.score = score;
    }

    public String say() {
        return super.say() + " 成绩=" + score;
    }
}

Teacher类 

package com.javase.poly_.polyarr_;

public class Teacher extends Person {
    private double salary;

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

    public double getSalary() {
        return salary;
    }

    public void setSalary(double salary) {
        this.salary = salary;
    }

    public String say() {
        return super.say() + " 薪水=" + salary;
    }
}

输出:

package com.javase.poly_.polyarr_;

public class PolyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("张三", 20);
        persons[1] = new Student("李四", 15, 79.5);
        persons[2] = new Student("王五", 16, 60.0);
        persons[3] = new Teacher("铁蛋", 25, 30000);
        persons[4] = new Teacher("二丫", 30, 60000);

        for (int i = 0; i < persons.length; i++) {
            //编译类型是Person 运行类型是根据实际情况由JVM来判断
            System.out.println(persons[i].say());//多态绑定机制
        }
    }
}

Java学习笔记 --- 面向对象之多态_第3张图片

如何在多态数组中调用子类特有的方法:

在Teacher类 新增特有的方法

public void teach() {
    System.out.println("老师 " + getName() + " 正在讲课...");
}

在Student类 新增特有的方法

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

输出:

package com.javase.poly_.polyarr_;

public class PolyArray {
    public static void main(String[] args) {
        Person[] persons = new Person[5];
        persons[0] = new Person("张三", 20);
        persons[1] = new Student("李四", 15, 79.5);
        persons[2] = new Student("王五", 16, 60.0);
        persons[3] = new Teacher("铁蛋", 25, 30000);
        persons[4] = new Teacher("二丫", 30, 60000);

        for (int i = 0; i < persons.length; i++) {
            //编译类型是Person 运行类型是根据实际情况由JVM来判断
            System.out.println(persons[i].say());//多态绑定机制

            //使用instanceof 判断 persons[i] 是不是Student类型
            if(persons[i] instanceof Student) {
//                Student student = ;//向下转型
//                student.study();//调用子类特有方法
                ((Student) persons[i]).study();
            }else if(persons[i] instanceof Teacher) {
                ((Teacher) persons[i]).teach();
            }

        }
    }
}

Java学习笔记 --- 面向对象之多态_第4张图片

2、多态参数

方法定义的形参类型为父类类型,实参类型允许为子类型

案例演示:

Java学习笔记 --- 面向对象之多态_第5张图片

Employee类

package com.javase.poly_.polyparameter;

public class Employee {
    private String name;
    private double sal;

    public Employee(String name, double sal) {
        this.name = name;
        this.sal = sal;
    }

    public String getName() {
        return name;
    }

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }
    
    //计算年工资
    public double getAnnual() {
        return sal * 12;
    }
}

Worker类 

package com.javase.poly_.polyparameter;

public class Worker extends Employee{

    public Worker(String name, double sal) {
        super(name, sal);
    }

    //子类特有方法
    public void work() {
        System.out.println("普通员工 " + getName() + " 正在工作...");
    }
    //共有方法
    public double getAnnual() {
        return super.getAnnual();
    }
}

 Manager类

package com.javase.poly_.polyparameter;

public class Manager extends Employee{
    private double bonus;

    public Manager(String name, double sal, double bonus) {
        super(name, sal);
        this.bonus = bonus;
    }

    public double getBonus() {
        return bonus;
    }

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

    //子类特有方法
    public void manage() {
        System.out.println("经理 " + getName() + " 正在管理员工...");
    }
    //共有方法
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}

输出:

package com.javase.poly_.polyparameter;

public class PolyParameter {
    public static void main(String[] args) {
        Worker zs = new Worker("张三", 2000);
        Manager ls = new Manager("李四", 5000, 1000);
        PolyParameter polyParameter = new PolyParameter();
        polyParameter.showEmpAnnual(zs);
        polyParameter.showEmpAnnual(ls);

        polyParameter.test(zs);
        polyParameter.test(ls);

    }
    //获取员工的年薪
    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());
    }
    
    public void test(Employee e) {
        if(e instanceof Worker) {//判断对象类型
            ((Worker) e).work();//向下转型
        }else if(e instanceof Manager) {
            ((Manager) e).manage();
        }
    }
}

Java学习笔记 --- 面向对象之多态_第6张图片

 

你可能感兴趣的:(Java基础,学习,java)