Java多態性
多態是對象采取多種形式表現的能力。當一個父類引用是用來指一個子類對象最常見多態性的用途是OOP中發生。
任何可以通過多個Java對象IS-A測試被認為是多態的。在Java中,所有的Java對象是多態的,因為任何對象將通過IS-A測試適合自己的類型和Object類。
重要的是要知道,訪問一個對象的唯一可能途徑是通過一個引用變量。引用變量隻能是一個類型的。一旦聲明,引用變量的類型不能改變。
引用變量可以重新分配,隻要它冇有聲明為final的其他對象。參考變量的類型將決定,它可以在對象上調用的方法。
引用變量可以參考它的聲明的類型或聲明的類型的任何子類的任何對象。引用變量可以聲明為一個類或接口類型。
例子:
讓我們來看一個例子。
public interface Vegetarian{} public class Animal{} public class Deer extends Animal implements Vegetarian{}
現在,Deer類被認為是多態的,因為這有多重繼承。以下是適用於上麵的例子:
-
鹿IS-A 動物
-
鹿IS-A 素食
-
鹿 IS-A 鹿
-
鹿 IS-A 對象
當我們應用的參考變量事實鹿對象引用,下麵的聲明是合法的:
Deer d = new Deer(); Animal a = d; Vegetarian v = d; Object o = d;
所有d的參考變量d,a,v,o 指向相同的Deer 對象在堆中。
虛擬方法:
在本節中,將展示如何在Java中重載方法的行為可以在設計類時采取多態性的優勢。
我們已經討論過的方法重載,其中一個子類可以在其父覆蓋的方法。一個重寫的方法本質上是隱藏的父類,並且不調用,除非子類使用的重載方法中的super關鍵字。
/* File name : 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("Constructing an Employee"); this.name = name; this.address = address; this.number = number; } public void mailCheck() { System.out.println("Mailing a check to " + 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類,如下所示:
/* File name : Salary.java */ public class Salary extends Employee { private double salary; //Annual salary public Salary(String name, String address, int number, double salary) { super(name, address, number); setSalary(salary); } public void mailCheck() { System.out.println("Within mailCheck of Salary class "); System.out.println("Mailing check to " + getName() + " with salary " + salary); } public double getSalary() { return salary; } public void setSalary(double newSalary) { if(newSalary >= 0.0) { salary = newSalary; } } public double computePay() { System.out.println("Computing salary pay for " + getName()); return salary/52; } }
現在,仔細研究下麵的程序,並嘗試確定它的輸出:
/* File name : VirtualDemo.java */ public class VirtualDemo { public static void main(String [] args) { Salary s = new Salary("Mohd Mohtashim", "Ambehta, UP", 3, 3600.00); Employee e = new Salary("John Adams", "Boston, MA", 2, 2400.00); System.out.println("Call mailCheck using Salary reference --"); s.mailCheck(); System.out.println(" Call mailCheck using Employee reference--"); e.mailCheck(); } }
這將產生以下結果:
Constructing an Employee Constructing an Employee Call mailCheck using Salary reference -- Within mailCheck of Salary class Mailing check to Mohd Mohtashim with salary 3600.0 Call mailCheck using Employee reference-- Within mailCheck of Salary class Mailing check to John Adams with salary 2400.0
在這裡,我們可實例化兩種工資的對象。使用一個工資參考s,而使用其他的 Employee 引用e。
在調用 s.mailCheck() 時編譯器看到 mailCheck() 在編譯時Salary類,JVM 調用 mailCheck() 在 Salary類 在運行時。
關於e調用 mailCheck() 是完全不同的,因為 e 是一個 Employee 引用。當編譯器看到 e.mailCheck(),編譯器看到在 Employee 類中的 mailCheck() 方法。
在這裡,在編譯時,編譯器使用mailCheck()員工,以驗證這個語句。在運行時,但是,JVM調用 mailCheck() 在Salary類中。
此行為被稱為虛擬方法調用,並且該方法被稱為虛擬方法。 Java中的所有方法的行為以這種方式,即一個重載方法被調用在運行時,無論什麼數據類型的引用在源代碼在編譯時。