前言
學(xué)過 Java的人都知道, Object是所有類的父類。但是你有沒有這樣的疑問,我并沒有寫 extends Object,它是怎么默認(rèn)繼承Object的呢?那么今天我們就來看看像 Java這種依賴于虛擬機(jī)的編程語言是怎樣實(shí)現(xiàn)默認(rèn)繼承 Object的,以及 Java編譯器和JVM到底是如何做的?
繼承自O(shè)bject驗(yàn)證
首先我們來驗(yàn)證一下 Object是不是所有類的父類,隨便新建一個(gè)Java類,如下圖:
從上面的代碼可以看出, new MyClass()打點(diǎn)之后可以選擇調(diào)用的方法有很多,我們定義的 MyClass類里面只有一個(gè) main方法,那這些方法哪來的,顯然是 Object里聲明的,故 MyClass類的父類就是 Object,因此,在 MyClass中可以使用 Object類的 public或 protected資源。
另外,當(dāng) A類繼承 MyClass類時(shí),通過打點(diǎn)也可以調(diào)到 Object內(nèi)的方法,這是繼承的傳遞,好比 Object是 MyClass的“父親”, MyClass是A類的“父親”, Object是A類的“爺爺”,間接的繼承了 Object。因此, Object是超類,是所有類的父類。
推測原因
- 編譯器處理
在編譯源代碼時(shí),當(dāng)一個(gè)類沒有顯式標(biāo)明繼承的父類時(shí),編譯器會為其指定一個(gè)默認(rèn)的父類(一般為
Object),而交給虛擬機(jī)處理這個(gè)類時(shí),由于這個(gè)類已經(jīng)有一個(gè)默認(rèn)的父類了,因此, JVM仍然會按照常規(guī)的方法像處理其他類一樣來處理這個(gè)類。對于這種情況,從編譯后的二進(jìn)制角度來看,所有的類都會有一個(gè)父類(后面可以以此依據(jù)來驗(yàn)證)。
- JVM處理
編譯器仍然按照實(shí)際代碼進(jìn)行編譯,并不會做額外的處理,即如果一個(gè)類沒有顯式地繼承于其他類時(shí),編譯后的代碼仍然沒有父類。然后由虛擬機(jī)運(yùn)行二進(jìn)制代碼時(shí),當(dāng)遇到?jīng)]有父類的類時(shí),就會自動將這個(gè)類看成是
Object類的子類(一般這類語言的默認(rèn)父類都是Object)。
驗(yàn)證結(jié)論
從上面兩種情況可以看出,第 1種情況 是在編譯器上做的文章,也就是說,當(dāng)沒有父類時(shí),由編譯器在編譯時(shí)自動為其指定一個(gè)父類。第 2種情況 是在虛擬機(jī)上做文章,也就是這個(gè)默認(rèn)的父類是由虛擬機(jī)來添加的。
那么 Java是屬于哪一種情況呢?
使用JDK自帶的工具(
javap)反編譯
可以看出實(shí)際的反編譯后的文件中并沒有 extends Object,使用排除法,因此是 第2種情況。
這樣來推導(dǎo)出的結(jié)論是 第2種情況,但事實(shí)真的如此嗎?為什么網(wǎng)上還有說反編譯后的是有 extends Object字樣?
JDK版本問題?
猜想是 JDK版本的問題,于是把 JDK版本切換到7,使用 jd-gui和 javap反編譯,接果和使用 JDK8反編譯后的結(jié)果一樣,也都沒有 extendsObject。繼續(xù)換版本,把 JDK版本切換到 JDK 6。
竟然有extends Object。即, JDK 6之前使用 javap反編譯后的 MyClass類顯式的繼承 Object, JDK 7以后沒有。
小結(jié)
那么就是說 JDK 6之前是編譯器處理,JDK 7之后是虛擬機(jī)處理。
但是仔細(xì)想想我們在編輯器里(IDEA)打點(diǎn)時(shí)就能列出 Object類下的方法,此時(shí)還沒輪到編譯器和JVM,編輯器就已經(jīng)知道MyClass類的父類是Object類了,這是因?yàn)榫庉嬈鳛槲覀冏隽艘恍┲悄芴幚怼?/p>

