更新時間:2020-05-22 16:13:50 來源:動力節點 瀏覽2205次
在使用Java的多態機制時,常常使用的一個特性便是子類和父類之間的對象轉換。從子類向父類的轉換稱為向上轉換(upcasting),通過向上轉換,我們能夠在編寫程序時采用通用程序設計的思想,在需要使用子類對象的時候,通過把變量定義為父類型,我們可以通過一個變量,使用該父類型的所有子類型實例;從父類型向子類型的轉換稱為向下轉換(downcasting),通過向下轉換,我們能在必要的時候,將父類型變量轉換成子類型變量,使用一些通過子類型才能夠使用的方法。以下是我對于對象轉換的一些個人理解,如有不對,歡迎指正,虛心向大神們請教。
首先是從子類向父類的向上轉換。向上轉換比較直觀,總是能夠將一個子類的實例轉換為一個父類的對象,從繼承鏈的角度,這個特性很容易理解:繼承是一種“是一種”的關系,從父類派生出的子類,我們都能理解為,子類總是父類的一個實例。比如說,Fruit類派生出了Orange類,Apple類,Orange和Apple都是Fruit;Animal類派生出了Tiger類和Lion類,Tiger和Lion都是Animal。因此,從子類向父類的轉換不需要什么限制,只需直接將子類實例賦值給父類變量即可,這也是Java中的多態的實現機制。
//Test.java
public?class?Test?{
????public?static?void?main(String?args[])?{
????????Animal?tiger?=?new?Tiger();
????????Animal?lion?=?new?Lion();
????}
}
?
class?Animal?{
????String?name;
????Animal()?{
????????name?=?"animal";
????}
????Animal(String?name)?{
????????this.name?=?name;
????}
}
class?Tiger?extends?Animal?{
????Tiger()?{
????????super("tiger");
????}
}
class?Lion?extends?Animal?{
????Lion()?{
????????super("lion");
????}
}
然而從父類向子類的向下轉換就稍微復雜一些了。在講述向下轉換之前,也許有些剛學java的朋友會有點不解為什么要使用向下轉換,使用多態和動態綁定機制通過父類型變量使用子變量不就可以了么(比如我就曾對此感到疑惑)。這就要考慮到,在繼承關系中,有一些方法是不適合由父類定義并由子類繼承并重寫的,有些方法是子類特有的,不應該通過繼承得到,且子類可能也會有自己特有的成員變量,那么在使用多態機制的時候,若我們要通過父類型變量使用到這些子類特有的方法和屬性的話,就需要將服類型變量轉換成對應的子類型變量。一個典型例子便是標準庫中的數據類型包裝類:Integer類,Double類,Long類等,它們都繼承自Number類,且它們都有一個方法叫做compareTo用于比較兩個同樣的類型。然而這個方法是這些子類通過實現Comparable接口來實現的,在Number類中并沒有該方法的實現,因此若要通過Number類型變量來使用compareTo方法,就要先將Number類轉換成子類的對象。
從父類向子類的轉換就有限制了。首先,父類變量向子類轉換必須通過顯式強制類型轉換,采取和向上轉換相同的直接賦值方式是不行的,;并且,當把一個父類型變量實例轉換為子類型變量時,必須確保該父類變量是子類的一個實例,從繼承鏈的角度來理解這些原因:子類一定是父類的一個實例,然而父類卻不一定是子類的實例;比如說,Fruit未必是Orange,它可能是Apple;Animal也不一定是Tiger,它可能是Lion。用代碼來解釋一下:
Animal?tiger?=?new?Tiger();
Animal?lion?=?new?Lion();
在前面向上轉換的代碼示例當中,main方法中的這兩行代碼,意思就是父類型變量tiger是子類Tiger的一個實例,lion是Lion的一個實例。
也就是說,如果要把tiger轉換為Tiger類型,必須保證tiger本身是Tiger的一個實例,在上例中,如果要把tiger轉換成Lion類型,或是把Lion類型轉換為Tiger類型,都是行不通的,在運行時,這會拋出一個運行異常ClassCastException,表示類轉換異常。因此,在進行父類向子類的轉換時,一個好的習慣是通過instanceof運算符來判斷父類變量是否是該子類的一個實例:
Tiger?t?=?null;
if(tiger?instanceof?Tiger)
????t?=?(Tiger)tiger;
如果要通過父類調用子類變量的方法,那么要注意要將父類型變量和強制轉換用括號括起來:
Number?i?=?new?Integer(3);
System.out.println(
????((Integer)i).compareTo(new?Integer(4))
??????????????????);
因為成員訪問運算符.的優先級大于類型轉換,所以要用括號括起來保證類型轉換先于成員訪問進行運算。
前面說到用instanceof判斷父類是否是子類的一個實例是一個好習慣,如果不養成這個習慣的話很容易出問題,請看下面這段代碼:
Animal?animal?=?new?Tiger();
Lion?lion?=?(Lion)tiger;
前面說到,這段代碼會在運行時拋出ClassCastException異常,然而,這段代碼卻是能夠編譯成功的。原因是因為,Java編譯器并沒有聰明到能夠在編譯階段就知道父類型變量是哪一個子類的實例,所以,將animal轉換為Lion類型的代碼:(Lion)animal是能夠編譯通過的,即使事實上我們能看到animal是Tiger的一個實例,因為Animal類型確實能轉換成Lion類型,所以這條語句是合法的。所以,如果沒有使用instanceof防止不同子類型之間的對象轉換,而又不能指望編譯器檢查出這種轉換邏輯錯誤的話,就很容易犯錯了。
如果目的是把以上的,tiger與lion的共同屬性值賦值,可以使用以下方式:
BeanUtils.copyProperties(tiger,lion);?
以上就是動力節點java培訓機構的小編針對“Java編程分享,Java子類與父類轉換”的內容進行的回答,希望對大家有所幫助,如有疑問,請在線咨詢,有專業老師隨時為你服務。
0基礎 0學費 15天面授
有基礎 直達就業
業余時間 高薪轉行
工作1~3年,加薪神器
工作3~5年,晉升架構
提交申請后,顧問老師會電話與您溝通安排學習