[短文速度-4] new子類是否會實例化父類

前言

本篇文章討論一個很簡單的問題:實例化子類是否會實例化父類。java

本篇篇幅不長,適合碎片化時間閱讀。文章會從字節碼dump內存結構來解答這個問題。面試

愛因斯坦:「若是你不能簡單地解釋同樣東西,說明你沒真正理解它。」編程

[短文速讀-1] a=a+b和a+=b的區別安全

[短文速讀-2] 重載/重寫,動/靜態分派?(從新修訂)多線程

[短文速讀-3] 內部匿名類使用外部變量爲何要加finalide

[短文速度-4] new子類是否會實例化父類工具

[短文速讀 -5] 多線程編程引子:進程、線程、線程安全post

出場角色

小A:剛踏入Java編程之路…學習

MDove:一個快吃不上飯的Android開發…spa

正題

引子

小A:MDove,我最近在思考一個問題:實例化子類,會實例化父類麼?

MDove:這是一個有趣的問題。那我也反問你一個問題:抽象類能夠被實例化麼?

小A:雖然我很菜,但你請不要羞辱我!抽象類不能被實例化這是常識啊。

MDove:既然你知道這個,那我再問你:子類繼承了抽象類。此時,實例化子類,那麼父類做爲抽象類你以爲能被實例化麼?

小A:不能吧...

MDove:沒錯,就是如此啊。那你爲何還會有疑問呢?

疑惑點

小A:由於我在學習多態的時候,發現new子類,父類的構造方法也會執行,就像這樣:

public static void main(String[] args) {
    SunClass sunClass1 = new SunClass();
}

public class SunClass extends SuperClass {
    public String mSunName;
    public SunClass() {
        mSunName = "Sun Name";
        System.out.println(mSunName);
    }
}

public class SuperClass {
    public String mSuperName;
    public SuperClass() {
        mSuperName = "Super Name";
        System.out.println(mSuperName);
    }
}
複製代碼

image

小A:既然父類的構造方法都被執行了,那豈不也會實例化?

大錯特錯,父類不會實例化

MDove:有這樣的疑問,屬實不怪你。首先指出你一個錯誤:構造方法被執行不表明實例化這個類。爲何構造方法會被執行?那是由於要初始化父類變量。

MDove:咱們來看一下這個demo的字節碼:

image

MDove:看到紅線的指令了吧?子類的構造方法裏,調用了父類的構造方法。子類須要繼承父類的public/protect類型的變量和方法。有繼承,那麼勢必要調用構造方法對其進行內存分配

小A那若是這麼說的話?若是父類是一個空實現,是否是就不用調用父類的構造方法了?

MDove:不會的,編譯期會幫咱們隱式的調用。

MDove:我最開始也有這個疑惑,既然父類都沒有對變量進行賦值,爲啥還這麼費勁的調用它的構造方法?沒錯,咱們的父類可能不須要初始化變量,可是!!它的父類不必定不須要啊!!別忘了,咱們全部的類都隱式的繼承了Object,你告訴我,怎麼能夠作到跳過調用父類的構造方法,而直接調用Object的構造方法?很顯然,很差實現,所以逐級調用父類構造方法是一個合適的解決方案!

小A:這麼一說還真是這回事。

從內存分配角度看構造方法

MDove:爲了不文字的蒼白。這裏我使用一些工具,讓你看一看對象的內存分配。

這裏使用的工具是AndroidStudio3.0,由於我是一名Android開發,並且AS3.0在內存查看方面作的很出色,因此就用這個工具來展開這個內容。

MDove:我簡單新建了一個工程,很簡單的一個操做:

findViewById(R.id.btn_ok).setOnClickListener(new View.OnClickListener() {
`   @Override
    public void onClick(View v) {
        new SunClass();
    }
});
複製代碼

MDove:接下來讓咱們在Android Profiler裏邊看一些咱們的內存分配狀況,這裏我Dump了new子類的那個過程:

image

image

MDove:看到了吧?咱們的包下面只有這麼3個主要內存對象。一個是咱們MainActivity這個無需多言。MainActivity$1是咱們的Listener。而SunClass也就是咱們new的子類。很明顯,沒有父類!那讓咱們來看一看SunClass的內存都分配了些啥:

image

MDove:看沒看到父類的變量:mSuperName!並且在SunClass的對象裏。清晰了吧?父類構造方法的執行,是爲了給mSuperName這個變量進行賦值,而不是爲了實例化父類

小A:那若是我不在構造方法裏邊給變量賦值咋辦?好比這樣:

public class TestClass {
    public String name = "TestClass";

    public TestClass() {
    }
}
複製代碼

MDove:你口中所謂的不在構造方法裏邊賦值,只是java層面的而已。咱們看一看字節碼就清楚了:

image

MDove:看到了吧?咱們的java文件在被編譯成class文件時。咱們的編譯器會把對應成員變量初始化操做的字節碼寫到構造方法裏邊,就醬~

小A:那我學習道路常遇到的一些嘗試,好比:一、若是父類沒有顯示聲明一個無參構造方法,編譯器會隱式的增長一個無參構造方法。二、若是咱們不顯式的調用父類的構造方法,編譯器會隱式的幫咱們調用。是否是也是經過你說的這種形式去作?

MDove:沒錯,就醬~

小A:看樣子,學習的道路上不能想固然,有些內容還要多思考,多實踐纔多~

劇終

我是一個應屆生,最近和朋友們維護了一個公衆號,內容是咱們在從應屆生過渡到開發這一路所踩過的坑,以及咱們一步步學習的記錄,若是感興趣的朋友能夠關注一下,一同加油~

我的公衆號:IT面試填坑小分隊
相關文章
相關標籤/搜索