大战熟女丰满人妻av-荡女精品导航-岛国aaaa级午夜福利片-岛国av动作片在线观看-岛国av无码免费无禁网站-岛国大片激情做爰视频

Java教程
Java標(biāo)識(shí)符與關(guān)鍵字
Java變量
Java數(shù)據(jù)類(lèi)型
Java運(yùn)算符
Java控制語(yǔ)句
Java方法

Java多態(tài)

多態(tài)(Polymorphism)屬于面向?qū)ο笕筇卣髦唬那疤崾欠庋b形成獨(dú)立體,獨(dú)立體之間存在繼承關(guān)系,從而產(chǎn)生多態(tài)機(jī)制。多態(tài)是同一個(gè)行為具有多個(gè)不同表現(xiàn)形式或形態(tài)的能力。現(xiàn)實(shí)中,比如我們按下 F1 鍵這個(gè)動(dòng)作:

● 如果當(dāng)前在 Flash 界面下彈出的就是 AS 3 的幫助文檔;

● 如果當(dāng)前在 Word 下彈出的就是 Word 幫助;

● 如果當(dāng)前在 Windows 下彈出的就是 Windows 幫助和支持。

多態(tài)就是“同一個(gè)行為”發(fā)生在“不同的對(duì)象上”會(huì)產(chǎn)生不同的效果。那么在java中多態(tài)是如何體現(xiàn)的呢?

在java中允許這樣的兩種語(yǔ)法出現(xiàn),一種是向上轉(zhuǎn)型(Upcasting),一種是向下轉(zhuǎn)型(Downcasting),向上轉(zhuǎn)型是指子類(lèi)型轉(zhuǎn)換為父類(lèi)型,又被稱為自動(dòng)類(lèi)型轉(zhuǎn)換,向下轉(zhuǎn)型是指父類(lèi)型轉(zhuǎn)換為子類(lèi)型,又被稱為強(qiáng)制類(lèi)型轉(zhuǎn)換。請(qǐng)看下圖:

Java多態(tài)

圖13-4:向上轉(zhuǎn)型和向下轉(zhuǎn)型

在java語(yǔ)言中有這樣的一個(gè)規(guī)定,無(wú)論是向上轉(zhuǎn)型還是向下轉(zhuǎn)型,兩種類(lèi)型之間必須要有繼承關(guān)系,沒(méi)有繼承關(guān)系情況下進(jìn)行向上轉(zhuǎn)型或向下轉(zhuǎn)型的時(shí)候編譯器都會(huì)報(bào)錯(cuò),這一點(diǎn)要死記硬背哦!

接下來(lái)我們來(lái)看一段代碼:

public class Animal {
	public void move(){
		System.out.println("Animal move!");
	}
}
public class Cat extends Animal{
	//方法覆蓋
	public void move(){
		System.out.println("走貓步!");
	}
	//子類(lèi)特有
	public void catchMouse(){
		System.out.println("抓老鼠!");
	}
}
public class Bird extends Animal{
	//方法覆蓋
	public void move(){
		System.out.println("鳥(niǎo)兒在飛翔!");
	}
//子類(lèi)特有
public void sing(){
	System.out.println("鳥(niǎo)兒在歌唱!");
	}
}
public class Test01 {
	public static void main(String[] args) {
		//創(chuàng)建Animal對(duì)象
		Animal a = new Animal();
		a.move();
		//創(chuàng)建Cat對(duì)象
		Cat c = new Cat();
		c.move();
		//創(chuàng)建鳥(niǎo)兒對(duì)象
		Bird b = new Bird();
		b.move();
	}
}

運(yùn)行結(jié)果如下圖所示:

Java編程開(kāi)發(fā)

圖13-5:運(yùn)行結(jié)果

其實(shí)在java中還允許這樣寫(xiě)代碼,請(qǐng)看:

public class Test02 {
	public static void main(String[] args) {
		Animal a1 = new Cat();
		a1.move();
		Animal a2 = new Bird();
		a2.move();
	}
}

運(yùn)行結(jié)果如下圖所示:

Java應(yīng)用

圖13-6:運(yùn)行結(jié)果

以上程序演示的就是多態(tài),多態(tài)就是“同一個(gè)行為(move)”作用在“不同的對(duì)象上”會(huì)有不同的表現(xiàn)結(jié)果。java中之所以有多態(tài)機(jī)制,是因?yàn)閖ava允許一個(gè)父類(lèi)型的引用指向一個(gè)子類(lèi)型的對(duì)象。也就是說(shuō)允許這種寫(xiě)法:Animal a2 = new Bird(),因?yàn)锽ird is a Animal是能夠說(shuō)通的。其中Animal a1 = new Cat()或者Animal a2 = new Bird()都是父類(lèi)型引用指向了子類(lèi)型對(duì)象,都屬于向上轉(zhuǎn)型(Upcasting),或者叫做自動(dòng)類(lèi)型轉(zhuǎn)換。

我來(lái)解釋一下這段代碼片段【Animal a1 = new Cat();a1.move(); 】:java程序包括編譯和運(yùn)行兩個(gè)階段,分析java程序一定要先分析編譯階段,然后再分析運(yùn)行階段,在編譯階段編譯器只知道a1變量的數(shù)據(jù)類(lèi)型是Animal,那么此時(shí)編譯器會(huì)去Animal.class字節(jié)碼中查找move()方法,發(fā)現(xiàn)Animal.class字節(jié)碼中存在move()方法,然后將該move()方法綁定到a1引用上,編譯通過(guò)了,這個(gè)過(guò)程我們可以理解為“靜態(tài)綁定”階段完成了。緊接著程序開(kāi)始運(yùn)行,進(jìn)入運(yùn)行階段,在運(yùn)行的時(shí)候?qū)嶋H上在堆內(nèi)存中new的對(duì)象是Cat類(lèi)型,也就是說(shuō)真正在move移動(dòng)的時(shí)候,是Cat貓對(duì)象在移動(dòng),所以運(yùn)行的時(shí)候就會(huì)自動(dòng)執(zhí)行Cat類(lèi)當(dāng)中的move()方法,這個(gè)過(guò)程可以稱為“動(dòng)態(tài)綁定”。但無(wú)論是什么時(shí)候,必須先“靜態(tài)綁定”成功之后才能進(jìn)入“動(dòng)態(tài)綁定”階段。

來(lái)看以下的一段代碼以及編譯結(jié)果:

public class Test03 {
	public static void main(String[] args) {
		Animal a = new Cat();
		a.catchMouse();
	}
}

編譯結(jié)果:

Java多態(tài)

圖13-7:編譯錯(cuò)誤信息

有人認(rèn)為Cat貓是可以抓老鼠的呀,為什么會(huì)編譯報(bào)錯(cuò)呢?那是因?yàn)?ldquo;Animal a = new Cat();”在編譯的時(shí)候,編譯器只知道a變量的數(shù)據(jù)類(lèi)型是Animal,也就是說(shuō)它只會(huì)去Animal.class字節(jié)碼中查找catchMouse()方法,結(jié)果沒(méi)找到,自然“靜態(tài)綁定”就失敗了,編譯沒(méi)有通過(guò)。就像以上描述的錯(cuò)誤信息一樣:在類(lèi)型為Animal的變量a中找不到方法catchMouse()。

那么,假如說(shuō)我就是想讓這只貓去抓老鼠,以上代碼應(yīng)該如何修改呢?請(qǐng)看以下代碼:

public class Test04 {
	public static void main(String[] args) {
		//向上轉(zhuǎn)型
		Animal a = new Cat();
		//向下轉(zhuǎn)型:為了調(diào)用子類(lèi)對(duì)象特有的方法
		Cat c = (Cat)a;
		c.catchMouse();
	}
}

運(yùn)行結(jié)果如下圖所示:

圖13-8:向下轉(zhuǎn)型

我們可以看到直接使用a引用是無(wú)法調(diào)用catchMouse()方法的,因?yàn)檫@個(gè)方法屬于子類(lèi)Cat中特有的行為,不是所有Animal動(dòng)物都可以抓老鼠的,要想讓它去抓老鼠,就必須做向下轉(zhuǎn)型(Downcasting),也就是使用強(qiáng)制類(lèi)型轉(zhuǎn)換將Animal類(lèi)型的a引用轉(zhuǎn)換成Cat類(lèi)型的引用c(Cat c = (Cat)a;),使用Cat類(lèi)型的c引用調(diào)用catchMouse()方法。

通過(guò)這個(gè)案例,可以得出:只有在訪問(wèn)子類(lèi)型中特有數(shù)據(jù)的時(shí)候,需要先進(jìn)行向下轉(zhuǎn)型。其實(shí)向下轉(zhuǎn)型就是用在這種情形之下。那么向下轉(zhuǎn)型會(huì)存在什么風(fēng)險(xiǎn)嗎?請(qǐng)看以下代碼:

public class Test05 {
	public static void main(String[] args) {
		Animal a = new Bird();
		Cat c = (Cat)a;
	}
}

以上代碼可以編譯通過(guò)嗎?答案是可以的,為什么呢?那是因?yàn)榫幾g器只知道a變量是Animal類(lèi)型,Animal類(lèi)和Cat類(lèi)之間存在繼承關(guān)系,所以可以進(jìn)行向下轉(zhuǎn)型(前面提到過(guò),只要兩種類(lèi)型之間存在繼承關(guān)系,就可以進(jìn)行向上或向下轉(zhuǎn)型),語(yǔ)法上沒(méi)有錯(cuò)誤,所以編譯通過(guò)了。但是運(yùn)行的時(shí)候會(huì)出問(wèn)題嗎,因?yàn)楫吘筧引用指向的真實(shí)對(duì)象是一只小鳥(niǎo)。來(lái)看運(yùn)行結(jié)果:

Java開(kāi)發(fā)

圖13-9:類(lèi)型轉(zhuǎn)換異常

以上的異常是很常見(jiàn)的ClassCastException,翻譯為類(lèi)型轉(zhuǎn)換異常,這種異常通常出現(xiàn)在向下轉(zhuǎn)型的操作過(guò)程當(dāng)中,當(dāng)類(lèi)型不兼容的情況下進(jìn)行轉(zhuǎn)型出現(xiàn)的異常,之所以出現(xiàn)此異常是因?yàn)樵诔绦蜻\(yùn)行階段a引用指向的對(duì)象是一只小鳥(niǎo),然后我們要將一只小鳥(niǎo)轉(zhuǎn)換成一只貓,這顯然是不合理的,因?yàn)樾▲B(niǎo)和貓之間是沒(méi)有繼承關(guān)系的。為了避免這種異常的發(fā)生,建議在進(jìn)行向下轉(zhuǎn)型之前進(jìn)行運(yùn)行期類(lèi)型判斷,這就需要我們學(xué)習(xí)一個(gè)運(yùn)算符了,它就是instanceof。

instanceof運(yùn)算符的語(yǔ)法格式是這樣的:

(引用 instanceof 類(lèi)型)

instanceof運(yùn)算符的運(yùn)算結(jié)果是布爾類(lèi)型,可能是true,也可能是false,假設(shè)(c instanceof Cat)結(jié)果是true則表示在運(yùn)行階段c引用指向的對(duì)象是Cat類(lèi)型,如果結(jié)果是false則表示在運(yùn)行階段c引用指向的對(duì)象不是Cat類(lèi)型。有了instanceof運(yùn)算符,向下轉(zhuǎn)型就可以這樣寫(xiě)了:

public class Test05 {
	public static void main(String[] args) {
		Animal a = new Bird();
		if(a instanceof Cat){
			Cat c = (Cat)a;
			c.catchMouse();
		}
	}
}

以上程序運(yùn)行之后不再發(fā)生異常,并且什么也沒(méi)有輸出,那是因?yàn)閕f語(yǔ)句的條件并沒(méi)有成立,因?yàn)樵谶\(yùn)行階段a引用指向的對(duì)象不是Cat類(lèi)型,所以(a instanceof Cat)是false,自然就不會(huì)進(jìn)行向下轉(zhuǎn)型了,也不會(huì)出現(xiàn)ClassCastException異常了。在實(shí)際開(kāi)發(fā)中,java中有這樣一條默認(rèn)的規(guī)范需要大家記住:在進(jìn)行任何向下轉(zhuǎn)型的操作之前,要使用instanceof進(jìn)行判斷,這是一個(gè)很好的編程習(xí)慣。就像下面的代碼:

public class Test05 {
	public static void main(String[] args) {
		Animal a = new Bird();
		if(a instanceof Cat){
			Cat c = (Cat)a;
			c.catchMouse();
		}else if(a instanceof Bird){
			Bird b = (Bird)a;
			b.sing();
		}
	}
}

運(yùn)行結(jié)果如下圖所示:

圖13-10:向下轉(zhuǎn)型前判斷

到這里大家理解什么是多態(tài)了嗎?其實(shí)多態(tài)存在的三個(gè)必要條件分別是:

● 繼承

● 方法覆蓋

● 父類(lèi)型引用指向子類(lèi)型對(duì)象

多態(tài)顯然是離不開(kāi)方法覆蓋機(jī)制的,多態(tài)就是因?yàn)榫幾g階段綁定父類(lèi)當(dāng)中的方法,程序運(yùn)行階段自動(dòng)調(diào)用子類(lèi)對(duì)象上的方法,如果子類(lèi)對(duì)象上的方法沒(méi)有進(jìn)行重寫(xiě),這個(gè)時(shí)候創(chuàng)建子類(lèi)對(duì)象就沒(méi)有意義了,自然多態(tài)也就沒(méi)有意義了,只有子類(lèi)將方法重寫(xiě)之后調(diào)用到子類(lèi)對(duì)象上的方法產(chǎn)生不同效果時(shí),多態(tài)就形成了。實(shí)際上方法覆蓋機(jī)制和多態(tài)機(jī)制是捆綁的,誰(shuí)也離不開(kāi)誰(shuí),多態(tài)離不開(kāi)方法覆蓋,方法覆蓋離開(kāi)了多態(tài)也就沒(méi)有意義了。

接下里就來(lái)看看之前沒(méi)有解決的問(wèn)題:方法覆蓋主要是說(shuō)實(shí)例方法,靜態(tài)方法為什么不談方法覆蓋?

public class OverrideTest {
	public static void main(String[] args) {
		Math.sum();
		MathSubClass.sum();
	}
}
public class Math{
	public static void sum(){
		System.out.println("Math's sum execute!");
	}
}
public class MathSubClass extends Math{
	//嘗試覆蓋從父類(lèi)中繼承過(guò)來(lái)的靜態(tài)方法
	public static void sum(){
		System.out.println("MathSubClass's sum execute!");
	}
}

運(yùn)行結(jié)果如下圖所示:

Java開(kāi)發(fā)

圖13-11:嘗試覆蓋靜態(tài)方法

我們發(fā)現(xiàn)貌似也發(fā)生了覆蓋,在程序運(yùn)行的時(shí)候確實(shí)也調(diào)用了“子類(lèi)MathSubClass”的sum方法,但這種“覆蓋”有意義嗎?其實(shí)上面的課程我們已經(jīng)說(shuō)過(guò)了,方法覆蓋和多態(tài)機(jī)制聯(lián)合起來(lái)才有意義,我們來(lái)看看這種“覆蓋”是否能夠達(dá)到“多態(tài)”的效果,請(qǐng)看代碼:

public class OverrideTest {
	public static void main(String[] args) {
		Math m = new MathSubClass();
		m.sum();
		m = null;
		m.sum();
	}
}

運(yùn)行結(jié)果如下圖所示:

圖13-12:運(yùn)行結(jié)果

通過(guò)以上的代碼,我們發(fā)現(xiàn)雖然創(chuàng)建了子類(lèi)型對(duì)象“new MathSubClass()”,但是程序在運(yùn)行的時(shí)候仍然調(diào)用的是Math類(lèi)當(dāng)中的sum方法,甚至m = null的時(shí)候再去調(diào)用m.sum()也沒(méi)有出現(xiàn)空指針異常,這說(shuō)明靜態(tài)方法的執(zhí)行壓根和對(duì)象無(wú)關(guān),既然和對(duì)象無(wú)關(guān)那就表示和多態(tài)無(wú)關(guān),既然和多態(tài)無(wú)關(guān),也就是說(shuō)靜態(tài)方法的“覆蓋”是沒(méi)有意義的,所以通常我們不談靜態(tài)方法的覆蓋。

主站蜘蛛池模板: 亚洲国产成人久久综合野外 | 夜夜操夜夜摸 | 欧美一级夜夜爽 视频 | 久久精品一区二区三区不卡 | 亚洲国产观看 | 久久精品国产亚洲沈樵 | 欧美成人天天综合天天在线 | 91在线观 | 黄色片免费在线观看视频 | 亚洲高清国产一区二区三区 | 天天射天天做 | 中文字幕视频在线免费观看 | 成人毛片免费观看视频大全 | 在线看片亚洲 | 欧美国产成人免费观看永久视频 | 91久久澡人人爽人人添 | 国产伦精品一区二区三区视频小说 | 亚洲另类精品综合 | 亚洲酷色综合 | 91视频播放 | 亚洲免费视频观看 | 国产精品一国产精品 | 久久99热不卡精品免费观看 | 男人爱看的网站 | 国产免费青青青免费视频观看 | 国产综合精品 | 福利姬视频在线观看 | 久久日韩精品中文字幕网 | 4hu影院永久在线播放 | 四虎海外影库www4hu | 永久黄网站色视频免费 | 四虎在线视频免费观看 | 在线观看精品视频一区二区三区 | 日本草草影院 | 老司机午夜免费视频 | 亚洲国产欧美精品 | 久在线精品视频 | 亚洲精品国产福利一区二区三区 | 美国成人毛片 | 欧美日韩黄色大片 | 奇米网久久 |