对于下面的代码,许多有经验的程序员都没能给出正确的答案。如果你能只看代码给出的答案和文章末尾出给出大答案一致,那么你已经掌握了Java对象的建构顺序,中间的分析可以不用看了。
/** * 父类Foo,实现控制台输出 * * @author youngto * @since 2013-01-25 */ class Foo { private int index = 100; //静态代码块 static { System.out.println("Foo static"); } //初始化代码块 { System.out.println("Foo initialization"); } public Foo() { System.out.println("Foo constructor"); System.out.println(printIndex()); } protected int printIndex() { return index; } } /** * 子类Bar,实现控制台输出 * * @author youngto * @since 2013-01-25 */ public class Bar extends Foo{ private int index = 100; static Bar bar = new Bar(); //静态代码块 static{ System.out.println("Bar static"); } //初始化代码块 { System.out.println("Bar initialization"); } public Bar() { System.out.println("Bar constructor"); System.out.println(printIndex()); } @Override protected int printIndex() { System.out.println(bar); return index; } public static void main(String[] args) { Foo foo = new Bar(); System.out.println(foo.printIndex()); foo = new Bar(); } }
在对象建构过程中。为确保其正确性,以下事件一定会以固定顺序发生:
a、从heap之中分配内存,用以存放全部的 instance 变量以及这个对象连同其 superclasses的实现专属数据(implementation-specific data)。所谓「实现专属数据」包括指向“class and method data的指针。
b、 对象的Instance变量被初始化为其相应的缺省值。
c、调用most derived class(最深层派生类)的构造函数(constructor)(注:事实上,构造函数被.class文件中的一个initialization method(初始化函数)替换了。Initialization method是名为<init>的特殊函数,由Java编译器安放在.class文件里。其中包含[构造函数代码]、[instance变量之初始化代码],以及[调用superclass Initialization method]之代码。)。构造函致做的第一件事就是调用superclass的构造函数。这个程序一直反复持续到 java.lang.object构适函数被调用为止。一定要记住,java.lang.object是一切java对象的base class。
d、所有对象的静态代码块或静态字段先获得执行,优先级从父类开始。
e、在构造函数本体执行之前,所有 instance 变量的初值设定式(initializers)和初始化区(initialization blocks)先获得执行,然后才执行构造函数本体。于是base class的构造函数最先执行,most derived class的构造函数最后执行。这使得任何class的构造函数都能放心大胆地使用其任何superclass 的instance 变量。
代码分析:
1、根据a:从heap分配内存,用来存放Bar的instance变量(index和bar)、Foo的instance变量(index),和一份「实现专属数据」。
2、根据b:instance变量被初始化为其相应缺省值,Bar的index被赋值为0,bar被赋值为null,Foo的index被赋值为0。
3、根据c:在代码65行准备创建Bar的一个对象,调用Bar的构造函数立即调用其superclass Foo的构造函数,Foo构造函数立即调用其superclass java.lang.Object的构造函数。
4、根据d:java.lang.Object构造函数返回后,在Foo对象中执行静态代码块输出Foo static,Foo静态代码块执行完,执行Bar静态代码此时代码执行到41行,准备创建Bar的第二个对象,针对这个对象,又从步骤1开始重复全部过程。
5、将要创建第二个Bar对象代码再次执行到Foo对象,由于静态对象只初始化一次,所以不会再次执行Foo的静态代码块,直接先执行初始化代码块输出Foo initialization,再执行Foo构造函数本体,根据e:Foo的index被赋值为100(这是来迷惑你的),输出Foo constructor;在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,根据e:此时代码还未执行到Bar的构造函数本体,所以此时printIndex函数输出缺省值bar=null,返回Bar的index缺省值0,因此这一步输出null,0,Foo构造函数完成,返回。
6、继续构建第二个Bar对象,执行Bar的初始化代码块,输出Bar initialization,再执行构造函数,输出Bar constructor。此时Bar的index赋值100,Bar的bar对象还正在构建中所以为null,输出null,100,Bar构造函数完成。
7、Object reference bar指向heap之中最后创建完成的Bar对象,此时在第一个Bar的对象创建过程中而创建的第二Bar对象创建完成。
8、继续第一个Bar对象的创建、执行Bar的静态代码块,输出Bar static。
9、从4-8步静态代码执行完成,继续执行Foo的初始化代码块输出Foo initialization,再执行Foo的构造函数本体输出Foo constructor。在Foo的构造函数中调用了printIndex函数,由于printIndex函数已经被子类Bar重写所以此时调用的是Bar中的printIndex函数,由于在构建第二个Bar对象时已经为静态字段bar赋值,所以静态变量bar此时有值,但实例变量index还是为缺省值0,输出Bar@4633c1aa和0,Foo构造函数完成,返回。
10、执行Bar的初始化代码块输出:Bar initialization,再执行Bar的构造函数输出Bar constructor,Bar@4633c1aa和100,Bar构造函数完成。
11、Object reference bar指向heap之中最后创建完成的Bar对象,此时第一个Bar的对象创建完成。
12、66行调用bar对象函数输出Bar@4633c1aa和100.
13、67行此时给bar引用从新赋值,又从步骤一重复全部过程,由于静态只实例化一次所以输出为:Foo initialization、Foo constructor、Bar@4633c1aa、0、Bar initialization、Bar constructor、Bar@4633c1aa、100
输出结果为:
//代码在65行建构第一个Bar对象
Foo static
//代码执行到41行建构第二个Bar对象
Foo initialization
Foo constructor
null
0
Bar initialization
Bar constructor
null
100
//代码执行到56行第二个Bar对象建构完,继续建构第一个Bar对象
Bar static
Foo initialization
Foo constructor
Bar@4633c1aa
0
Bar initialization
Bar constructor
Bar@4633c1aa
100
//66行调用第一个Bar对象的函数输出结果
Bar@4633c1aa
100
//67行此时第一个Bar对象执行完,给第一个Bar引用从新建构对象
Foo initialization
Foo constructor
Bar@4633c1aa
0
Bar initialization
Bar constructor
Bar@4633c1aa
100
相关推荐
Java建构主义教学实践 Java是一种流行的面向对象编程语言,许多高校开设了Java课程。但是,传统的教学模式只是知识简单地被复制,不利于激发学生的学习兴趣和学习激情。为了达到更好的教学效果,需要引进建构主义...
本文主要探讨了如何应用基于一致性建构原则的混合教学模式于Java课程中,以提高教学质量和学习效果。混合教学模式结合了线上与线下教学资源,旨在解决传统教学模式中存在的问题,包括学习目标不明确、教学方法单一、...
【基于Java的云计算编程模型建构】探讨了Java在云计算领域的核心地位和应用方式。Java,作为一种广泛应用的编程语言,因其特性如简洁性、兼容性、安全性等,成为了构建云计算编程模型的理想选择。云计算,根据服务...
《项目自动化之道——如何建构、部署、监控Java应用》是由Mike Clark撰写的一本关于提高Java应用开发效率和运维质量的专业书籍。这本书的核心是探讨如何利用自动化技术来优化项目的各个环节,从而提升团队的工作效能...
例如,可以采用项目驱动、案例分析等方式,让学生在实践中学习和解决问题,从而深入理解和掌握Java语言。 再者,教学评价方式也需要改革。单一的结果评价不能全面反映学生的学习过程和进步。在建构主义视角下,过程...
Java是一种广泛使用的、跨平台的编程语言,它提供了面向对象、分布式、多线程、动态、高性能、安全等特点,非常适合作为云计算环境下的编程语言。在云计算编程模型中,Java的MapReduce编程模型特别重要,它是一种...
教师在设计Java课程时,需遵循一致性建构原则,先介绍基础概念如变量、控制流,再逐步引入面向对象编程思想,如类、对象和继承。每个阶段都应设置与之前知识相关的实践任务,确保学生能逐步建立起完整的知识框架。 ...
项目自动化之道:如何建构、部署、监控Java应用
MCA JAVA后端架构师-2023版.xmind
本书基于建构主义教育思想,通过大量循序渐进的案例,让学生在体验中掌握Java语句,同时获得编程能力、排错能力和学习能力。本书多次使用陷阱式教学法,帮助学生深刻理解所学知识,理解面向对象编程思想。本书详细地...
"基于Java3D的Web3D交互式系统的建构" 本文主要介绍了基于Java3D技术的Web3D交互式系统的设计和实现。该系统基于浏览器/服务器(B/S)架构,使用Java3D API开发,拥有跨平台、交互式三维图形浏览器的特点。系统解决...
综上所述,基于GIS与VR技术的开埠城市空间形态演化分析方法的建构,不仅为历史城市空间形态的研究提供了新的视角和工具,也为未来的城市规划与管理提供了科学依据和实践指导。随着GIS与VR技术的不断进步和创新应用,...
综上所述,支持幼儿在建构游戏中进行深度学习的策略要求教师深入了解幼儿的学习特点和需求,为其提供适宜的外部支持、激发其积极情感、增强其观察和生活经验借鉴能力,并鼓励他们主动思考和操作。通过这种深度参与和...
知识点详述: ...通过上述知识点的梳理,我们不仅了解了Java的基础语法和物件导向的特性,还掌握了如何在Java中进行有效的数据管理和程序控制,为进一步深入学习Java和物件导向程式设计奠定了坚实的基础。