在java中強制類型轉換分爲基本數據類型和引用數據類型兩種,這裏咱們討論的後者,也就是引用數據類型的強制類型轉換。java
在Java中因爲繼承和向上轉型,子類能夠很是天然地轉換成父類,可是父類轉換成子類則須要強制轉換。由於子類擁有比父類更多的屬性、更強的功能,因此父 類轉換爲子類須要強制。那麼,是否是隻要是父類轉換爲子類就會成功呢?其實否則,他們之間的強制類型轉換是有條件的。函數
當咱們用一個類型的構造器構造出一個對象時,這個對象的類型就已經肯定的,也就說它的本質是不會再發生變化了。在Java中咱們能夠經過繼承、向上轉型的關係使用父類類型來引用它,這個時候咱們是使用功能較弱的類型引用功能較強的對象,這是可行的。可是將功能較弱的類型強制轉功能較強的對象時,就不必定能夠行了。佈局
舉個例子來講明。好比系統中存在Father、Son兩個對象。首先咱們先構造一個Son對象,而後用一個Father類型變量引用它:post
Father father = new Son();spa
在這裏Son對象實例被向上轉型爲father了,可是請注意這個Son對象實例在內存中的本質仍是Son類型的,只不過它的能力臨時被消弱了而已,若是咱們想變強怎麼辦?將其對象類型還原!指針
Son son = (Son)father;code
這條語句是可行的,其實father引用仍然是Father類型的,只不過是將它的能力增強了,將其增強後轉交給son引用了,Son對象實例在son的變量的引用下,恢復真身,可使用所有功能了。對象
每次轉載,我都會附加本身的感想和有關的知識點,此次也不例外:blog
-----------------------------------------------------------------------------------------------------------------------繼承
上面提到一句特別重要的話:當 咱們用一個類型的構造器構造出一個對象時,這個對象的類型就已經肯定的,也就說它的本質是不會再發生變化了。各類類型的轉換,只不過是他的能力被臨時消弱 了而已(能力被削弱的意思是你訪問這個對象用的指針能看到這個對象的多少的功能,雖然這個對象有不少的功能擺在那裏),其本質的東西並無任何的變化(這 句話是重點)。看下面的一段Java的代碼:
1 public class TestCastClassException 2 { 3 public static void main(String[] args) 4 { 5 Father father = new Son(); 6 7 //這兩句話是不對的,由於一個father類型的引用(指針)是看不見、看不到son中新定義的數據成員或者成員函數的 8 //雖然這個對象的本質是Son類型的,它也確實有這樣的數據成員和成員函數,可是指針的做用範圍不夠,它看不到。 9 //代碼後面附上模型分析 10 //father.son = 2; 11 //father.show_son(); 12 13 father.show_father(); 14 father.show(); 15 Father father1 = (Father)father;//一個對象在內存中被new出來後,只能選擇訪問它的方式,不能修改它的佈局(包含的成員的個數等) 16 father1.show(); 17 18 } //main 19 } 20 21 class Father 22 { 23 public int father = 2; 24 Father(){} 25 26 void show() 27 { 28 System.out.println("This is father"); 29 } 30 31 void show_father() 32 { 33 System.out.println("father!!"); 34 } 35 } 36 37 class Son extends Father 38 { 39 public int son = 1; 40 Son(){} 41 void show() 42 { 43 System.out.println("This is son"); 44 } 45 46 void show_son() 47 { 48 System.out.println("son!!"); 49 } 50 }
下面是具體的模型,咱們以C++的虛函數模型類比Java:
解釋:若是子類中有和父類同樣的函數,那麼子類的函數會覆蓋父類的 相同的函數,這種覆蓋叫作重寫,這種覆蓋的行爲表如今子類對象中繼承父類的那部分的成員函數指針部分的相同函數被覆蓋。然而子類中的成員函數的指針中並沒 有相應的函數。如上面的show()函數,子類重寫以後,直接覆蓋繼承父類的本來的show()函數,本身沒有必要留有備份。
還有就是一旦這個son對象被new出來以後,他在內存中的本質就 不會改變,我該有的就是個人,用Father類型的指針來訪問這個對象的時候,Father類型的指針的做用範圍是有限的,只能看到子類繼承自父類的那部 分,固然他能看到被重寫的show()函數,這也就是多態的實現。要想看到son中新定義的數據成員和成員函數,必須用Son類型的指針來訪問這個對象。
還有就是一旦某個對象被new出來後,咱們只能選擇不一樣的指針來選擇訪問它的方式,固然也能修改其中的某個數據成員的值,可是不能修改其數據成員的個數和成員函數的個數,也就是說這個對象的本質是不會變的了。
-----------------------------------------------------------------------------------------------------------------------
前面提到父類強制轉換成子類並非老是成功,那麼在什麼狀況下它會失效呢?
當引用類型的真實身份是父類自己的類型時,強制類型轉換就會產生錯誤。例如:
Father father = new Father();
Son son = (Son) father;
這個系統會拋出ClassCastException異常信息。
因此編譯器在編譯時只會檢查類型之間是否存在繼承關係,有則經過;而在運行時就會檢查它的真實類型,是則經過,不然拋出
ClassCastException異常。
因此在繼承中,子類能夠自動轉型爲父類,可是父類強制轉換爲子類時只有當引用類型真正的身份爲子類時纔會強制轉換成功,不然失敗。