[短文速度-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面试填坑小分队
相关文章
相关标签/搜索