文档章节

Java对象初始化顺序

群星纪元
 群星纪元
发布于 2016/10/06 22:20
字数 1070
阅读 5
收藏 0

最近我发现了一个有趣的问题,这个问题的答案乍一看下骗过了我的眼睛。看一下这三个类:

package com.ds.test;

public class Upper {
	String upperString;

	public Upper() {
		Initializer.initialize(this);
	}
}
package com.ds.test;

public class Lower extends Upper {

	String lowerString = null;
	
	public Lower() {
		super();
		System.out.println("Upper:  " + upperString);
		System.out.println("Lower:  " + lowerString);
	}
	
	public static void main(final String[] args) {
		new Lower();
	}
}
package com.ds.test;
public class Initializer {
	static void initialize(final Upper anUpper) {
		if (anUpper instanceof Lower) {
			Lower lower = (Lower) anUpper;
			lower.lowerString = "lowerInited";
		}
		anUpper.upperString = "upperInited";
	}
}

运行 Lower 这个类可以得到什么输出?在这个极简的例子中可以更容易地看到整个形势,但是这个情形发生在现实中会有非常多的代码分散一个人的注意力。

不管怎么样,输出是像这样的:

Upper:  upperInited
Lower:  null;

虽然小示例中使用了 String 类型,Initializer 类的实际代码中有一个用于注册的委托对象,与 Lower 类的功能是相同的 — 至少 Lower 类是这个意图。但由于某些原因在运行应用程序时没有工作。取而代之的是,使用了默认路径,委托对象没有被设置 (null)。

现在稍微改变一下 Lower 的代码:

package com.ds.test;

public class Lower extends Upper {

	String lowerString;
	
	public Lower() {
		super();
		System.out.println("Upper:  " + upperString);
		System.out.println("Lower:  " + lowerString);
	}
	
	public static void main(final String[] args) {
		new Lower();
	}
}

现在的输出是这样的:

Upper:  upperInited
Lower:  lowerInited

发现代码中的区别了吗?

是的,这个 lowerString 字段不再明确地设置为空。为什么这么做会有不同。不管怎样参考类型字段(例如这里的 String )的默认值不是为空的吗?当然是空的。事实证明,虽然这种微小的变化显然不会以任何方式改变代码行为,但是却让结果变的不同。

那么,到底发生了什么?当查看初始化顺序的时候一切就变的清晰了:

1)main() 函数调用了 Lower 构造器。

2)Lower 的一个实例被准备好了。意味着所有的字段都被创建并且填充了默认值,例如,引用类型的默认值为空,布尔类型的默认值为 false 。在这个时候,任何的对字段的内联赋值都没有发生。

3)父类构造器被调用了。这是被语言的特性所强制执行的。所以在其他任何事发生之前,Upper 的构造器被调用了。

4)Upper 这个构造器运行并且指定了一个引用,指向 Initializer.initialize() 方法新创建的的实例。

5)Initializer 类为两个字段( upperString 和 lowerString )附上新字符串。通过使用有点肮脏的 instanceof 实例检查做到为那两个字段赋值 – 这不是一个特别好的设计模式,但是也有可行的,不用管那么多。一旦发生了,upperString 和 lowerString 的引用都不再为空。

6)Initializer.initialize() 的调用完成,Upper 构造器也同样完成。

7)现在变得有趣了:Lower 实例的构造在继续。假设在 lowerString 字段的声明中没有明确地 =null 赋值,Lower 构造器恢复执行并且打印出两个连接到字段的字符串。

然而,如果有一个明确地赋值 null 的操作,执行流程会略有不同:当父类构造器完成后,在其余的构造器运行前,任何变量初始化都会执行(参见java语言规范12.5节)。在这种情况下,之前赋值给 lowerString 的字符串引用不会再一次被赋予 null 。然后继续执行其余的函数构造,现在打印 lowerString 的值为: null 。

这是一个很好的例子,不仅方便我们如何注意一些创建对象的细节(或者知道去哪里查看 Java 编码规范,打印的或者在线的),还显示了为什么像这样写初始化是很糟糕的。我们一点都不应该关心 Upper 的子类。相反的,如果因为一些原因对某些字段的初始化不能在子类本身被完成,它将只需要它自己的某些初始化帮助类的变体。在这种情况下,如果你使用 String lowString 或者 String lowerString = null 是真的没有任何区别的,它应该是什么就会是什么。

本文转载自:http://www.importnew.com/21832.html

群星纪元
粉丝 50
博文 456
码字总数 44497
作品 0
朝阳
高级程序员
私信 提问
加载中

评论(0)

Java类继承关系中的初始化顺序

Java类初始化的顺序经常让人犯迷糊,现在本文尝试着从JVM的角度,对Java非继承和继承关系中类的初始化顺序进行试验,尝试给出JVM角度的解释。 非继承关系中的初始化顺序 对于非继承关系,主类...

osc_dh0xu7zu
2018/01/07
9
0
java与C++变量初始化的对比

java尽力保证:所有变量在使用前都能得到恰当的初始化 ①函数/方法局部变量的初始化 在C/C++中,变量的初始化还是得依赖于程序员的自觉性。对于函数局部变量,编译器不会为基本类型赋予默认初...

good luck.
2017/03/16
0
0
JVM系列第7讲:JVM 类加载机制

当 Java 虚拟机将 Java 源码编译为字节码之后,虚拟机便可以将字节码读取进内存,从而进行解析、运行等整个过程,这个过程我们叫:Java 虚拟机的类加载机制。JVM 虚拟机执行 class 字节码的过...

陈树义
2018/11/20
0
0
Java的初始化块及执行过程详解

问题:Java对象初始化方式主要有哪几种?分别是什么? 针对上面的问题,想必大家脑海中首先浮现出的答案是构造器,没错,构造器是Java中常用的对象初始化方式。 还有一种与构造器作用非常相似...

osc_cw97bsoa
2019/09/16
4
0
【转】两道面试题,带你解析Java类加载机制(类初始化方法 和 对象初始化方法)

本文转自 https://www.cnblogs.com/chanshuyi/p/thejavaclassload_mechamism.html 关键语句 我们只知道有一个构造方法,但实际上Java代码编译成字节码之后,是没有构造方法的概念的,只有类初...

osc_mnd6q2ay
2019/03/24
4
0

没有更多内容

加载失败,请刷新页面

加载更多

如何用数据结构解释计算机系统 常用数据结构

详细:https://www.cnblogs.com/morui/p/10726864.html 数据结构(计算机存储、组织数据方式) 数据结构是计算机存储、组织数据的方式。数据结构是指相互之间存在一种或多种特定关系的数据元...

osc_rnx2cje5
29分钟前
23
0
黑客你咋这么牛掰,不屑用鼠标?

如需快速跳转,请戳以下蓝色字条 01 前情提要 02 有苦说得出 1、黑客开发绝大多数工具是没有图形化界面的 2、命令行更有助于批量操作 3、图形化界面消耗系统资源量大,增加计算机性能负担 4、...

osc_m6gaz63w
31分钟前
20
0
计算机网络TCP/IP模型复习笔记(随时补充)

看到一篇大佬的博客,刚好前段时间也有简单了解了一点计算机网络的TCP/IP,就顺便总结一下。 大佬文章链接: https://blog.csdn.net/ThinkWon/article/details/104903925 计算机网络的自己理...

osc_boqyoaed
32分钟前
17
0
IDEA使用技巧-->查看类的继承关系图

IDEA使用技巧-->查看类的继承关系图 简单实用(很实用) 转自 ☞https://www.cnblogs.com/deng-cc/p/6927447.html 最近忙,有用的直接拿来给大家分享,但凡分享的都是我亲测有效的!...

宇宝
33分钟前
21
0
浏览器同源政策及其规避方法

自己以思维导图的形式梳理了一遍 浏览器同源政策及其规避方法

酒窝yun过去了
34分钟前
12
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部