天天看點

Java多态

關于多态的一段代碼

public class test {
    public static void main(String[] args) {
        show(new Cat());  // 以 Cat 對象調用 show 方法
        show(new Dog());  // 以 Dog 對象調用 show 方法

        Animal a = new Cat();  // 向上轉型
        a.eat();               // 調用的是 Cat 的 eat
        Cat c = (Cat) a;        // 向下轉型
        c.work();        // 調用的是 Cat 的 work
    }

    public static void show(Animal a) {
        a.eat();
        // 類型判斷
        if (a instanceof Cat) {  // 貓做的事情
            Cat c = (Cat) a;
            c.work();
        } else if (a instanceof Dog) { // 狗做的事情
            Dog c = (Dog) a;
            c.work();
        }
    }
}

abstract class Animal {
    abstract void eat();
}

class Cat extends Animal {
    public void eat() {
        System.out.println("吃魚");
    }

    public void work() {
        System.out.println("抓老鼠");
    }
}

class Dog extends Animal {
    public void eat() {
        System.out.println("吃骨頭");
    }

    public void work() {
        System.out.println("看家");
    }
}
           

輸出結果:

吃魚
抓老鼠
吃骨頭
看家
吃魚
抓老鼠
           

虛函數

虛函數的存在是為了多态。

Java 中其實沒有虛函數的概念,它的普通函數就相當于 C++ 的虛函數,動态綁定是Java的預設行為。如果 Java 中不希望某個函數具有虛函數特性,可以加上 final 關鍵字變成非虛函數。

重寫

Employee.java代碼

/* 檔案名 : Employee.java */
public class Employee {
    private String name;
    private String address;
    private int number;

    public Employee(String name, String address, int number) {
        System.out.println("Employee 構造函數");
        this.name = name;
        this.address = address;
        this.number = number;
    }

    public void mailCheck() {
        System.out.println("郵寄支票給: " + this.name
                + " " + this.address);
    }

    public String toString() {
        return name + " " + address + " " + number;
    }

    public String getName() {
        return name;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String newAddress) {
        address = newAddress;
    }

    public int getNumber() {
        return number;
    }
}

           

假設下面的類繼承Employee類

/* 檔案名 : Salary.java */
public class Salary extends Employee {
    private double salary; // 全年工資

    public Salary(String name, String address, int number, double salary) {
        super(name, address, number);
        setSalary(salary);
    }

    public void mailCheck() {
        System.out.println("Salary 類的 mailCheck 方法 ");
        System.out.println("郵寄支票給:" + getName()
                + " ,工資為:" + salary);
    }

    public double getSalary() {
        return salary;
    }

    public void setSalary(double newSalary) {
        if (newSalary >= 0.0) {
            salary = newSalary;
        }
    }

    public double computePay() {
        System.out.println("計算工資,付給:" + getName());
        return salary / 52;
    }
}
           

VirtualDemo.java代碼

/* 檔案名 : VirtualDemo.java */
public class VirtualDemo {
    public static void main(String[] args) {
        Salary s = new Salary("員工 A", "北京", 3, 3600.00);
        Employee e = new Salary("員工 B", "上海", 2, 2400.00);
        System.out.println("使用 Salary 的引用調用 mailCheck -- ");
        s.mailCheck();
        System.out.println("\n使用 Employee 的引用調用 mailCheck--");
        e.mailCheck();
    }
}
           

運作結果:

Employee 構造函數
Employee 構造函數
使用 Salary 的引用調用 mailCheck -- 
Salary 類的 mailCheck 方法 
郵寄支票給:員工 A ,工資為:3600.0

使用 Employee 的引用調用 mailCheck--
Salary 類的 mailCheck 方法 
郵寄支票給:員工 B ,工資為:2400.0
           

多态的實作

  • 借口
  • 抽象類和抽象方法

多态的分類

多态一般分為兩種:重寫式多态和重載式多态。

重載式多态,也叫編譯時多态。也就是說這種多态再編譯時已經确定好了。重載大家都知道,方法名相同而參數清單不同的一組方法就是重載。在調用這種重載的方法時,通過傳入不同的參數最後得到不同的結果。

但是這裡是有歧義的,有的人覺得不應該把重載也算作多态。因為很多人對多态的了解是:程式中定義的引用變量所指向的具體類型和通過該引用變量發出的方法調用在程式設計時并不确定,而是在程式運作期間才确定,這種情況叫做多态。 這個定義中描述的就是我們的第二種多态—重寫式多态。并且,重載式多态并不是面向對象程式設計特有的,而多态卻是面向對象三大特性之一(如果我說的不對,記得告訴我。。)。

我覺得大家也沒有必要在定義上去深究這些,我的了解是:同一個行為具有多個不同表現形式或形态的能力就是多态,是以我認為重載也是一種多态,如果你不同意這種觀點,我也接受。

重寫式多态,也叫運作時多态。這種多态通過動态綁定(dynamic binding)技術來實作,是指在執行期間判斷所引用對象的實際類型,根據其實際的類型調用其相應的方法。也就是說,隻有程式運作起來,你才知道調用的是哪個子類的方法。 這種多态通過函數的重寫以及向上轉型來實作,我們上面代碼中的例子就是一個完整的重寫式多态。我們接下來講的所有多态都是重寫式多态,因為它才是面向對象程式設計中真正的多态。

JAVA – 虛函數、抽象函數、抽象類、接口

1. Java 虛函數

C++ 中普通成員函數加上 virtual 關鍵字就成為虛函數。

Java 中其實沒有虛函數的概念,它的普通函數就相當于 C++ 的虛函數,動态綁定是 Java 的預設行為。如果 Java 中不希望某個函數具有虛函數特性,可以加上 final 關鍵字變成非虛函數。

PS: 其實 C++ 和 Java 在虛函數的觀點大同小異,異曲同工罷了。

2. Java抽象函數(純虛函數)

抽象函數或者說是純虛函數的存在是為了定義接口。

C++ 中純虛函數形式為:

virtual void print() = 0;
           

Java 中純虛函數形式為:

abstract void print();
           

PS: 在抽象函數方面 C++ 和 Java 還是換湯不換藥。

3. Java 抽象類

抽象類的存在是因為父類中既包括子類共性函數的具體定義,也包括需要子類各自實作的函數接口。抽象類中可以有資料成員和非抽象方法。

C++ 中抽象類隻需要包括純虛函數,既是一個抽象類。如果僅僅包括虛函數,不能定義為抽象類,因為類中其實沒有抽象的概念。

Java 抽象類是用 abstract 修飾聲明的類。

PS: 抽象類其實是一個半虛半實的東西,可以全部為虛,這時候變成接口。

4. Java 接口

接口的存在是為了形成一種規約。接口中不能有普通成員變量,也不能具有非純虛函數。

C++ 中接口其實就是全虛基類。

Java 中接口是用 interface 修飾的類。

PS: 接口就是虛到極點的抽象類。

5. 小結

C++ 虛函數    ==  Java 普通函數

C++ 純虛函數  ==  Java 抽象函數

C++ 抽象類    ==  Java 抽象類

C++ 虛基類    ==  Java 接口