激情久久久_欧美视频区_成人av免费_不卡视频一二三区_欧美精品在欧美一区二区少妇_欧美一区二区三区的

服務(wù)器之家:專注于服務(wù)器技術(shù)及軟件下載分享
分類導(dǎo)航

PHP教程|ASP.NET教程|Java教程|ASP教程|編程技術(shù)|正則表達(dá)式|C/C++|IOS|C#|Swift|Android|VB|R語(yǔ)言|JavaScript|易語(yǔ)言|vb.net|

服務(wù)器之家 - 編程語(yǔ)言 - Java教程 - Java多態(tài)性定義與用法實(shí)例詳解

Java多態(tài)性定義與用法實(shí)例詳解

2021-01-11 13:53dackwind Java教程

這篇文章主要介紹了Java多態(tài)性定義與用法,較為詳細(xì)的分析了多態(tài)的概念、功能以及java定義與實(shí)現(xiàn)面向?qū)ο蠖鄳B(tài)性的相關(guān)操作技巧,需要的朋友可以參考下

本文實(shí)例講述了Java多態(tài)性定義與用法。分享給大家供大家參考,具體如下:

多態(tài)性是通過(guò):

1 接口和實(shí)現(xiàn)接口并覆蓋接口中同一方法的幾不同的類體現(xiàn)的

2 父類和繼承父類并覆蓋父類中同一方法的幾個(gè)不同子類實(shí)現(xiàn)的.

一、基本概念

多態(tài)性:發(fā)送消息給某個(gè)對(duì)象,讓該對(duì)象自行決定響應(yīng)何種行為 。通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用 。

java 的這種機(jī)制遵循一個(gè)原則:當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰(shuí)的成員方法,但是這個(gè)被調(diào)用的方法必須是在超類中定義過(guò)的,也就是說(shuō)被子類覆蓋的方法 。

如果a是類A的一個(gè)引用,那么,a可以指向類A的一個(gè)實(shí)例,或者說(shuō)指向類A的一個(gè)子類 。

如果a是接口A的一個(gè)引用,那么,a必須指向?qū)崿F(xiàn)了接口A的一個(gè)類的實(shí)例 。

二、Java多態(tài)性實(shí)現(xiàn)機(jī)制

SUN目前的JVM實(shí)現(xiàn)機(jī)制,類實(shí)例的引用就是指向一個(gè)句柄(handle)的指針,這個(gè)句柄是一對(duì)指針:

一個(gè)指針指向一張表格,實(shí)際上這個(gè)表格也有兩個(gè)指針(一個(gè)指針指向一個(gè)包含了對(duì)象的方法表,另外一個(gè)指向類對(duì)象,表明該對(duì)象所屬的類型);

另一個(gè)指針指向一塊從java堆中為分配出來(lái)內(nèi)存空間 。

三、總結(jié)

1、通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用 。

?
1
2
3
DerivedC c2=new DerivedC();
BaseClass a1= c2; //BaseClass 基類,DerivedC是繼承自BaseClass的子類
a1.play(); //play()在BaseClass,DerivedC中均有定義,即子類覆寫了該方法

分析:

1、為什么子類的類型的對(duì)象實(shí)例可以覆給超類引用?

自動(dòng)實(shí)現(xiàn)向上轉(zhuǎn)型 。通過(guò)該語(yǔ)句,編譯器自動(dòng)將子類實(shí)例向上移動(dòng),成為通用類型BaseClass;

2、a.play()將執(zhí)行子類還是父類定義的方法?

子類的 。在運(yùn)行時(shí)期,將根據(jù)a這個(gè)對(duì)象引用實(shí)際的類型來(lái)獲取對(duì)應(yīng)的方法 。所以才有多態(tài)性 。一個(gè)基類的對(duì)象引用,被賦予不同的子類對(duì)象引用,執(zhí)行該方法時(shí),將表現(xiàn)出不同的行為 。

在a1=c2的時(shí)候,仍然是存在兩個(gè)句柄,a1和c2,但是a1和c2擁有同一塊數(shù)據(jù)內(nèi)存塊和不同的函數(shù)表 。

2、不能把父類對(duì)象引用賦給子類對(duì)象引用變量

?
1
2
BaseClass a2=new BaseClass();
DerivedC c1=a2;//出錯(cuò)

在java里面,向上轉(zhuǎn)型是自動(dòng)進(jìn)行的,但是向下轉(zhuǎn)型卻不是,需要我們自己定義強(qiáng)制進(jìn)行 。

c1=(DerivedC)a2; 進(jìn)行強(qiáng)制轉(zhuǎn)化,也就是向下轉(zhuǎn)型.

3、記住一個(gè)很簡(jiǎn)單又很復(fù)雜的規(guī)則,一個(gè)類型引用只能引用引用類型自身含有的方法和變量 。

你可能說(shuō)這個(gè)規(guī)則不對(duì)的,因?yàn)楦割愐弥赶蜃宇悓?duì)象的時(shí)候,最后執(zhí)行的是子類的方法的 。

其實(shí)這并不矛盾,那是因?yàn)椴捎昧撕笃诮壎ǎ瑒?dòng)態(tài)運(yùn)行的時(shí)候又根據(jù)型別去調(diào)用了子類的方法 。而假若子類的這個(gè)方法在父類中并沒(méi)有定義,則會(huì)出錯(cuò) 。

例如,DerivedC類在繼承BaseClass中定義的函數(shù)外,還增加了幾個(gè)函數(shù)(例如 myFun())

分析:

當(dāng)你使用父類引用指向子類的時(shí)候,其實(shí)jvm已經(jīng)使用了編譯器產(chǎn)生的類型信息調(diào)整轉(zhuǎn)換了 。

這里你可以這樣理解,相當(dāng)于把不是父類中含有的函數(shù)從虛擬函數(shù)表中設(shè)置為不可見(jiàn)的 。注意有可能虛擬函數(shù)表中有些函數(shù)地址由于在子類中已經(jīng)被改寫了,所以對(duì)象虛擬函數(shù)表中虛擬函數(shù)項(xiàng)目地址已經(jīng)被設(shè)置為子類中完成的方法體的地址了 。

4、Java與C++多態(tài)性的比較

jvm關(guān)于多態(tài)性支持解決方法是和c++中幾乎一樣的,只是c++中編譯器很多是把類型信息和虛擬函數(shù)信息都放在一個(gè)虛擬函數(shù)表中,但是利用某種技術(shù)來(lái)區(qū)別 。

Java把類型信息和函數(shù)信息分開(kāi)放 。Java中在繼承以后,子類會(huì)重新設(shè)置自己的虛擬函數(shù)表,這個(gè)虛擬函數(shù)表中的項(xiàng)目有由兩部分組成 。從父類繼承的虛擬函數(shù)和子類自己的虛擬函數(shù) 。

虛擬函數(shù)調(diào)用是經(jīng)過(guò)虛擬函數(shù)表間接調(diào)用的,所以才得以實(shí)現(xiàn)多態(tài)的 。Java的所有函數(shù),除了被聲明為final的,都是用后期綁定 。

四. 1個(gè)行為,不同的對(duì)象,他們具體體現(xiàn)出來(lái)的方式不一樣,

比如: 方法重載 overloading 以及 方法重寫(覆蓋)override

?
1
2
3
4
5
6
class Human{
void run(){輸出 人在跑}
}
class Man extends Human{
void run(){輸出 男人在跑}
}

這個(gè)時(shí)候,同是跑,不同的對(duì)象,不一樣(這個(gè)是方法覆蓋的例子)

?
1
2
3
4
class Test{
void out(String str){輸出 str}
void out(int i){輸出 i}
}

這個(gè)例子是方法重載,方法名相同,參數(shù)表不同

ok,明白了這些還不夠,還用人在跑舉例

?
1
Human ahuman=new Man();

這樣我等于實(shí)例化了一個(gè)Man的對(duì)象,并聲明了一個(gè)Human的引用,讓它去指向Man這個(gè)對(duì)象

意思是說(shuō),把 Man這個(gè)對(duì)象當(dāng) Human看了.

比如去動(dòng)物園,你看見(jiàn)了一個(gè)動(dòng)物,不知道它是什么, “這是什么動(dòng)物? ” “這是大熊貓! “

這2句話,就是最好的證明,因?yàn)椴恢浪谴笮茇?但知道它的父類是動(dòng)物,所以,這個(gè)大熊貓對(duì)象,你把它當(dāng)成其父類 動(dòng)物看,這樣子合情合理.這種方式下要注意 new Man();的確實(shí)例化了Man對(duì)象,所以ahuman.run()這個(gè)方法 輸出的 是 “男人在跑 “如果在子類 Man下你 寫了一些它獨(dú)有的方法 比如 eat(),而Human沒(méi)有這個(gè)方法,在調(diào)用eat方法時(shí),一定要注意 強(qiáng)制類型轉(zhuǎn)換 ((Man)ahuman).eat(),這樣才可以…

對(duì)接口來(lái)說(shuō),情況是類似的…

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
package domatic;
//定義超類superA
class superA {
int i = 100;
void fun(int j) {
j = i;
System.out.println("This is superA");
}
}
// 定義superA的子類subB
class subB extends superA {
int m = 1;
void fun(int aa) {
System.out.println("This is subB");
}
}
// 定義superA的子類subC
class subC extends superA {
int n = 1;
void fun(int cc) {
System.out.println("This is subC");
}
}
class Test {
public static void main(String[] args) {
superA a = new superA();
subB b = new subB();
subC c = new subC();
a = b;
a.fun(100);
a = c;
a.fun(200);
}
}
?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
/*
* 上述代碼中subB和subC是超類superA的子類,我們?cè)陬怲est中聲明了3個(gè)引用變量a, b,
* c,通過(guò)將子類對(duì)象引用賦值給超類對(duì)象引用變量來(lái)實(shí)現(xiàn)動(dòng)態(tài)方法調(diào)用 。也許有人會(huì)問(wèn):
* “為什么(1)和(2)不輸出:This is superA” 。
* java的這種機(jī)制遵循一個(gè)原則:當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),
* 被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰(shuí)的成員方法,
* 但是這個(gè)被調(diào)用的方法必須是在超類中定義過(guò)的,
* 也就是說(shuō)被子類覆蓋的方法 。
* 所以,不要被上例中(1)和(2)所迷惑,雖然寫成a.fun(),但是由于(1)中的a被b賦值,
* 指向了子類subB的一個(gè)實(shí)例,因而(1)所調(diào)用的fun()實(shí)際上是子類subB的成員方法fun(),
* 它覆蓋了超類superA的成員方法fun();同樣(2)調(diào)用的是子類subC的成員方法fun() 。
* 另外,如果子類繼承的超類是一個(gè)抽象類,雖然抽象類不能通過(guò)new操作符實(shí)例化,
* 但是可以創(chuàng)建抽象類的對(duì)象引用指向子類對(duì)象,以實(shí)現(xiàn)運(yùn)行時(shí)多態(tài)性 。具體的實(shí)現(xiàn)方法同上例 。
* 不過(guò),抽象類的子類必須覆蓋實(shí)現(xiàn)超類中的所有的抽象方法,
* 否則子類必須被abstract修飾符修飾,當(dāng)然也就不能被實(shí)例化了
*/

以上大多數(shù)是以子類覆蓋父類的方法實(shí)現(xiàn)多態(tài).下面是另一種實(shí)現(xiàn)多態(tài)的方法———–重寫父類方法

1.JAVA里沒(méi)有多繼承,一個(gè)類之能有一個(gè)父類 。而繼承的表現(xiàn)就是多態(tài) 。一個(gè)父類可以有多個(gè)子類,而在子類里可以重寫父類的方法(例如方法print()),這樣每個(gè)子類里重寫的代碼不一樣,自然表現(xiàn)形式就不一樣 。這樣用父類的變量去引用不同的子類,在調(diào)用這個(gè)相同的方法print()的時(shí)候得到的結(jié)果和表現(xiàn)形式就不一樣了,這就是多態(tài),相同的消息(也就是調(diào)用相同的方法)會(huì)有不同的結(jié)果 。舉例說(shuō)明:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
//父類
public class Father{
//父類有一個(gè)打孩子方法
public void hitChild(){
}
}
//子類1
public class Son1 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("為什么打我?我做錯(cuò)什么了!");
}
}
//子類2
public class Son2 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("我知道錯(cuò)了,別打了!");
}
}
//子類3
public class Son3 extends Father{
//重寫父類打孩子方法
public void hitChild(){
System.out.println("我跑,你打不著!");
}
}
//測(cè)試類
public class Test{
public static void main(String args[]){
Father father;
father = new Son1();
father.hitChild();
father = new Son2();
father.hitChild();
father = new Son3();
father.hitChild();
}
}

都調(diào)用了相同的方法,出現(xiàn)了不同的結(jié)果!這就是多態(tài)的表現(xiàn)!

希望本文所述對(duì)大家java程序設(shè)計(jì)有所幫助。

原文鏈接:http://blog.csdn.net/dackwind/article/details/49023921

延伸 · 閱讀

精彩推薦
主站蜘蛛池模板: 在线观看精品视频 | 午夜视频色| 国产精品久久久久久模特 | 久久久久久高清 | 毛片免费看网站 | 国产自在自线午夜精品视频在 | 激情小说激情电影 | av免费在线播放网址 | 古装三级在线观看 | 中国免费一级毛片 | 黄色试看视频 | 日本在线看片 | 欧美一级片在线 | 2019亚洲日韩新视频 | 56av国产精品久久久久久久 | 7777奇米成人四色影视 | 91精品国产综合久久男男 | 欧美性生活区 | 精品二区在线观看 | 国产成人高潮免费观看精品 | 久久精品国产亚洲7777小说 | 亚洲国产精品久久久久久久 | 久久人人做 | 国产三级在线观看a | 亚洲一级簧片 | 国产乱子视频 | 亚洲第一页综合 | 天堂在线中文资源 | 成人性视频欧美一区二区三区 | 九九热精彩视频 | 毛片视频大全 | 日本看片一区二区三区高清 | 免费黄色成人 | 国产精品久久久久久久久久久久久久久 | 成人电影毛片 | 久久伊人国产精品 | 农村寡妇偷毛片一级 | 欧美成人理论片乱 | 成人性视频在线 | 精品免费国产一区二区三区 | 国产午夜精品久久久久久久蜜臀 |