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