Java的继承是比较重要的特性,也是比较容易出错的地方,下面这个例子将展示如果父类构造器中调用被子类重写的方法时会出现的情况:

首先是父类:

public class test {
void fun(){
System.out.println("test fun()");
}
void fun1(){
System.out.println("test fun1()");
}
test(){
fun();
fun1();
}
public static void main(String[] args) {
test t =new test();
}
}

这里父类的构造器将调用一个fun方法,main函数的运行结果是:

test fun()
test fun1()

然后是子类:

public class test2 extends test {
int i = 2;
test2(){
fun();
}
void fun(){
System.out.println("test2 fun()");
System.out.println(i);
}
public static void main(String[] args) {
test2 t = new test2();
}
}

子类增加了一个字段i并初始化为2,并重写了fun方法,不仅打印的字符串不一样,还加了打印i的功能,构造器和父类一样调用了fun方法。main函数的运行结果是:

test2 fun()
0
test fun1()
test2 fun()
2

通常java的类进行初始化的时候,会先进行父类的初始化,所以会先调用父类的构造器,再进行子类的初始化,调用子类的构造器。

一开始写完代码我以为的结果是:

test fun()
test fun1()
test2 fun()
2

我以为就算父类的方法被重写了,也会调用自己的方法,但事实告诉我们,父类初始化过程中构造器如果调用了被子类重写的方法,会调用被子类重写的方法。

还有一点,如果子类重写的方法中使用了子类才定义的字段,那这个字段的值将是该字段类型的默认值。

所以类的初始化流程总结(继承相关)就是:

1.为对象分配的存储空间初始化为二进制零。

2.调用父类的构造器,如果调用被覆盖的方法,被覆盖的方法将被调用,如果使用了子类中才定义的字段,该字段的值为该字段类型的默认值。

3.调用子类的构造器。

(这里总结的初始化流程只总结了继承相关的,正常的static部分、初始化代码还是正常的样子)

为什么会出现这种情况呢,为什么需要先为对象的存储空间初始化为二进制零呢?

1.在继承中构造器的调用是分级的,先调用父类的,父类如果有父类就父类的。。。这一步是通过动态绑定实现的。

2.从概念上来说,构造器是用来初始化对象的,但是像上面那种情况,子类重写了父类的方法,使得父类将使用子类的成员,但是此时正在初始化父类,子类还没有进行初始化。

3.基于以上两点就将为对象分配的存储空间初始化为二进制零。

所以重写父类的方法的时候需要考虑到这个特性,这种特性可能会导致父类的初始化出现问题。

Java继承中构造器的调用原理的更多相关文章

  1. Java 继承中构造方法的执行顺序问题

    在Java中,如果一个类没有任何显式创建的构造器则该类默认会有一个无参构造器:如果显式创建了有参构造器则该类就不再有默认无参构造器. 在Java继承中,构造器并不能被继承,而是被显示或隐式调用. 1. ...

  2. JAVA 继承中的this和super

    学习java时看了不少尚学堂马士兵的视频,还是挺喜欢马士兵的讲课步骤的,二话不说,先做实例,看到的结果才是最实际的,理论神马的全是浮云.只有在实际操作过程中体会理论,在实际操作过程中升华理论才是最关键 ...

  3. 转转转!java继承中的this和super

    学习java时看了不少尚学堂马士兵的视频,还是挺喜欢马士兵的讲课步骤的,二话不说,先做实例,看到的结果才是最实际的,理论神马的全是浮云.只有在实际操作过程中体会理论,在实际操作过程中升华理论才是最关键 ...

  4. ecshop中ajax的调用原理 1

    ecshop中ajax的调用原理   1:首先ecshop是如何定义ajax对象的. ecshop中的ajax对象是在js/transport.js文件中定义的.里面是ajax对象文件.声明了一个va ...

  5. ECSHOP中ajax的调用原理

    ECSHOP中ajax的调用原理 ecshop中ajax的调用原理. 1.首先ecshop是如何定义ajax对象的. ecshop中的ajax对象是在js/transport.js文件中定义的.里面是 ...

  6. java中构造器的调用顺序

    在编程的过程中,我们经常会遇到多个类的继承问题,那么多个类的构造器是按照什么顺序调用的呢? 先看一段代码: public class Meal { public Meal() { System.out ...

  7. 【Java学习笔记之二十】final关键字在Java继承中的用法小结

    谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来了解final这个关键字的用法. ...

  8. Java继承中的转型及其内存分配

    看书的时候被一段代码能凌乱啦,代码是这样的: package 继承; abstract class People { public String tag = "疯狂Java讲义"; ...

  9. [Java] 继承中,父类被覆盖的成员变量、方法的可访问性

    在 Java 的继承机制里,在子类内部,可以访问父类被覆盖的变量和方法:在子类外部,可以访问父类的被覆盖变量,但是不能访问父类的被覆盖方法. 父类中被覆盖的方法不能在外部被方法,这是出于封装的考虑. ...

随机推荐

  1. 5.redis主从配置

    Redis的主从复制 1.什么是主从复制 持久化保证了即使redis服务重启也不会丢失数据,因为redis服务重启后会将硬盘上持久化的数据恢复到内存中,但是当redis服务器的硬盘损坏了可能会导致数据 ...

  2. 82)PHP,基本框架类步骤

    framework.class.php 基本代码展示: <?php /** * 框架初始化功能类 */ class Framework { /** * 入口 * 里面的static和self是一 ...

  3. Hypothesis Tests for One Population Mean When σ Is Known

    9.5 Hypothesis Tests for One Population Mean When σ Is Known 使用z-test前提(同使用mean distribution之前的考虑) 在 ...

  4. java5的静态导入import static

    在Java 5中,import语句得到了增强,以便提供甚至更加强大的减少击键次数功能,虽然一些人争议说这是以可读性为代价的.这种新的特性成为静态导入. 1.静态导入的与普通import的区别: imp ...

  5. deeplearning.ai 神经网络和深度学习 week3 浅层神经网络

    1. 第i层网络 Z[i] = W[i]A[i-1] + B[i],A[i] = f[i](Z[i]). 其中, W[i]形状是n[i]*n[i-1],n[i]是第i层神经元的数量: A[i-1]是第 ...

  6. 吴裕雄--天生自然Android开发学习:1.2.2 使用Android Studio开发Android APP

    1.下载Android Studio 官网下载:Android Studio for Window ... :http://developer.android.com/sdk/installing/s ...

  7. Mac下通过FFMpeg实现Android手机推流和播放

    一.Mac下搭建推流服务器(Nginx+RTMP+FFMpeg) 安装x264 git clone git://git.videolan.org/x264.git cd x264 ./configur ...

  8. win10安装inventor失败,怎么强力卸载删除注册表并重新安装

    一些搞设计的朋友在win10系统下安装inventor失败或提示已安装,也有时候想重新安装inventor的时候会出现本电脑windows系统已安装inventor,你要是不留意直接安装invento ...

  9. 将js进行到底:node学习4

    使用Node做web开发 HTTP与TCP 上一回使用node.js的NET(TCP)模块开发了一个聊天室demo.单纯用到了原始的TCP协议,可以说TCP是HTTP,SMTP,FTP的鼻祖了,后面的 ...

  10. container/injection简介以及发展历史

    一:什么是Container?Container的作用? 容器是一个标准的软件单元,它将代码及其所有依赖关系打包,以便应用程序从一个计算环境快速可靠地运行到另一个计算环境.container的主要作用 ...