我们参考下面这个例子:

读者可以提前考虑一下,这段程序的输出会是什么。

public class Polymorphism {

    /**
* 创建一个类A
* 该类中有一个方法draw,以及一个构造方法A
*/
static class A{
void draw(){
System.out.println("A.draw()");
}
A(){
System.out.println("A() before draw()");
draw();
System.out.println("A() after draw()");
}
} /**
* 创建一个类B,继承A
* 该类中同样有一个方法draw,以及一个构造方法B
*/
static class B extends A {
private int value=1;
void draw(){
System.out.println("B.draw(),value="+value);
}
B(int v){
value=v;
System.out.println("B.B(),value="+value);
}
} /*现在我们调用B的构造函数,构造一个B*/
public static void main(String[] args) {
new B(5);
}
}

最后的输出结果为

A() before draw()
B.draw(),value=0
A() after draw()
B.B(),value=5

初次分析

可见,当我们试图构造一个B时,应该会优先构造B的父类A,所以会调用父类A的构造函数A(),所以会输出

A() before draw()

这时A调用了draw()方法,因为是构造B类,而B类覆盖重写A类的draw()方法,所以这里应该调用的是B类重写过后的draw()方法,而B类的value默认值为1,所以会输出

B.draw(),value=1
A() after draw()

此刻父类A已经完成构造,所以接着才会构造B,调用B的构造函数B(),且传入的值为5,所以会输出

B.B(),value=5

而实际上,最后输出的并不是

B.draw(),value=1

而是

B.draw(),value=0

最后在《Thinking in Java》一书中找到了类似的例子,其中给出了一套正确的初始化顺序

(1)在其他任何事物之前,将分配给对象的存储空间初始化为二进制的零

(2)如前所述那样调用基类构造器。此时,调用被覆盖后的draw()方法  (要在调用B构造器之前调用),由于步骤1的缘故,我们此时会发现value的值为0。

(3)按照声明的顺序调用成员的初始化方法。

(4)调用导出类的构造器主体。

Java 多态方法构造器执行方法的更多相关文章

  1. Java 多态 父类和子类方法的访问控制权限

    Java 多态 父类和子类方法的访问控制权限 @author ixenos 父类和子类方法的访问控制权限 继承是为了扩展类的功能,而这种扩展显然就是对一个原始类的扩展,目的还是向上转型来调用,所以这就 ...

  2. 要想学好Java编程,构造器、方法重载、this关键字、垃圾回收机制,这4关一定要过!

    有人说,你应该关注时事.财经,甚至流行的电影.电视剧,才有可能趁着热点写出爆文:有人说,你别再写“无聊”的技术文了,因为程序员的圈子真的很小,即便是像鸿洋那样的招牌大牛,文章是那么的干货,浏览量有多少 ...

  3. Java基础03 构造器与方法重载

    作者:Vamei 出处:http://www.cnblogs.com/vamei 欢迎转载,也请保留这段声明.谢谢! 在方法与数据成员中,我们提到,Java中的对象在创建的时候会初始化(initial ...

  4. Java基础03 构造器与方法重载(转载)

    显式初始化要求我们在写程序时就确定初始值,这有时很不方便.我们可以使用构造器(constructor)来初始化对象.构造器可以初始化数据成员,还可以规定特定的操作.这些操作会在创建对象时自动执行. 定 ...

  5. java 多态 ---父类调用子类方法

    package test1;//多态的体现import javax.print.attribute.standard.RequestingUserName;import java.util.Scann ...

  6. JAVA多线程间隔时间段执行方法

    import java.util.Date; import java.util.Timer; import java.util.TimerTask; public class ManyProject ...

  7. java反射获取类的类名、属性名、属性类型、方法、执行方法、构造函数

    public class Demo02 { @SuppressWarnings("all") public static void main(String[] args) thro ...

  8. 用arthas的watch方法观察执行方法的输入输出

    watch 的参数比较多,主要是因为它能在 4 个不同的场景观察对象 参数名称 参数说明 class-pattern 类名表达式匹配 method-pattern 方法名表达式匹配 express 观 ...

  9. Java反射、动态加载(将java类名、方法、方法参数当做参数传递,执行方法)

    需求:将java类名.方法.方法参数当做参数传递,执行方法.可以用java的动态加载实现   反射的过程如下:     第一步:通过反射找到类并创建实例(classname为要实例化的类名,由pack ...

随机推荐

  1. 菜鸟笔记 -- Chapter 6.2.5 代码块

    6.2.5  代码块 在编程过程中我们通常会遇到如下这种形式的程序: package democlass; public class CodeBlock { { System.out.println( ...

  2. iOS | 实现拖拽CollectionViewCell排序

    现在很多项目都会用到类似拖动的效果,比如今日头条和网易新闻之类的资讯类产品,都有用该技术设置模块顺序的操作. 在iOS9.0之后,苹果提供相关的方法,非常方便. 设定三个私有属性 @property( ...

  3. Swift_数组详解

    Swift_数组详解 点击查看源码 初始化 //初始化 fileprivate func testInit() { //空数组 var array = [Int]() print(array) arr ...

  4. WebGL学习笔记(4)

    本篇笔记加强了上篇笔记示例代码的程序,实现了使用nodejs-websocket来广播每个玩家的坐标数据并在同一个世界模型中进行多人在线交互. websocket服务端: 安装nodejs与npm,创 ...

  5. Django从请求到返回流程

    图1:流程图 1. 用户通过浏览器请求一个页面2.请求到达Request Middlewares,中间件对request做一些预处理或者直接response请求3.URLConf通过urls.py文件 ...

  6. Firewalld共享上网及本地yum仓库搭建

    1.firewalld共享上网 1.服务端操作(有外网的服务器) 1.开启防火墙并加入开机自启动 [root@zeq ~]# systemctl start firewalld [root@zeq ~ ...

  7. ubuntu 18 lnmp

    1安装Nginx sudo apt-get install nginx 2安装PHP sudo apt- php7.-fpm 3安装mysql sudo apt-get install mysql 启 ...

  8. 移植Linux Kernel SM750 驱动到VxWorks 7

    一.SM750简介 SM750 是SiliconMotion 推出的一款适合嵌入式设备的显卡(Embedded GPU),采用PCIe接口与CPU连接,内部集成16MB DDR SDRAM显存,产品具 ...

  9. 【POJ】1008 Maya Calendar

    参考:https://blog.csdn.net/u011392408/article/details/28866779 https://blog.csdn.net/qq_36424540/artic ...

  10. JAVA多进程入门

    概念 并行和并发 并行:物理上的实现,在同一时间点上发生 并发:两个事件在一个时间段内发生,如单片机的单核多线程 进程和线程 进程:一个应用程序可以有多个进程,每一个进程有一个独立的内存空间 线程:一 ...