让我们先来看两个类:Base和Derived类。注意其中的whenAmISet成员变量,和方法preProcess()。

情景1:(子类无构造方法)

class Base {
Base() {
preProcess();
} void preProcess() {
}
} class Derived extends Base {
public String whenAmISet = "set when declared"; void preProcess() {
whenAmISet = "set in preProcess()";
}
} public class StaticTest {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.whenAmISet);
}
}

当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

class Base {
Base() {
preProcess();
} void preProcess() {
}
} class Derived extends Base {
public String whenAmISet; {whenAmISet = "set when declared";} void preProcess() {
whenAmISet = "set in preProcess()";
}
} public class StaticTest {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.whenAmISet);
}
}

输出结果是: set when declared

情景2:(子类添加了构造方法)

class Base {
Base() {
preProcess();
} void preProcess() {
}
} class Derived extends Base {
public String whenAmISet = "set when declared"; public Derived() {
whenAmISet = "set in constructor";
} void preProcess() {
whenAmISet = "set in preProcess()";
}
} public class StaticTest {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.whenAmISet);
}
}

当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

class Base {
Base() {
preProcess();
} void preProcess() {
}
} class Derived extends Base {
public String whenAmISet; public Derived() {
whenAmISet = "set when declared";
whenAmISet = "set in constructor";
} void preProcess() {
whenAmISet = "set in preProcess()";
}
} public class StaticTest {
public static void main(String[] args) {
Derived d = new Derived();
System.out.println(d.whenAmISet);
}
}

输出结果为:set in constructor

情景3:(赋值的细节)

public class Singleton {

    private static Singleton mInstance = new Singleton();  // 位置1
public static int counter1;
public static int counter2 = 0; private Singleton() {
counter1++;
counter2++;
} public static Singleton getInstantce() {
return mInstance;
} public static void main(String[] args) {
Singleton singleton = Singleton.getInstantce();
System.out.println("counter1: " + singleton.counter1);
System.out.println("counter2: " + singleton.counter2);
}
}

当.java源代码转换成一个.class文件后,其转换成类似下面的等价代码:

public class Singleton {

    private static Singleton mInstance;
public static int counter1;
public static int counter2; static {
mInstance = new Singleton();
counter2 = 0;
} private Singleton() {
counter1++;
counter2++;
} public static Singleton getInstantce() {
return mInstance;
} public static void main(String[] args) {
Singleton singleton = Singleton.getInstantce();
System.out.println("counter1: " + singleton.counter1);
System.out.println("counter2: " + singleton.counter2);
}
}
  • 在Prepare阶段,mInstance、counter1、counter2的初始值为(null,0,0);
  • 执行至 mInstance = new Singleton()时,进行实例创建并调用构造方法,使counter1、counter2变量的值改变为(1,1);
  • 执行counter2 = 0时,counter2的值再次置为0,最终程序的输出结果为:counter1: 1   counter2: 0

同理,以下代码的最终输出结果为:counter1: 1  counter2: 1

public class Singleton {

    public static int counter1;
public static int counter2 = 0;
private static Singleton mInstance = new Singleton(); // 位置2 private Singleton() {
counter1++;
counter2++;
} public static Singleton getInstantce() {
return mInstance;
} public static void main(String[] args) { Singleton singleton = Singleton.getInstantce();
System.out.println("counter1: " + singleton.counter1);
System.out.println("counter2: " + singleton.counter2);
}
}

原因分析:

  1. 陈皓博客
  2. Java Tutor - Visualize Java code execution to learn Java online (also visualize PythonJavaJavaScriptTypeScriptRubyC, and C++ code)

JAVA构造时成员初始化的陷阱的更多相关文章

  1. Java 构造时成员初始化的陷阱

    1.首先列出代码 Base.java public class Base { Base() { preProcess(); } void preProcess() {} } Derived.java ...

  2. Java中的成员初始化顺序和内存分配过程

    Java中的成员初始化顺序和内存分配过程 原帖是这样描述的: http://java.dzone.com/articles/java-object-initialization?utm_source= ...

  3. java类的成员初始化顺序和初始化块知识

    java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...

  4. Java类的成员初始化顺序

    Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...

  5. Java继承时的初始化顺序

    Java程序在启动和运行时,需要首先完成初始化的工作.在涉及到继承.static成员变量等因素时,初始化的顺序就复杂起来.下面以一个例子说明继承时的Java初始化顺序. 例子: class Insec ...

  6. Java 类的成员初始化顺序

    做个简单笔录,就当是重温下基础知识. 1.先看代码: package com.test; public class Test { public static void main(String[] ar ...

  7. java 编译时的初始化顺序

    有的时候,java的初始化会对我的工作照成很大影响,所以简单介绍一下, 首先介绍简单的变量的初始化:在类的内部,变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,它也会先于构造器和 ...

  8. JAVA构造MAP并初始化MAP

    第一种方法:static块初始化 public class Demo{ private static final Map<String, String> myMap; static { m ...

  9. Java类和对象初始化

    类的生命周期: Java类的初始化: 本阶段负责为类变量赋正确的初始值.(类变量即静态变量) Java编译器把所有的类变量初始化语句和静态初始化器通通收集到<clinit>方法中,该方法只 ...

随机推荐

  1. 故障重现, JAVA进程内存不够时突然挂掉模拟

    背景,服务器上的一个JAVA服务进程突然挂掉,查看产生了崩溃日志,如下: # Set larger code cache with -XX:ReservedCodeCacheSize= # This ...

  2. UE4新手之编程指南

    虚幻引擎4为程序员提供了两套工具集,可共同使用来加速开发的工作流程. 新的游戏类.Slate和Canvas用户接口元素以及编辑器功能可以使用C++语言来编写,并且在使用Visual Studio 或 ...

  3. ASP.NET Core应用的错误处理[2]:DeveloperExceptionPageMiddleware中间件如何呈现“开发者异常页面”

    在<ASP.NET Core应用的错误处理[1]:三种呈现错误页面的方式>中,我们通过几个简单的实例演示了如何呈现一个错误页面,这些错误页面的呈现分别由三个对应的中间件来完成,接下来我们将 ...

  4. Linux安装LAMP开发环境及配置文件管理

    Linux主要分为两大系发行版,分别是RedHat和Debian,lamp环境的安装和配置也会有所不同,所以分别以CentOS 7.1和Ubuntu 14.04做为主机(L) Linux下安装软件,最 ...

  5. 简单有效的kmp算法

    以前看过kmp算法,当时接触后总感觉好深奥啊,抱着数据结构的数啃了一中午,最终才大致看懂,后来提起kmp也只剩下“奥,它是做模式匹配的”这点干货.最近有空,翻出来算法导论看看,原来就是这么简单(先不说 ...

  6. 关于Visual Studio 未能加载各种Package包的解决方案

    问题: 打开Visual Studio 的时候,总提示未能加载相应的Package包,有时候还无法打开项目,各种提示 解决方案: 进入用户目录 C:\Users\用户名\AppData\Local\M ...

  7. CSS知识总结(八)

    CSS常用样式 8.变形样式 改变元素的大小,透明,旋转角度,扭曲度等. transform : none | <transform-function> <transform-fun ...

  8. Tomcat启动报错org.springframework.web.context.ContextLoaderListener类配置错误——SHH框架

    SHH框架工程,Tomcat启动报错org.springframework.web.context.ContextLoaderListener类配置错误 1.查看配置文件web.xml中是否配置.or ...

  9. 解决Ubuntu Kylin 1610安装ANSYS17.2的NVIDIA显卡驱动问题

    Ubuntu Kylin 1610在安装完毕后,会自动安装显卡驱动,对于一般的图形图像使用来说自然不会有太大的问题,但是对于ANSYS17.2的一些模块,还是会出现问题.一个比较常见的问题就是Open ...

  10. 一点公益商城开发系统模式Ring Buffer+

    一个队列如果只生产不消费肯定不行的,那么如何及时消费Ring Buffer的数据呢?简单的方案就是当Ring Buffer"写满"的时候一次性将数据"消费"掉. ...