java 抽象类语法_JAVA基础语法8--多态/抽象类/抽象方法
多態(tài)
繼承、封裝、多態(tài)、抽象是面向?qū)ο缶幊痰乃拇蠡咎卣鳌7庋b隱藏了類的內(nèi)部實現(xiàn)機制,從而可以在不影響使用者的前提條件下,改變類的內(nèi)部結(jié)構(gòu),同時保護了數(shù)據(jù)。繼承是為了重用父類代碼,同時為多態(tài)做準備。那么,什么是多態(tài)呢?
所謂多態(tài),英文單詞為polymorphism,這個英文單詞是由單詞poly(意思是很多或多個)和morph(意思是形狀或形式)組成的復(fù)合詞。多態(tài)一詞最早出現(xiàn)在生物學(xué),是指生物學(xué)的一個基本原則:一個生物或物種可以有多種不同的形式或階段。面向?qū)ο缶幊涛樟诉@一原則,在OOP中,多態(tài)是指一個對象有多種形式的能力。一個類的子類可以定義它們唯一的行為,同時共享父類的某些相同特征。
多態(tài)可以說是面向?qū)ο缶幊痰木杷凇R虼?#xff0c;理解多態(tài)的含義,對理解面向?qū)ο缶幊逃刑貏e重要的意義。
Java之所以引入多態(tài)的概念,原因之一是它在類的繼承問題上和C++不同。C++允許多繼承,這確實給它帶來了非常強大的功能,但是復(fù)雜的繼承關(guān)系也給C++開發(fā)者帶來了更大的麻煩。為了規(guī)避風(fēng)險,Java只允許單繼承,子類與父類間有IS-A的關(guān)系。這樣做雖然保證了繼承關(guān)系的簡單明了,但是勢必在功能上有很大的限制。所以,Java引入了多態(tài)性的概念,以彌補這點的不足。此外,我們在本節(jié)后面要學(xué)到的抽象類和接口也是解決單繼承規(guī)定限制的重要手段。
在Java中,多態(tài)有兩種理解方式:第一種是對象的不同的方法可以用相同的一個方法名,也就是重載的概念。?另一種是同一對象根據(jù)不同的消息執(zhí)行相應(yīng)的行為,也可以這樣認為發(fā)送消息給某一個對象,讓對象自行選擇哪種相應(yīng)的行為。根據(jù)這種兩種方式,所以多態(tài)可以分為靜態(tài)多態(tài)和動態(tài)多態(tài)。
靜態(tài)多態(tài)指的是程序在編譯時,系統(tǒng)就能決定調(diào)用哪個方法,所以也稱為編譯時多態(tài)。在Java中,靜態(tài)多態(tài)實現(xiàn)的方式就是方法重載,其調(diào)用規(guī)則是依據(jù)對象在定義時的類型相應(yīng)地調(diào)用對應(yīng)類中的重載方法。
動態(tài)多態(tài)指在運行中系統(tǒng)才能動態(tài)確定方法所指的對象,所以也稱為運行時多態(tài)。動態(tài)多態(tài)的實現(xiàn)方式是重寫父類中的同名成員方法,其調(diào)用規(guī)則是依據(jù)對象在實例化時而非定義時的類型,相應(yīng)地調(diào)用對應(yīng)類中的同名成員方法。也就是說,動態(tài)多態(tài)主要通過動態(tài)綁定和重寫的機制來實現(xiàn)。
多態(tài)技術(shù)基礎(chǔ)
在Java中,使用動態(tài)綁定和重寫機制來實現(xiàn)多態(tài),我們首先需要掌握如下三個基礎(chǔ)技術(shù)概念:
向上轉(zhuǎn)型技術(shù):一個父類的引用變量可以指向不同的子類對象,或者說一個子對象可以被當作一個父類類型。
instanceof關(guān)鍵字:instanceof關(guān)鍵字用于判斷運行時對象的真正類型。
可以規(guī)避掉“強制向下轉(zhuǎn)型過程中”可能會出現(xiàn)的轉(zhuǎn)型風(fēng)險。
動態(tài)綁定技術(shù):運行時根據(jù)父類引用變量所指對象的實際類型執(zhí)行相應(yīng)的子類方法,從而實現(xiàn)多態(tài)性。
1)向上轉(zhuǎn)型和向下轉(zhuǎn)型
在基礎(chǔ)數(shù)據(jù)類型中,我們已經(jīng)看到了表達式中數(shù)值數(shù)據(jù)類型byte、short、int、long、float和double的相互轉(zhuǎn)換規(guī)則,即:當從低精度數(shù)據(jù)類型向高精度數(shù)據(jù)類型轉(zhuǎn)換時實行自動轉(zhuǎn)換,這種類型轉(zhuǎn)換技術(shù)稱為向上轉(zhuǎn)型;當從高精度數(shù)據(jù)類型向低精度數(shù)據(jù)類型轉(zhuǎn)換時,需要使用強制類型轉(zhuǎn)換符,這種類型轉(zhuǎn)換技術(shù)稱為向下轉(zhuǎn)型。
對于引用數(shù)據(jù)類型,這種轉(zhuǎn)換技術(shù)依然適用。在父類和子類的繼承層次關(guān)系中,沿著子類向父類向上轉(zhuǎn)型是自動轉(zhuǎn)換,而從父類向子類必須使用強制類型轉(zhuǎn)換才能實現(xiàn)向下轉(zhuǎn)型。
例如:Employee e = new Salary("王二", "勝利大道24號", 47, 250000.00);
這里Salary是Employee的子類
那么,我們?yōu)槭裁匆靡粋€父類類型的引用去指向一個子類的對象呢?為什么不直接用一個子類類型的引用呢?這樣做到底有什么意義呢?
這是因為子類是對父類的一個改進和擴充,所以一般子類在功能上較父類更強大,屬性較父類更獨特。定義一個父類類型的引用指向一個子類的對象,既可以使用子類強大的功能,又可以抽取父類的共性,從而可以使代碼更容易編寫,更容易維護。
既然父類類型的引用沒有改變什么,那么為什么不總是用它呢?如果我們使用Employee類型的引用來指向一個Salary對象,對象不會丟失數(shù)據(jù),但是用父類類型的引用則不能直接訪問Salary類的成員變量和方法的。
如果要用父類類型的引用訪問子類的成員變量和方法,我們就必須將Employee類型的引用強制轉(zhuǎn)換為Salary類型的引用。
如:Salary?salary =(Salary)e;
注:引用數(shù)據(jù)類型向下強制轉(zhuǎn)換是有風(fēng)險的,不一定能夠轉(zhuǎn)型成功,如果要轉(zhuǎn)型成功,必須同時滿足以下兩個要求:
必須是父類引用指向一個子類的實現(xiàn)
強制轉(zhuǎn)換類型必須跟這個子類實現(xiàn)具體的類型一致,不能是父類其他子類的類型
使用instanceof關(guān)鍵字判斷對象的真正類型
Java語言的多態(tài)機制導(dǎo)致了引用變量的聲明類型和實際引用對象的類型可能不一致。為更準確鑒別一個對象的真正類型,Java語言引入了instanceof運算符。
使用instanceof的語句如下:
引用?instanceof 類名
如果引用是指定的類類型,那么instanceof運算符返回true,否則返回false。
動態(tài)綁定技術(shù)
我們首先要理解Java中的動態(tài)綁定機制。
在面向?qū)ο蟪绦蜷_發(fā)中,我們將一個方法調(diào)用與該方法所在的類關(guān)聯(lián)起來,稱為"綁定"。綁定分靜態(tài)綁定和動態(tài)綁定,或者稱為前期綁定和后期綁定。
所謂靜態(tài)綁定,是指在程序執(zhí)行前方法已經(jīng)被綁定,此時由編譯器或其它連接程序?qū)崿F(xiàn)。針對Java簡單的可以理解為程序編譯期的綁定;這里特別說明一點,Java中的方法只有final、static、private和構(gòu)造器是前期綁定。
所謂動態(tài)綁定,是指在運行時根據(jù)具體對象的類型進行綁定。Java中所有的普通方法,都采用動態(tài)綁定技術(shù)。通過動態(tài)綁定,JVM必須沿著繼承層次樹向下找,判斷一個方法是否被重寫。如果方法被重寫了,在運行時就執(zhí)行子類中的方法,而不是編譯時調(diào)用的父類方法。
多態(tài)的主要應(yīng)用
1)多態(tài)參數(shù)
所謂多態(tài)參數(shù),就是當方法的某個形式參數(shù)是一個引用的時候,與該引用兼容的任何對象都可以傳遞給方法,從而允許方法接受不同數(shù)據(jù)類型的形式參數(shù)。
例如,如下的方法有一個Employee類型的形式參數(shù):
public void payEmployee(Employee e)
如果要調(diào)用payEmployee()方法,我們需要用一個Employee對象作為實際參數(shù)。如果Salary和Hourly繼承自Employee類,那么Salary或Hourly對象也可以作為實際參數(shù)傳給payEmployee()方法。因為通過多態(tài),Salary或Hourly對象也是一個Employee對象。
現(xiàn)在,通過將Employee類型的引用作為形式參數(shù),使payEmployee()成為了一個更通用的方法。現(xiàn)在,它可以接受Employee、Hourly、Salary對象作為實際參數(shù)。如果出現(xiàn)了一個繼承自Employee類的新類,那么這個新類也可以傳遞給payEmplyee()。
2)異構(gòu)集合
多態(tài)最常見的應(yīng)用是創(chuàng)建一個不是同一類型,但是有共同父類的數(shù)據(jù)集合。不同對象的集合稱為異構(gòu)集合。
例如所有的類都繼承object,如果寫一個數(shù)組為object類型數(shù)組,那么就可以裝任何的類型對象。
多態(tài)總結(jié)
從以上示例,我們可以看出:父類類型的引用可以調(diào)用父類中定義的所有屬性和方法,而對于子類中定義而父類中沒有的方法,它是無可奈何的;同時,父類中的一個方法只有在父類中定義而在子類中沒有重寫的情況下,才可以被父類類型的引用調(diào)用;對于父類中定義的方法,如果子類中重寫了該方法,那么父類類型的引用將會調(diào)用子類中的這個方法,這就是動態(tài)綁定。也就是說:在多態(tài)機制中,是由被引用對象的類型,而不是引用變量的類型,決定了調(diào)用誰的成員方法。但是,這個被調(diào)用的方法必須是在父類中定義過的,也就是說被子類重寫的方法?。
因此,對于多態(tài),我們可以總結(jié)它為:
使用父類類型的引用指向子類的對象。
該引用只能調(diào)用父類中定義的方法,不能調(diào)用子類中獨有的方法。
如果子類中重寫了父類中的一個方法,那么在調(diào)用這個方法的時候,將會調(diào)用子類中的這個方法。
在多態(tài)中,子類可以調(diào)用父類中的所有方法。
在Java中,所有普通方法默認都是動態(tài)綁定,要避免動態(tài)綁定默認行為的唯一方法是將方法聲明為final。聲明為final的方法不能被重寫,所以JVM不需要沿著繼承層次樹向下尋找,并試圖判斷子類是否重寫該方法。基于此原因,final方法可以提升性能,因為避免了動態(tài)綁定的開銷。
抽象
我們在編寫類時,通常會在類中定義一些方法,用來描述該類所具有的行為。在類的方法體中,我們編寫代碼實現(xiàn)該類所要執(zhí)行的行為。在繼承關(guān)系中,子類繼承父類后,子類也就具有父類所具備的行為。如果子類繼承了父類的行為,但是與父類的行為實現(xiàn)方式不同,就需要通過方法重寫來覆蓋父類的行為。
如果我們不需要類的實例時,就可以將類設(shè)計成為一個抽象類。所謂抽象類,是不能被實例化的類。在抽象類中,類的所有其它功能都存在,成員變量、方法、構(gòu)造器都可以用同樣的方式訪問。我們只是不能創(chuàng)建抽象類的實例。
抽象類
在Java中,使用關(guān)鍵字abstract可以聲明一個抽象類,該關(guān)鍵字可以出現(xiàn)在類聲明時class關(guān)鍵字前的任何地方。
我們注意到類除了聲明為abstract外,其它的沒有改變。現(xiàn)在,我們不能實例化一個抽象的對象。但是對于它的子類沒有任何影響。
抽象方法
在父類中有的行為我們不需要去具體實現(xiàn),因為我們永遠不會調(diào)用它,但是它又是子類必須有的,我們只需要在子類中去對方法進行重寫,進行具體的實現(xiàn)。這種情況下,我們就可以用抽象方法了。如果我們想一個類包含一個特定的方法,該方法的實際實現(xiàn)由子類決定,那么我們就可以在父類中將該方法聲明為抽象方法。抽象方法只有方法簽名,沒有方法體。
代碼清單展示了聲明為抽象的computePay()方法。注意,該方法沒有定義部分,并且方法簽名后跟一個分號,沒有大括號。
/*代碼清單??Employee.java
這里,computePay()方法被聲明為抽象方法,在類中沒有實現(xiàn)
*/
public abstract class Employee{
private String name;
private String address;
private int number;
public abstract double computePay();
//類定義的剩余部分
}
將一個方法聲明為抽象方法有兩個結(jié)果:
類也必須聲明為抽象類。如果一個類包含了抽象方法,那么該類也必須是抽象的。
任何子類必須重寫抽象方法,除非子類本身也是抽象的。
從設(shè)計的角度看,將一個抽象方法放在父類中,可以強制任何子類實現(xiàn)一個特別的行為。繼承抽象方法的子類必須重寫該方法。如果子類不重寫抽象方法,那么子類必須是抽象類,子類的子類必須重寫該方法。最終,必須有一個后代類實現(xiàn)抽象方法,否則,我們就有一個不能實例化的抽象類層次。
那么,為什么要使用方法抽象呢?這是因為強制其它類實現(xiàn)某個行為有好處。
使用抽象類類和抽象方法的好處
用抽象類及接口最重要的用處還是在于,使代碼實現(xiàn)很方便的擴展,最簡單的就是在new對象時,將生成對象定義為接口,在以后需要替換時就很方便。
抽象類及接口,并不只是為了抽象,為了接口面抽象,而接口。在你需要用到一系列可繼承自抽象類的子類,或是需要實現(xiàn)共同接口的多個實現(xiàn)類時,才需要考慮。
其實抽象類的一個好處是類不能被實例化,最大的好處就是通過方法的覆蓋來實現(xiàn)多態(tài)的屬性。也就是運行期綁定。
用抽象的型別統(tǒng)一類型,來進行操作,有利于以后的擴展,移植,復(fù)用!!
總結(jié)
以上是生活随笔為你收集整理的java 抽象类语法_JAVA基础语法8--多态/抽象类/抽象方法的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 他山之石,可以攻玉——来自亚马逊的电商启
- 下一篇: 【应用推荐】常见资源管理器整理,内含使用