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. C++ List的用法

    Lists将元素按顺序储存在链表中. 与 向量(vectors)相比, 它允许快速的插入和删除,但是随机访问却比较慢. assign() 给list赋值 back() 返回最后一个元素 begin() ...

  2. django框架进阶-cookie和session-长期维护

    ###############    python基础回顾:装饰器    ################ # 装饰器非常重要,1是写代码的时候,2是面试的时候,没有python开发不问装饰器的, # ...

  3. Java IO: InputStreamReader和OutputStreamWriter

    作者: Jakob Jenkov 译者: 李璟(jlee381344197@gmail.com) 本章节将简要介绍InputStreamReader和OutputStreamWriter.细心的读者可 ...

  4. 《你不知道的Javascript》学习笔记

    简介 众所周知,JavaScript 既是一门充满吸引力.简单易用的语言,又是一门具有许多复杂微妙技术的语言,即使是经验丰富的JavaScript 开发者,如果没有认真学习的话也无法真正理解它们. 如 ...

  5. Mysql主从同步原理简介

    1.定义:当master(主)库的数据发生变化的时候,变化会实时的同步到slave(从)库. 2.好处: 1)水平扩展数据库的负载能力. 2)容错,高可用.Failover(失败切换)/High Av ...

  6. mac安装并配置nexus3.5.1版本

    一.安装nexus 前置条件 :已经安装了JDK 1:下载nexus(http://www.sonatype.com/download-oss-sonatype) 最新版本(我的是3.5.1). 2: ...

  7. js Array 中的 map, filter 和 reduce

    原文中部分源码来源于:JS Array.reduce 实现 Array.map 和 Array.filter Array 中的高阶函数 ---- map, filter, reduce map() - ...

  8. Mybatis--映射器注解

    因为最初设计时,MyBatis 是一个 XML 驱动的框架.配置信息是基于 XML 的,而且 映射语句也是定义在 XML 中的.而到了 MyBatis 3,有新的可用的选择了.MyBatis 3 构建 ...

  9. 维生素D补充过多会中毒

    虽然我们的物质生活越来越丰富,各种食材几乎一年四季都能够吃到,然而却越来越多的人选择进行补充各种维生素,但是你知道吗?维生素不是我们想象中多吃无害的,补充过多也会要人命,特别是最近非常流行补充的一种维 ...

  10. Memcached笔记——(三)Memcached使用总结

    为了将N个前端数据同步,通过Memcached完成数据打通,但带来了一些新问题: 使用iBatis整合了Memcached,iBatis针对每台server生成了唯一标识,导致同一份数据sql会产生不 ...