一、簡介
描述:
- 多態(tài)性是面向?qū)ο缶幊讨械囊粋€重要特性,主要是用來實現(xiàn)動態(tài)聯(lián)編的。換句話說,就是程序的最終狀態(tài)只有在執(zhí)行過程中才被決定,而非在編譯期間就決定了。這對于大型系統(tǒng)來說能提高系統(tǒng)的靈活性和擴展性。
- 多態(tài)允許相同類域的不同對象對同一消息做出響應(yīng)。即同一消息可以根據(jù)發(fā)送對象的不同而采用多種不同的行為方式。
- 多態(tài)可以讓我們不用關(guān)心某個對象到底是什么具體類型,就可以使用該對象的某些方法,從而實現(xiàn)更加靈活的編程,提高系統(tǒng)的可擴展性。
- 如果對象的編譯時類型和運行時類型不一致,就會造成多態(tài)。
存在條件:
- 類之間有繼承關(guān)系。
- 子類重寫父類方法。
- 父類引用指向子類對象。
注意:
- 多態(tài)是方法的多態(tài),屬性沒有多態(tài)性。
- 一個對象的實際類型是確定的,但是可以指向這個對象的引用的類型,卻是可以是這對象實際類型的任意父類型。
- 子類繼承父類,調(diào)用方法,如果該方法在子類中沒有重寫,那么就是調(diào)用的是子類繼承父類的方法,如果重寫了,那么調(diào)用的就是重寫之后的方法。
- 'protected'修飾的父類方法可以被子類見到,也可以被子類重寫,但是它是無法被外部所引用的,所以沒有多態(tài)性。
- 通過一個變量調(diào)用其引用的對象的一個方法,編譯器是否能讓其編譯通過,主要是看該變量類型的類中有沒有定義該方法,如果有則編譯通過,如果沒有則編譯報錯。而不是看這個變量所引用的對象中有沒有該方法。
- Java中的方法調(diào)用,是運行時動態(tài)和對象綁定的,不到運行的時候,是不知道到底哪個方法被調(diào)用的。
- 編寫程序時,如果想調(diào)用運行時類型的方法,只能進行類型轉(zhuǎn)換,不然通不過編譯器的檢查。但是如果兩個沒有關(guān)聯(lián)的類進行強制轉(zhuǎn)換,會報類型轉(zhuǎn)換異常:ClassCastException。
示例:
public class Test {
public static void main(String[] args) {
/* 編譯看左,運行看右 */
Student student = new Student();
/* 變量person是可以指向Person類型或其子類型的對象,所以可以指向Student類型對象 */
Person person = new Student();
/* 變量student能調(diào)用的方法是Student類中有的方法(包括繼承過來的) */
student.say();//Student
/* 變量person能調(diào)用的方法是Person類中有的方法 */
person.say();//Student
}
}
class Person {
public void say() {
System.out.println("Person");
}
}
class Student extends Person {
public void say() {
System.out.println("Student");
}
}
二、重寫、重載、多態(tài)的關(guān)系
- 重載是編譯時多態(tài)
- 調(diào)用重載的方法,在編譯期間就要確定調(diào)用的方法是誰,如果不能確定則編譯報錯 。
- 重寫是運行時多態(tài)
- 調(diào)用重寫的方法,在運行期間才能確定這個方法到底是哪個對象中的。
- 重寫方法所屬取決于調(diào)用方法的引用,在運行期間所指向的對象是誰,那么調(diào)用的就是該對象中的方法。
三、方法綁定
- 程序執(zhí)行調(diào)用方法時,系統(tǒng)根據(jù)相關(guān)信息,能夠執(zhí)行內(nèi)存地址中代表該方法的代碼。
- 根據(jù)綁定方法的代碼的時機不同,分為靜態(tài)綁定和動態(tài)綁定。
靜態(tài)綁定:
動態(tài)綁定:
- 通過對象調(diào)用的方法,采用動態(tài)綁定機制。
- 這雖然讓我們編程靈活,但是降低了代碼的執(zhí)行速度。
- Java所有方法都是JVM在運行期才進行動態(tài)綁定的。
四、'instanceof'關(guān)鍵字
描述:
- 'instanceof'是Java的一個二元操作符。
- 'instanceof'是Java的保留關(guān)鍵字。
- 'instanceof'的作用是測試它左邊的對象是否是它右邊的類的實例,返回一個布爾值。
注意:
- 'instanceof'左邊的引用的類型與右邊的類之間,必須有父子關(guān)系或子父關(guān)系,否則編譯會報錯。
- 'instanceof'的布爾值結(jié)果,根據(jù)左邊的引用的對象類型是否為右邊的類的子類型。
示例:
public class Test {
public static void main(String[] args) {
Object object = new Student();
System.out.println(object instanceof Student);//true
System.out.println(object instanceof Person);//true
System.out.println(object instanceof Object);//true
System.out.println(object instanceof Teacher);//false
System.out.println(object instanceof String);//false
Person person = new Student();
System.out.println(person instanceof Student);//true
System.out.println(person instanceof Person);//true
System.out.println(person instanceof Object);//true
System.out.println(person instanceof Teacher);//false
Student student = new Student();
System.out.println(student instanceof Student);//true
System.out.println(student instanceof Person);//true
System.out.println(student instanceof Object);//true
}
}
class Person {
}
class Student extends Person {
}
class Teacher extends Person {
}
五、類型轉(zhuǎn)換
描述:
- 由于多態(tài)的關(guān)系,父類引用可以指向子類對象,子類引用不能指向父類對象。當我們想要調(diào)用子類中的方法,而對象的引用類型是其父類時,就需要將該引用類型進行強制類型轉(zhuǎn)換。
- 把子類對象直接賦給父類引用叫向上轉(zhuǎn)型,向上轉(zhuǎn)型不用進行強制類型轉(zhuǎn)換。
- 把指向子類對象的父類引用賦給子類引用叫向下轉(zhuǎn)型,需要進行強制類型轉(zhuǎn)換。
- 向上轉(zhuǎn)型會丟失子類特有的方法,但是子類若重寫了父類的方法,重寫的子類方法仍有效。
- 向上轉(zhuǎn)型可以減少重復(fù)代碼,體現(xiàn)了抽象編程的思想。父類引用作為形式參數(shù),調(diào)有時用子類引用作為實際參數(shù),就是利用了向上轉(zhuǎn)型。
強制類型轉(zhuǎn)換語法:
(targetType) object
示例:
public class Test {
public static void main(String[] args) {
Person person1 = new Student();
Student student1 = (Student) person1;
student1.go();//studentGo
student1.run();//studentRun
person1.run();//studentRun
Object object1 = new Student();
Person person2 = (Person) object1;
person2.run();//studentRun
/*
因為object2引用的對象類型不是Student的子類型,所以以下代碼會出現(xiàn)運行時異常:ClassCastException
Object object2 = new Teacher();
Student student2 = (Student) object2;
*/
}
}
class Person {
public void run() {
System.out.println("personRun");
}
}
class Student extends Person {
public void run() {
System.out.println("studentRun");
}
public void go() {
System.out.println("studentGo");
}
}
class Teacher extends Person {
}
|