Java的第三大特性------>多態(tài)
一、什么是多態(tài)
多態(tài)根據(jù)其字面意思就是多種形態(tài)的意思夏块,那么在Java中的多態(tài)指的是什么呢交汤?
指的是對象具有多種形態(tài)的意思剃幌,只是Java中分為引用多態(tài)和方法多態(tài)
A.引用多態(tài)
a.父類的引用指向本類的對象
b.父類的引用指向子類的對象
如下圖所示可以看出來,父類Animal_manStyle的引用指向了本身税肪,還可以指向子類的對象溉躲,
但是子類的引用不可以指向父類的對象。
這就好比貓是動物益兄,但動物不一定是貓啊
B.方法多態(tài)
a.父類的對象可以調(diào)用本身的方法
b.父類指向子類的對象锻梳,那么調(diào)用的時候就是調(diào)用的子類的方法(子類重寫了父類的方法),如果子類沒有重寫父類的方法净捅,那么子類對象調(diào)用的就是父類的對象
如上圖的調(diào)用疑枯,a是父類的對象引用,c是子類的對象引用蛔六,結(jié)果如下
注意:多態(tài)是基于繼承的荆永,但是有一種情況下是不能使用多態(tài)的,便是父類指向的引用不能指向子類獨有的方法
二国章、多態(tài)之引用類型轉(zhuǎn)換
引用類型轉(zhuǎn)換分為兩種轉(zhuǎn)換具钥,一種是自動類型轉(zhuǎn)換,二是強(qiáng)制類型轉(zhuǎn)換
A.自動類型轉(zhuǎn)換又稱為向上類型提升
Bus類是Transportation的子類捉腥,即 父類的引用可以指向其子類(小類型轉(zhuǎn)換成大類型)氓拼,上圖就是自動類型轉(zhuǎn)換。
B.強(qiáng)制類型轉(zhuǎn)換又稱為向下類型轉(zhuǎn)換,存在一定的風(fēng)險
上圖可以看出來桃漾,當(dāng)一個父類型的引用指向一個子類型的對象時坏匪,可以對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換,為了避免類型轉(zhuǎn)換時出現(xiàn)的不安全為問題撬统,我們利用 instanceof關(guān)鍵字适滓,instanceof關(guān)鍵字是判斷這個引用是否是這個類的,即 car 引用是否是Car類型的或者是Car的子類型的恋追,
當(dāng)if中的判斷成立的話凭迹,我們就可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換,并且不會出錯苦囱。
其實強(qiáng)制類型轉(zhuǎn)換的根本就是嗅绸,當(dāng)利用構(gòu)造器構(gòu)造出來的對象在內(nèi)存中本身已經(jīng)有一個類型,如果要賦予的引用是這個類型的或者是其父類型的則可以進(jìn)行強(qiáng)制類型轉(zhuǎn)換撕彤,如
Animal animal = new Dog();
Dog dog=(Dog)animal;
animal 在內(nèi)存中本身就是Dog類型的鱼鸠,所以對其進(jìn)行強(qiáng)制類型轉(zhuǎn)換成Dog是可以的
但是,
Animal animal = new Animal();
Dog dog = (Dog) animal;
這個是不行的羹铅,因為animal 在內(nèi)存中本身是Animal 類型的蚀狰,現(xiàn)在對它進(jìn)行的轉(zhuǎn)換不是它本類,或者是它的父類职员,所以這個是不可以進(jìn)行類型轉(zhuǎn)換的麻蹋,編譯器會通過,但是運行時會拋出ClassCastException異常
同樣還有一種情況是不可以的焊切,如下:
Animal dog = new Dog();
Cat cat =(Cat)dog;
這里的Cat 是繼承自Animal 的扮授,但是同樣不可以,因為dog 的本身是Dog類型蛛蒙,不是同級的Cat類型糙箍。
三、多態(tài)之抽象類
A.什么是抽象類
抽象類就是不能具體的表示一個對象的類牵祟,比如動物深夯,它不可能是一個具體的對象,要是想清楚的表示一個對象诺苹,那么必須由他的子類貓或者狗來表示
B.怎么描述一個抽象類
a.前面必須有關(guān)鍵字abstract 來修飾
b.抽象類中包含抽象方法咕晋,抽象方法沒有方法體,必須由子類來實現(xiàn)
c.體現(xiàn)了數(shù)據(jù)抽象的思想收奔,是實現(xiàn)多態(tài)的一種機(jī)制
d.抽象類不能被實例化掌呜,它有的只是指向子類對象的引用
e.從多個類中抽象出一個抽象類,作為子類設(shè)計的模板坪哄,從而限制了子類設(shè)計的隨意性
f.不關(guān)心子類的具體實現(xiàn)质蕉,只關(guān)注子類中必須有什么方法
g. abstract不能和final同時修飾一個類
h.abstract 不能與private 势篡、static 、final 等共同修飾同一個方法
抽象類為Telphone,子類是 CellPhone ,SmartPhone模暗,那么代碼如下:
public abstract class Telphone {
public abstract void call();
public abstract void message();
public void printf(){
System.out.println("Hello_abstractClass");
}
}
public class CellPhone extends Telphone{
@Override
public void call(){
System.out.println("cellPhone電話具有打電話的功能");
}
@Override
public void message() {
System.out.println("CellPhone具有發(fā)短信的功能");
}
public void inter(){
System.out.println("可以上網(wǎng)");
}
}
public class SmartPhone extends Telphone{
@Override
public void call() {
System.out.println("SmartPhone具有打電話的功能");
}
@Override
public void message() {
System.out.println("SmartPhone具有發(fā)短信的功能");
}
@Override
public void printf() {
super.printf();
System.out.println("可以輸出");
}
}
public class Initail {
public static void main(String[] args){
Telphone tel1=new CellPhone();
Telphone tel2=new SmartPhone();
CellPhone tel3=new CellPhone();
CellPhone tel4=(CellPhone) tel1;
tel4.inter();
tel3.inter();
tel1.call();
tel1.message();
tel1.printf();
tel2.call();
tel2.message();
tel2.printf();
}
}
從這段代碼中可以看出來抽象類的引用指向了子類的對象禁悠,并且可以調(diào)用子類實現(xiàn)的方法,但是有一點就是當(dāng)子類中的獨有方法時兑宇,父類的引用是不可以調(diào)用的碍侦,惟有子類的引用可以調(diào)用。如上圖的inter()方法隶糕。
四瓷产、多態(tài)之接口
A.什么是接口
接口是一組規(guī)范,并不關(guān)心類的具體的數(shù)據(jù)與實現(xiàn)枚驻,只是規(guī)定了類該實現(xiàn)哪些方法濒旦,是用來約束類的,
B. 怎么描述接口
a.接口是一個特殊的類测秸,其中可以是公共的常量和公共的抽象方法組成
b.使用interface關(guān)鍵字定義接口
c.是public abstract(可以有,沒有顯示出現(xiàn)的話疤估,會被隱式添加上)
d.接口是可以多繼承的,它可以繼承多個父接口
如:
修飾符 (abstract) 接口名 [ extends 父接口1 霎冯,父接口2,....]
{
0~n個常量
0~n個抽象方法的定義
}
e.接口中是常量钞瀑,修飾符是public static final 沈撞,如果沒有寫,系統(tǒng)會隱式的添加
f.定義方法時修飾是public abstract雕什,如果沒有添加缠俺,那么系統(tǒng)會自動添加
g.一個類可以實現(xiàn)一個或多個接口,多個接口之間使用贷岸,分隔開來壹士,使用implements實現(xiàn)接口
h.在繼承一個類的同時也可以實現(xiàn)接口,但是繼承的類必須在實現(xiàn)接口之前
如:
修飾符 class 類名 extends 父類 implements 接口1, 接口 2...
public abstract interface IplayGame{
public static final int IGrade=1;//可以在接口中定義常量
public void playGame();
}
public class CellPhone extends Telphone implements IplayGame{
public void call(){
System.out.println("cellPhone電話具有打電話的功能");
}
@Override
public void message() {
System.out.println("CellPhone具有發(fā)短信的功能");
}
public void inter(){
System.out.println("可以上網(wǎng)");
}
@Override
public void playGame() {
System.out.println("CellPhone 不能打游戲");
}
}
public class initail {
public static void main(String[] args){
((CellPhone) tel1).playGame();
System.out.println(CellPhone.IGrade);
}
}
在這段代碼中偿警,有一個接口IplayGame躏救,CellPhone 實現(xiàn)了IplayGame這個接口,然后用了CellPhone 的引用調(diào)用這個接口中的常量和方法螟蒸。
I.使用匿名內(nèi)部類實現(xiàn)接口
IplayGame ip1= new IplayGame() {
@Override
public void playGame() {
System.out.println("使用匿名內(nèi)部類實現(xiàn)接口");
}
};
ip1.playGame();
new IplayGame() {
@Override
public void playGame() {
System.out.println("使用匿名內(nèi)部類實現(xiàn)了接口2");
}
}.playGame();
在匿名內(nèi)部類中可以直接new 一個接口的引用盒使,后來可以用接口的引用直接調(diào)用我們的接口內(nèi)的方法。個人覺得這個就像是在接口中實現(xiàn)了抽象方法七嫌,然后利用接口的引用調(diào)用了被實現(xiàn)的方法少办,這個接口就相當(dāng)于一個類(如有不對的,還請多多指教!!!).
多態(tài)的就總結(jié)到這兒诵原,下面簡單的說一下接口和抽象類的區(qū)別:
1.關(guān)鍵字不同
2.接口中不能有被實現(xiàn)了的方法英妓,抽象類中可以有
3.接口可以實現(xiàn)多繼承挽放,抽象類只能單繼承
4.接口中只能是成員常量,抽象類中可以成員變量
5.繼承抽象類的子類必須和抽象類本身有繼承關(guān)系蔓纠,則存在 is a的關(guān)系骂维,但是實現(xiàn)接口不一定,只要能夠?qū)崿F(xiàn)接口中定義的方法即可
每天總結(jié)一點點贺纲,堅持