進(jìn)一步理解Java中的多態(tài)概念
多態(tài)性有兩種:
1)編譯時(shí)多態(tài)性
對(duì)于多個(gè)同名方法,如果在編譯時(shí)能夠確定執(zhí)行同名方法中的哪一個(gè),則稱為編譯時(shí)多態(tài)性.
2)運(yùn)行時(shí)多態(tài)性
如果在編譯時(shí)不能確定,只能在運(yùn)行時(shí)才能確定執(zhí)行多個(gè)同名方法中的哪一個(gè),則稱為運(yùn)行時(shí)多態(tài)性.
方法覆蓋表現(xiàn)出兩種多態(tài)性,當(dāng)對(duì)象獲得本類實(shí)例時(shí),為編譯時(shí)多態(tài)性,否則為運(yùn)行時(shí)多態(tài)性,例如:
XXXX x1 = new XXXX(參數(shù)列表); //對(duì)象獲得本類實(shí)例,對(duì)象與其引用的實(shí)例類型一致
XXX xx1 = new XXX(參數(shù)列表);
x1.toString(); //編譯時(shí)多態(tài)性,執(zhí)行XXX類的方法.
xx1.toString(); //編譯時(shí)多態(tài)性,執(zhí)行XXXX類覆蓋的方法.
XXXX為XXX的父類.
由于子類對(duì)象既是父類對(duì)象,父類對(duì)象與子類對(duì)象之間具有賦值相容性,父類對(duì)象能夠被賦值為子類對(duì)象.例如,
XXXX x2 = new XXX(參數(shù)列表); //父類對(duì)象獲得子類實(shí)例,子類對(duì)象即是父類對(duì)象
x2.toString(); //運(yùn)行時(shí)多態(tài)
x2聲明為父類對(duì)象卻獲得子類XXX的實(shí)例,那么x2.toString()究竟執(zhí)行父類方法還是執(zhí)行子類覆蓋的方法呢?
這分為兩種情況:
取決于子類是否覆蓋父類方法.如果子類覆蓋父類方法,則執(zhí)行子類方法;
如果沒有覆蓋,則執(zhí)行父類方法.
在編譯時(shí),僅僅依據(jù)對(duì)象所屬的類,系統(tǒng)無法確定到底應(yīng)該執(zhí)行那個(gè)類的方法,只有運(yùn)行時(shí)才能確定,因此這是運(yùn)行時(shí)多態(tài).
父類對(duì)象并不能執(zhí)行所有的子類方法,只能執(zhí)行那些父類中聲明\子類覆蓋的子類方法.
java多態(tài)實(shí)現(xiàn)
java的多態(tài)和c++一樣,是通過動(dòng)態(tài)綁定或者說運(yùn)行時(shí)綁定來實(shí)現(xiàn)的。當(dāng)調(diào)用某一個(gè)對(duì)象引用的方法時(shí),因?yàn)榫幾g器并不知道這個(gè)引用到底指向的是變量聲明時(shí)說明的類型對(duì)象,還是該類型子類的對(duì)象。因此編譯器無法為這次調(diào)用綁定到具體的某個(gè)方法。只有通過java中運(yùn)行時(shí)類型識(shí)別(RTT)在運(yùn)行時(shí)綁定到具體的方法
方法的重寫overriding和方法的重載overloading是java多態(tài)的不同表現(xiàn)。重寫overriding是父類和子類之間多態(tài)性的一種表現(xiàn),重載overloading是一個(gè)類中多態(tài)性的表現(xiàn)。
給出一個(gè)具體例子:
class People { public String toString() { return "I am a people!"; } public void eat() { }; public void speak() { }; } class Boy extends People { public String toString() { return "I am a boy!"; } public void fight() { }; public void speak() { }; } class Girl extends People { public String toString() { return "I am a girl!"; } public void sing() { }; public void speak() { }; } public class TestToString { public static void main(String args[]) { People p = new Girl(); System.out.println(p.toString()); } }
運(yùn)行結(jié)果是:
I am a girl!
p是People的一個(gè)引用,但是在運(yùn)行時(shí)因?yàn)槭荊irl對(duì)象,所以還是調(diào)用了Girl的toString方法
深入理解java多態(tài)
聲明,這里借鑒了其他同學(xué)的例子,原文鏈接:http://blog.csdn.net/thinkghoster/article/details/2307001
測(cè)試題目
class A { public String show(D obj) { return "A and D"; } public String show(A obj) { return "A and A"; } } class B extends A { public String show(B obj) { return "B and B"; } public String show(A obj) { return "B and A"; } } class C extends B { } class D extends B { } public class Main { public static void main(String args[]) { A a1 = new A(); A a2 = new B(); B b = new B(); C c = new C(); D d = new D(); System.out.println(a1.show(b)); // 1 System.out.println(a1.show(c)); // 2 System.out.println(a1.show(d)); // 3 System.out.println(a2.show(b)); // 4 System.out.println(a2.show(c)); // 5 System.out.println(a2.show(d)); // 6 System.out.println(b.show(b)); // 7 System.out.println(b.show(c)); // 8 System.out.println(b.show(d)); // 9 } }
答案
A and A A and A A and D B and A B and A A and D B and B B and B A and D
解析
我開始做這道題目,4、5、6、9全部做錯(cuò)了,原因就是沒能很好的理解java的多態(tài)性,這里說明一下
首先,要深刻的理解重寫和重載,重寫不僅僅包括了函數(shù)名稱相同,也包括參數(shù)類型和返回值類型
其次,深刻理解這句話“當(dāng)超類對(duì)象引用變量引用子類對(duì)象時(shí),被引用對(duì)象的類型而不是引用變量的類型決定了調(diào)用誰的成員方法,但是這個(gè)被調(diào)用的方法必須是在超類中定義過的,也就是說被子類重寫的方法”
然后,我們?cè)趤矸治鲆幌逻@幾道題目
問題:你認(rèn)為B重寫了父類A的show方法了嗎?如果重寫了,重寫了幾個(gè)?
答案:重寫了,重寫了一個(gè),也就是public String show(A obj),為什么public String show(B obj)不算重寫父類方法呢,很簡(jiǎn)單,因?yàn)閰?shù)類型不同
舉例分析
看了上面的分析,我們也來分析兩個(gè)例子:
一、a2.show(b):
a2是一個(gè)引用變量,類型為A,b是B的一個(gè)實(shí)例。首先,在類A中找show(B obj),沒有找到。于是到A的超類中找,而A沒有超類,因此轉(zhuǎn)向了A.this((super)B),(super)B為A,因此在A中找到了show(A obj)的方法,但是由于a2引用的類B的一個(gè)對(duì)象,B重寫了A的show(A obj)方法,因此最終鎖定到類B的show(A obj),輸出為“B and A”
二、a2.show(c):
a2是一個(gè)引用變量,類型為A,b是B的一個(gè)實(shí)例。首先,在類A中找show(C obj),沒有找到。于是到A的超類中找,而A沒有超類,因此轉(zhuǎn)向了A.this((super)C),(super)C為B,到這里為止,這個(gè)a2.show(c)變成了a2.show(b)的問題,而a2.show(b)上面已經(jīng)分析了是輸出"B and A",因此這里也是輸出“B and A”
相關(guān)文章
Spring Boot 2.7.6整合redis與低版本的區(qū)別
這篇文章主要介紹了Spring Boot 2.7.6整合redis與低版本的區(qū)別,文中補(bǔ)充介紹了SpringBoot各個(gè)版本使用Redis之間的區(qū)別實(shí)例講解,需要的朋友可以參考下2023-02-02SpringBoot入坑筆記之spring-boot-starter-web 配置文件的使用
本篇向小伙伴介紹springboot配置文件的配置,已經(jīng)全局配置參數(shù)如何使用的。需要的朋友跟隨腳本之家小編一起學(xué)習(xí)吧2018-01-01詳解Spring Boot的GenericApplicationContext使用教程
這篇教程展示了如何在Spring應(yīng)用程序中使用GenericApplicationContext 。小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-11-11詳解Spring Cloud Eureka多網(wǎng)卡配置總結(jié)
本篇文章主要介紹了詳解Spring Cloud Eureka多網(wǎng)卡配置總結(jié),小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2018-04-04零基礎(chǔ)學(xué)Java:Java開發(fā)工具 Eclipse 安裝過程創(chuàng)建第一個(gè)Java項(xiàng)目及Eclipse的一些基礎(chǔ)使用技巧
這篇文章主要介紹了零基礎(chǔ)學(xué)Java:Java開發(fā)工具 Eclipse 安裝過程創(chuàng)建第一個(gè)Java項(xiàng)目及Eclipse的一些基礎(chǔ)使用技巧,本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-09-09SpringBoot項(xiàng)目URL訪問異常的問題處理
這篇文章主要介紹了SpringBoot項(xiàng)目URL訪問異常的問題處理方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-07-07Hibernate中實(shí)現(xiàn)增刪改查的步驟詳解
本篇文章主要介紹了Hibernate中實(shí)現(xiàn)增刪改查的步驟與方法,具有很好的參考價(jià)值,下面跟著小編一起來看下吧2017-02-02詳解利用SpringCloud搭建一個(gè)最簡(jiǎn)單的微服務(wù)框架
這篇文章主要介紹了詳解利用SpringCloud搭建一個(gè)最簡(jiǎn)單的微服務(wù)框架,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧2017-11-11