`
jackyhongvip
  • 浏览: 159650 次
  • 性别: Icon_minigender_1
  • 来自: 北京
社区版块
存档分类
最新评论

Java Object Initialization Order - Know your JLS!

    博客分类:
  • j2se
 
阅读更多

转自:http://www.danielschneller.com/2010/07/java-object-initialization-order-know.html

 

Recently I came across an interesting problem whose solution eluded me at first glance. Consider these three classes:

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";
 }
}

What output is to be expected from running the Lower class?

In this very reduced example it is much easier to get a view of the whole situation - in reality where this occurred there was a lot more code to distract one's attention...
Anyway, this is what the output looks like:

Upper:  upperInited
Lower:  null;

While the little example uses Strings, the real code of Initializer had a delegate object registered with the equivalent of the Lower class - at least that was the intention. For some reason however did this not work when running the application. Instead, the default path was taken - the one for the delegate object being not set (null).
Now, change the code of Lower slightly:

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();
 }
}

The output is now:

Upper:  upperInited
Lower:  lowerInited

Notice the difference in the code?
Yes, the lowerString field is no longer explicitly set to null. Why would this make a difference? Isn't the default value for reference type fields (such as String here) null anyway? Of course, it is. However it turns out that this tiny little change - which apparently would not change the code's behavior in any way - makes this thing fly or not fly.
So what is going on? It becomes clear when looking at the initialization order:

  1. main() calls the Lower constructor.
  2. An instance of Lower is prepared. That means, all fields are created and populated with default values, i. e. null for reference types, false for booleans and so on. At this time, any inline assignments to the fields have not taken place!
  3. The super-constructor is called. This is mandated by the language spec. So, before anything else happens, Upper's constructor is called.
  4. The Upper constructor runs and hands a reference to the freshly created instance to the Initializer.initialize() method.
  5. The Initializer attaches new Strings to both fields. It does so by using a somewhat dirty instanceof check - not a particularly good design pattern, but possible, nevertheless. Once that has happened, both the upperString lowerString references are no longer null.
  6. The Initializer.initialize() call finishes, as does the Upper constructor.
  7. Now it becomes interesting: Construction of the Lower instance continues. Assuming there is no explicit =null assignment in the lowerString field declaration, the Lower constructor resumes execution and prints out the two Strings that are attached to the fields.
    However, if there is an explicit assignment to null, execution has a slightly different flow: Just after the super constructor is done, any variable initializers are executed (see section 12.5 of the Java Language Spec), before the rest of the constructor is run. In this case the String reference that was previously assigned to lowerString is now overwritten with null again! Only then does the rest of the constructor continue execution, now printing lowerString: null.

Apart from being a nice example for why it is handy to be aware of some of the minutiae of object creation (or knowing where to look in the JLS, printed or online) this shows why it is a bad idea to write the Initializer like this. It should not be aware of Upper's subclasses at all! Instead, if for some reason initialization of certain fields cannot be done in the Lower class itself, it will just require its own variant of some sort of initialization helper. In that case, it would really make no difference if you used String lowerString; or String lowerString = null; - just as it should be.

分享到:
评论

相关推荐

    Library Initialization Failed(解决方案).md

    项目中碰到的问题

    Java - The Well-Grounded Java Developer

    ### Java - The Well-Grounded Java Developer #### PART 1: DEVELOPING WITH JAVA 7 **1. Introducing Java 7** - **Overview**: This section provides a comprehensive introduction to the new features and ...

    提示Initialization failure-0x0000000c错误无法上网怎么办.docx

    "解决 Initialization failure: 0x0000000c 错误无法上网的多种方法" 在本文中,我们将讨论 Initialization failure: 0x0000000c 错误的多种解决方法,这个错误通常会导致无法上网的情况。本文将从问题的根源开始,...

    java设计模式----单例模式

    在Java编程语言中,设计模式是一种经过验证的解决常见软件设计问题的最佳实践。单例模式是其中最常用的一种,它的核心思想是确保一个类只有一个实例,并提供全局访问点。单例模式的应用场景包括:控制资源的访问、...

    PCI_system-address-map-initialization

    在计算机硬件领域,PCI(Peripheral Component Interconnect)系统地址映射初始化是一个至关重要的步骤,它涉及到BIOS(基本输入输出系统)在启动过程中如何管理和分配系统内存资源给PCI设备。本文将深入探讨PCI设备...

    ruby-oo-fundamentals-object-initialization-lab

    对象初始化实验室 目标 用自定义的初始化例程定义一个类。 从初始化设置实例变量属性。 为初始化参数包括默认参数。 概述 您将要构建一个Person类,该类在初始化一个人时接受一个人的名字。 您还将要构建一个Dog类...

    Java虚拟机----类的加载过程.docx

    Java虚拟机(JVM)的类加载过程是Java程序运行的基础,它涉及到类加载器、类的生命周期和一系列复杂的步骤。在这个过程中,类加载器主要任务是根据类的全限定名加载二进制字节流并转化为`java.lang.Class`对象。整个...

    Console Initialization script-开源

    标题中的"Console Initialization script-开源"指的是一个专用于Linux系统的脚本,它的主要功能是对文本模式的控制台进行初始化设置。这个脚本被称为"SetConsole",它在系统启动时运行,确保控制台具备合适的配置,...

    SubarnaTripathi-Tracker_Initialization-

    【标题】"SubarnaTripathi-Tracker_Initialization-" 暗示了这是一个与追踪算法初始化相关的项目,可能是一个研究或教程,由Subarna Tripathi主导。在计算机视觉和机器学习领域,追踪器初始化是目标追踪过程中的关键...

    06-Java基础(数组-内存图解)

    Java基础是学习任何Java开发者的基石,而数组作为Java中最基本的数据结构,是理解内存管理的关键。本节我们将深入探讨“Java基础中的数组与内存图解”,了解数组在内存中的存储方式及其工作原理。 首先,数组是Java...

    Object- Oriented Programming with Ansi-C

    automatic initialization to prevent another class of bugs. Chapter ten introduces delegates and shows how classes and callback functions cooperate to simplify, for example, the constant chore of ...

    Infineon-XMC1000-C_Start_and_Device_Initialization-AN-v01_00-EN启动文件说明.pdf

    文档《Infineon-XMC1000-C_Start_and_Device_Initialization-AN-v01_00-EN启动文件说明.pdf》详细介绍了在DAVE开发环境中,如何进行XMC1000系列微控制器的启动文件配置与设备初始化。下面将围绕文档内容,展开对于...

    Platform Initialization SCT-开源

    平台初始化自我认证测试(Platform Initialization Self Certification Test,简称pi-sct)是一个开源项目,它为IT专业人士提供了一个工具,用于测试和验证平台的初始化过程是否符合UEFI(统一可扩展固件接口)标准...

    基于Java的实例源码-各种EJB之间的调用示例.zip

    Java企业版(Enterprise JavaBeans,EJB)是Java平台中用于构建可扩展、安全和事务处理的服务器端应用程序的关键技术。这个"基于Java的实例源码-各种EJB之间的调用示例.zip"压缩包提供了关于如何在Java环境中实现EJB...

    java object create process

    在`Cupboard.java`、`StaticInitialization.java`、`Table.java`和`Bowl.java`这些文件中,我们可以看到不同类的定义,如`Cupboard`、`StaticInitialization`、`Table`和`Bowl`。 2. **实例化(Instantiation)**:...

    Array-Initialization-.zip_LabVIEW 数组

    "Array-Initialization-.zip" 文件可能是一个教学资源,专为帮助用户掌握在LabVIEW中如何初始化和操作数组而设计。在这个实验室练习中,"Array Initialization .vi" 可能是一个虚拟仪器(VI)示例,演示了数组的创建...

    Java程序员面试宝典-Java代码查错.doc

    Java编程语言中的错误和最佳实践在面试中是常见的考察点,尤其对于Java程序员而言,理解并掌握这些知识点至关重要。以下是一些从提供的文档内容中提取的关键知识点及其详细解释: 1. **抽象方法(Abstract Methods...

    java面试题大全-代码与编程问题

    Java面试中的代码与编程问题涵盖了广泛的Java编程概念,包括设计模式、类的初始化以及内部类的使用。以下是对这些问题的详细解释: 1. **Singleton模式**:Singleton模式是一种设计模式,确保一个类只有一个实例,...

    Linux iSCSI boot initialization program-开源

    Linux iSCSI Boot Initialization Program,通常被称为iSCSI-init,是一种开源软件,专门设计用于Linux操作系统,以实现通过网络启动(Network Booting)系统。它允许计算机通过Internet SCSI(iSCSI)协议从远程...

Global site tag (gtag.js) - Google Analytics