Java三大特性有封裝、繼承、多態(tài)。
前面我們已經(jīng)學(xué)過了封裝和繼承,今天學(xué)習(xí)多態(tài),如需前面內(nèi)容的可自行查看。
1、多態(tài)的引入
多態(tài)是繼封裝、繼承之后,面向?qū)ο蟮牡谌筇匦?/strong>
生活中,比如交通工具的種類可以分為飛機(jī)、汽車、輪船
再比如交通工具的運(yùn)行方式飛機(jī)運(yùn)行方式是飛在天上、汽車是在馬路上開、輪船是在海上行駛
可見,同一行為,通過不同的事物,可以體現(xiàn)出來的不同的形態(tài)
多態(tài),描述的就是這樣的狀態(tài)。
2、多態(tài)性的概念
2.1 多態(tài)的含義
多態(tài)性是面向?qū)ο蟮娜筇卣髦?,同一行為,通過不同的事物,可以體現(xiàn)出來的不同的形態(tài)。
2.2 Java中多態(tài)的具體體現(xiàn)
- 方法重載(在同一個(gè)類中,同名的方法,由于形參的不同,實(shí)現(xiàn)方法的重載,在調(diào)用方法時(shí),可根據(jù)實(shí)參的組合來選擇所調(diào)用的方法)
- 方法覆蓋(主要在繼承時(shí)用到,子類繼承父類,可以重寫父類的非靜態(tài)的方法)
- 多態(tài)參數(shù)(新內(nèi)容,重點(diǎn)、難點(diǎn),本章主要講)
2.3 多態(tài)的前提
- 存在繼承或者實(shí)現(xiàn)關(guān)系
- 子類或?qū)崿F(xiàn)類必須重寫父類方法
- 父類引用指向子類對(duì)象
2.4 父類引用指向子類對(duì)象
提個(gè)概念,編譯器類型指的是‘=’左邊的類型,運(yùn)行期類型指的是‘=’右邊的類型。
當(dāng)有繼承關(guān)系時(shí),可能發(fā)生編譯期類型和運(yùn)行期類型不同的情況,即編譯期類型是父類類型,運(yùn)行期類型是子類類型。
即:父類引用指向子類對(duì)象
例如:
//動(dòng)物類
public class Animal {
private String name;
public Animal() {
// TODO Auto-generated constructor stub
this.name = "動(dòng)物";
}
public void eat() {
System.out.println("動(dòng)物在吃");
}
static void look() {
System.out.println("動(dòng)物在看");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//狗類
public class Dog extends Animal {
private String name;
public Dog() {
// TODO Auto-generated constructor stub
this.name = "狗";
}
public void eat() {
System.out.println("狗在吃");
}
public void bite() {
System.out.println("狗咬人");
}
static void look() {
System.out.println("狗在看");
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
//測(cè)試類:
public class Demo {
public static void main(String[] args) {
// 父類對(duì)象指向子類引用
Animal animal = new Dog();
// 如果子類中重寫了父類的方法,按照子類重寫的方法執(zhí)行
animal.eat();
// 子類自己擴(kuò)展的方法,不能調(diào)用
// animal.bite();
// 調(diào)用父類和子類同名的靜態(tài)方法,調(diào)用的是父類的靜態(tài)方法
animal.look();
}
}
3、多態(tài)參數(shù)
3.1 形參具有多態(tài)性
接著上述的案例,如果我們有個(gè)方法需要分別調(diào)用他們同名的方法,應(yīng)該怎么做呢?
比如:在Demo類中有個(gè)doing()方法,我想要傳進(jìn)來的對(duì)象,讓他們都執(zhí)行他們的eat()這個(gè)方法,此時(shí),我們就需要利用方法參數(shù)多態(tài)性。
我們只需要把形參的類型定義成父類的類型,我們可以利用上面提到過的驗(yàn)證(當(dāng)父類引用調(diào)用子類對(duì)象時(shí),調(diào)用重寫的方法,是執(zhí)行子類的重寫后方法)。
在一個(gè)方法的形參類型你設(shè)成父類類型,你傳入一個(gè)實(shí)參對(duì)象,如果是一個(gè)子類的對(duì)象就相當(dāng)于上述的父類引用調(diào)用子類對(duì)象,如果傳入的是父類對(duì)象那就是正常的編譯器類型等于運(yùn)行期類型情況,正常調(diào)用。
如此,我們就實(shí)現(xiàn)了形參的多態(tài)性,在很大程度上減少了代碼的重復(fù)性,也提高了代碼的擴(kuò)展性。
class Demo{
void doing(Animal a){
a.eat();
}
}
3.2 多態(tài)環(huán)境下對(duì)象造型
上述情況,只是描述對(duì)于一些子類重寫父類方法的調(diào)用,在第一個(gè)案例中,我們知道父類引用指向子類對(duì)象時(shí),沒有辦法調(diào)用子類擴(kuò)展的方法,那我們應(yīng)該怎么做了?
此時(shí),我們就需要用到我們?cè)趯W(xué)習(xí)數(shù)據(jù)類型時(shí)的一個(gè)概念,強(qiáng)制轉(zhuǎn)換,將父類引用強(qiáng)制轉(zhuǎn)換成子類的類型。
注意:強(qiáng)制轉(zhuǎn)換,只能是將父類類型轉(zhuǎn)換成運(yùn)行期類型,不能是別的類型。
不僅父類引用可以強(qiáng)制轉(zhuǎn)換成子類的類型,子類的引用也可以強(qiáng)制轉(zhuǎn)換成父類的類型。
從造型方向上看,可分為:
(1)向上造型 –又稱自動(dòng)類型提升
即父類引用指向子類對(duì)象,將子類對(duì)象向上造型成為父類類型。
作用是:提高程序的擴(kuò)展性。
(2)向下造型 –又稱向下轉(zhuǎn)型
即將子類對(duì)象強(qiáng)制轉(zhuǎn)換成父類類型
作用:實(shí)現(xiàn)子類擴(kuò)展方法的調(diào)用。
例如:接著上述例子
//父類引用指向子類對(duì)象
Animal animal=new Dog();
Dog dog = (Dog)animal; //將父類引用強(qiáng)制轉(zhuǎn)換成子類的類型
dog.look(); //此時(shí)調(diào)用的子類的靜態(tài)方法
dog.bite(); //可以調(diào)用子類擴(kuò)展的方法
//子類引用指向子類對(duì)象
Dog dog1 = new Dog();
Animal a = (Animal)dog1; //將子類引用轉(zhuǎn)換成父類類型
a.eat(); //調(diào)用的是子類的方法
a.look(); //調(diào)用的是父類的靜態(tài)方法
//a.bite(); //子類擴(kuò)展的方法不能調(diào)用
4、instanceof ()方法
4.1 instanceof 操作符
使用instanceof操作符來判斷一個(gè)對(duì)象的運(yùn)行期類型,即用來在運(yùn)行時(shí)指出對(duì)象是否是特定類的一個(gè)實(shí)例。
4.1 instanceof 用法
語法:
對(duì)象名稱 instanceof 類型;
返回值類型:布爾類型
Dog dog1 = new Dog();
Animal a = (Animal)dog1;
System.out.println(a instanceof Animal);
//結(jié)果:
true