首頁 > 軟體

深入解析Java多型進階學習

2022-07-13 18:01:53

1.動態繫結機制

java的動態繫結機制非常重要

範例A

我們來看一個範例:

閱讀上面的程式碼,請說明下面的程式將輸出什麼結果:

程式將會輸出40和30,這個範例很簡單,直接看執行型別即可,該程式碼的執行型別為B,所以會呼叫B類的方法

範例B

我們將上面的程式碼變通一下,將子類中的如下程式碼塊登出:

隨後繼承機制會存取父類別的sum方法:

那麼這裡有一個問題,此處的getI(),會執行子類的還是父類別的呢?

當呼叫物件方法的時候,該方法會和該物件的記憶體地址/執行型別繫結

程式碼的執行型別依然是B,所以此處會執行子類的getI()方法,結果輸出為30

範例C

現在我們再變通以下上面的程式碼

再將子類中如下的程式碼塊登出:

繼承機制會執行父類別的sum1方法:

那麼這裡有一個問題,此處的i,會使用子類的還是父類別的呢?

屬性沒有動態繫結機制,哪裡宣告,哪裡使用(使用當前類的)

此處的i在父類別進行宣告,所以會選用父類別的i屬性,結果為20

2.多型陣列

定義:

陣列的定義型別為父類別型別,但是儲存的實際元素型別為子類型別

Person父類別:

/**
 * 多型陣列父類別
 */
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 + 't' + age;
    }
}

Student子類:

/**
 * 多型陣列學生子類
 */
public class Student extends Person{
    private double score;

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

    // 重寫父類別的say方法
    public String say() {
        return super.say() + 't' + score;
    }
}

Teacher子類:

/**
 * 多型陣列教師子類
 */
public class Teacher extends Person {
    private double sal;

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

    public double getSal() {
        return sal;
    }

    public void setSal(double sal) {
        this.sal = sal;
    }

    public String say() {
        return super.say() + 't' + sal;
    }
}

測試多型陣列的使用:

public class Test {
    public static void main(String[] args) {
        // 多型陣列的使用
        Person[] persons = new Person[5];
        persons[0] = new Person("dahe",20);
        persons[1] = new Student("wangwei",11,100);
        persons[2] = new Student("zhangsan",12,60);
        persons[3] = new Teacher("wang",33,15000);
        persons[4] = new Teacher("li",55,25000);

        // 迴圈遍歷多型陣列,呼叫say方法
        for (int i = 0; i < persons.length; i++) {
            String out = persons[i].say(); // 動態繫結機制,編譯型別永遠都是Person
            // 執行型別是根據實際情況由JVM機決定
            System.out.println(out);
        }
    }
}

輸出:

dahe    20
wangwei    11    100.0
zhangsan    12    60.0
wang    33    15000.0
li    55    25000.0

3.多型陣列的高階用法

現在,教師子類新增了教學方法:

public void teach() {
    System.out.println("老師:" + getName() + "正在講課!");
}

學生子類新增了學習方法:

public void study() {
    System.out.println("學生:" + getName() + "正在學習!");
}

那麼,有沒有辦法通過多型陣列來存取他們子類對應的獨有的方法呢?事實上,可以通過巧妙使用instanceof來解決:

變通一下,改變多型陣列的迴圈操作:

// 迴圈遍歷多型陣列,呼叫say方法
for (int i = 0; i < persons.length; i++) {
    String out = persons[i].say(); // 動態繫結機制,編譯型別永遠都是Person
    // 執行型別是根據實際情況由JVM機決定
    System.out.println(out);
    if (persons[i] instanceof Student) {
        // 向下轉型
        Student student = (Student) persons[i];
        student.study();
    } else if (persons[i] instanceof Teacher) {
        Teacher teacher = (Teacher) persons[i];
        teacher.teach();
    }
}

輸出:

dahe    20
wangwei    11    100.0
學生:wangwei正在學習!
zhangsan    12    60.0
學生:zhangsan正在學習!
wang    33    15000.0
老師:wang正在講課!
li    55    25000.0
老師:li正在講課!

大功告成!多型陣列即強大又完美!

4.多型引數

方法定義的形參型別為父類別型別,實參型別允許為子類型別

接下來我們來演示以下多型引數的使用:

父類別:

/**
 * 多型引數 - 父類別
 */
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 12 * sal;
    }
}

員工子類:

/**
 * 多型引數 - 子類員工
 */
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();
    }
}

經理子類:

/**
 * 多型引數 - 經理子類
 */
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() + "正在管理!");
    }

    @Override
    public double getAnnual() {
        return super.getAnnual() + bonus;
    }
}

我們來測試一下,求不同崗位的僱員的年薪:

/**
 * 多型引數測試類
 */
public class Test {
    public static void main(String[] args) {
        Worker zhang = new Worker("張工",1000);
        Manager milan = new Manager("milan", 5000, 2000);
        Test test = new Test();
        test.showEmpAnnual(zhang);
        test.showEmpAnnual(milan);
    }


    // 獲取員工的年薪,採用多型引數
    public void showEmpAnnual(Employee e) {
        System.out.println(e.getAnnual());
    }
}

輸出:

12000.0
62000.0

5.多型引數的高階用法

我們來對上面的多型引數程式碼做一個完善,如果傳入的是員工,則呼叫自己的work方法,如果傳入的是經理,則呼叫自己的manage方法

增加一個下面的方法:

public void testWork(Employee e) {
    if (e instanceof Worker) {
        ((Worker) e).work(); // 向下轉型
    } else if (e instanceof Manager) {
        ((Manager) e).manage();
    }
}

測試:

test.testWork(zhang);
test.testWork(milan);

輸出:

普通員工:張工正在工作!
經理:milan正在管理!

到此這篇關於深入解析Java多型進階學習的文章就介紹到這了,更多相關Java多型內容請搜尋it145.com以前的文章或繼續瀏覽下面的相關文章希望大家以後多多支援it145.com!


IT145.com E-mail:sddin#qq.com