Java類是如何預設繼承Object的?

walkinger發表於2019-04-02

前言

學過Java的人都知道,Object是所有類的父類。但是你有沒有這樣的疑問,我並沒有寫extends Object,它是怎麼預設繼承Object的呢?

那麼今天我們就來看看像Java這種依賴於虛擬機器的程式語言是怎樣實現預設繼承Object的,以及Java編譯器JVM到底是如何做的?

繼承自Object驗證

首先我們來驗證一下Object是不是所有類的父類,隨便新建一個Java類,如下圖:

Java類是如何預設繼承Object的?
從上面的程式碼可以看出,new MyClass()打點之後可以選擇呼叫的方法有很多,我們定義的MyClass類裡面只有一個main方法,那這些方法哪來的,顯然是Object裡宣告的,故MyClass類的父類就是Object,因此,在MyClass中可以使用Object類的public或protected資源。

另外,當A類繼承MyClass類時,通過打點也可以調到Object內的方法,這是繼承的傳遞,好比Object是MyClass的“父親”,MyClass是A類的“父親”,Object是A類的“爺爺”,間接的繼承了Object。

因此,Object是超類,是所有類的父類。

推測可能的原因

要了解Java類是如何預設繼承Object的?的原因其實並不需要知道JVM的實現細節。只需瞭解一下對於這種虛擬機器程式的基本原理即可。一般對於這種靠虛擬機器執行的語言(如Java、C#等)會有兩種方法處理預設繼承問題。

編譯器處理

在編譯原始碼時,當一個類沒有顯式標明繼承的父類時,編譯器會為其指定一個預設的父類(一般為Object),而交給虛擬機器處理這個類時,由於這個類已經有一個預設的父類了,因此,VM仍然會按照常規的方法像處理其他類一樣來處理這個類。對於這種情況,從編譯後的二進位制角度來看,所有的類都會有一個父類(後面可以以此依據來驗證)。

JVM處理

編譯器仍然按照實際程式碼進行編譯,並不會做額外的處理,即如果一個類沒有顯式地繼承於其他類時,編譯後的程式碼仍然沒有父類。然後由虛擬機器執行二進位制程式碼時,當遇到沒有父類的類時,就會自動將這個類看成是Object類的子類(一般這類語言的預設父類都是Object)。

驗證結論

從上面兩種情況可以看出,第1種情況是在編譯器上做的文章,也就是說,當沒有父類時,由編譯器在編譯時自動為其指定一個父類。第2種情況是在虛擬機器上做文章,也就是這個預設的父類是由虛擬機器來新增的。

那麼Java是屬於哪一種情況呢?其實這個答案很好得出。只需要隨便找一個反編譯工具,將.class檔案進行反編譯即可得知編譯器是如何編譯的。

就以上面程式碼為例,如果是第1種情況,就算MyClass沒有父類,但由於編譯器已經為MyClass自動新增了一個Object父類,所以,在反編譯後得到的原始碼中的MyClass類將會繼承Object類的。如果不是這種情況,那麼就是第2種情況。

那麼實際情況是什麼樣的呢?現在我們就將MyClass.class反編譯看看到底如何。

jd-gui反編:

Java類是如何預設繼承Object的?
使用JDK自帶的工具(javap)反編譯

CMD命令列下執行:javap MyClass>MyClass.txt

Java類是如何預設繼承Object的?
可以看出實際的反編譯後的檔案中並沒有extends Object,使用排除法,因此是第2情況。

這樣來推匯出的結論是第2種情況,但事實真的如此嗎?為什麼網上還有說反編譯後的是有extends Object字樣?

JDK版本問題?

猜想是JDK版本的問題,於是把JDK版本切換到7,使用jd-gui和javap反編譯,接果和使用JDK8反編譯後的結果一樣,也都沒有extends Object

繼續換版本,昨晚在宿舍準備到Oracle官網下載JDK 6,但是死活下不來,今早到公司後第一件事就是下載,很順利,安裝後把JDK版本切換到JDK 6。

仍然在CMD視窗執行javap MyClass>MyClass.txt,得到的TXT檔案內容如下:

Java類是如何預設繼承Object的?
what?竟然有extends Object,jd-gui反編譯後的依然沒有。 即,JDK 6之前使用javap反編譯後的MyClass類顯式的繼承Object,JDK 7以後沒有;jd-gui反編譯後的不管JDK版本如何始終沒有。我們以java自帶的工具為準。

總結

那麼就是說JDK 6之前是編譯器處理,JDK 7之後是虛擬機器處理。

但是仔細想想我們在編輯器裡(IDE)打點時就能列出Object類下的方法,此時還沒輪到編譯器和jvm,編輯器就已經知道MyClass類的父類是Object類了,這是因為編輯器為我們做了一些智慧處理。

【end】

參考文獻:

java中 建立一個新的類 怎麼預設繼承Object類的: zhidao.baidu.com/question/12…

相關文章