Java 名稱 參考 以及 物件(續)
如果以之前說的觀念,將『名稱』『參考』『物件』這三個名稱分隔清
楚,那在討論轉型的時候就會更加明確了。
以這個例子來說:
一般的書可能會說成『將這個 String 型別的物件轉型成 Object 型別的物
件』,其實這樣說也是不完全正確的。如果你還記得的話應該可以發現:
這個敘述除了會在電腦的記憶體某處產生一個物件之外,他還會傳回指向這
個物件的『參考』。而且查書也可以發現 new運算 的執行優先權高於強制轉
型的運算,而轉型運算會優於 = 的指定運算,也就是說第一個式子會先運算
new 的部分,然後把結果做轉型運算,最後再做指定運算。所以很明顯的
這個運算並不是將物件做轉型,而是將 new 運算的結果做轉型,換句話說就
是把『參考』轉型。所以你發現了嗎?
『物件』根本不會轉型,會轉型的是『參考』。
這就是我之前在其它討論串中所說的,不管如何轉型,Java 都會記住物件原
來是屬於什麼類別的,因為物件從頭到尾都沒有變過,變的是參考。至於
JVM 如何處理『參考』轉型後對物件方法以及物件欄位的呼叫,就跟 JVM
如何處理類別的程式碼,以及 JVM 如何處理物件的資料有關,這邊就不多加
討論。
實際上,原來的式子不強制轉型也是可行的。如:
為什麼 JVM 允許這樣做呢?因為 String 是 extends Object 的。讓我舉個
例子吧。之前說過變數是一個容器,一個用來放置參考的容器,如果我們有
一個杯子,這個杯子規定只能放入液體,那麼你可以把水放進去,也可以把
油放進去,也可以把果汁放進去,因為這些東西都是液體,也就是說 水 油
跟 果汁 都是 extends 液體,所以非常直覺的,放這些東西進去都不會出現
問題。但是如果今天是一顆蘋果,或是一袋花生,那就不能被塞到杯子裡,
因為這些東西根本不是液體,不能放進去也是很正常的。如果今天我們把蘋
果強制幾成果汁,把花生強制炸成花生油,那就可以放置。如果今天要塞進
去的是一把火,因為他跟液體扯不上關係,所以他本身不能放進去這個杯子
,火也沒有辦法強制變成液體,這時候火就是完全無法放入杯子裡的。所以
如果現在有一個式子:
這是可行的,因為 o 這個變數裡面的參考指向的是 String 的物件,所以可
以把 o 裡面所包含的參考轉型為 String 的格式,然後再把這個參考複製一
份放入 str 這個變數中。但是如果是:
那就會出問題。因為 o 變數裡面的參考指向的是 String 物件,如果將這個
參考變成 System 格式,那就再也無法參考到 String 物件了,所以這個轉
型會發生例外。
楚,那在討論轉型的時候就會更加明確了。
以這個例子來說:
Object o = (Object) new String("This is a String.");
一般的書可能會說成『將這個 String 型別的物件轉型成 Object 型別的物
件』,其實這樣說也是不完全正確的。如果你還記得的話應該可以發現:
new String("This is a String.");
這個敘述除了會在電腦的記憶體某處產生一個物件之外,他還會傳回指向這
個物件的『參考』。而且查書也可以發現 new運算 的執行優先權高於強制轉
型的運算,而轉型運算會優於 = 的指定運算,也就是說第一個式子會先運算
new 的部分,然後把結果做轉型運算,最後再做指定運算。所以很明顯的
(Object) .....;
這個運算並不是將物件做轉型,而是將 new 運算的結果做轉型,換句話說就
是把『參考』轉型。所以你發現了嗎?
『物件』根本不會轉型,會轉型的是『參考』。
這就是我之前在其它討論串中所說的,不管如何轉型,Java 都會記住物件原
來是屬於什麼類別的,因為物件從頭到尾都沒有變過,變的是參考。至於
JVM 如何處理『參考』轉型後對物件方法以及物件欄位的呼叫,就跟 JVM
如何處理類別的程式碼,以及 JVM 如何處理物件的資料有關,這邊就不多加
討論。
實際上,原來的式子不強制轉型也是可行的。如:
Object o = new String("This is a String");
為什麼 JVM 允許這樣做呢?因為 String 是 extends Object 的。讓我舉個
例子吧。之前說過變數是一個容器,一個用來放置參考的容器,如果我們有
一個杯子,這個杯子規定只能放入液體,那麼你可以把水放進去,也可以把
油放進去,也可以把果汁放進去,因為這些東西都是液體,也就是說 水 油
跟 果汁 都是 extends 液體,所以非常直覺的,放這些東西進去都不會出現
問題。但是如果今天是一顆蘋果,或是一袋花生,那就不能被塞到杯子裡,
因為這些東西根本不是液體,不能放進去也是很正常的。如果今天我們把蘋
果強制幾成果汁,把花生強制炸成花生油,那就可以放置。如果今天要塞進
去的是一把火,因為他跟液體扯不上關係,所以他本身不能放進去這個杯子
,火也沒有辦法強制變成液體,這時候火就是完全無法放入杯子裡的。所以
如果現在有一個式子:
String str = (String) o;
這是可行的,因為 o 這個變數裡面的參考指向的是 String 的物件,所以可
以把 o 裡面所包含的參考轉型為 String 的格式,然後再把這個參考複製一
份放入 str 這個變數中。但是如果是:
System s = (System) o;
那就會出問題。因為 o 變數裡面的參考指向的是 String 物件,如果將這個
參考變成 System 格式,那就再也無法參考到 String 物件了,所以這個轉
型會發生例外。

0 Comments:
張貼留言
<< Home