让我们先来看两个类: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. js实现前端分页页码管理

    用JS实现前端分页页码管理,可以很美观的区分页码显示(这也是参考大多数网站的分页页码展示),能够有很好的用户体验,这也是有业务需要就写了一下,还是新手,经验不足,欢迎指出批评! 首先先看效果图: 这是 ...

  2. python通过protobuf实现rpc

    由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...

  3. IOS FMDB 获取数据库表和表中的数据

    ios开发中,经常会用到数据库sqlite的知识,除了增,删,改,查之外,我们说说如何获取数据库中有多少表和表相关的内容. 前言 跟数据库使用相关的一般的增删改查的语句,这里就不做解释了.在网上有很多 ...

  4. Java 程序优化 (读书笔记)

    --From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10第一版) 1. java性能调优概述 1.1 性能概述 程序性能: 执行速度,内存分配,启动时间, 负载承受能力. 性能 ...

  5. css选择器

    常用css选择器,希望对大家有所帮助,不喜勿喷. 1.*:通用选择器 * { margin: 0; padding: 0; } 选择页面上的全部元素,通常用于清除浏览器默认样式,不推荐使用. 2.#i ...

  6. Android Socket连接PC出错问题及解决

    最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.

  7. NSURLSession详解

    导语 现在NSURLConnection在开发中会使用的越来越少,iOS9已经将NSURLConnection废弃,现在最低版本一般适配iOS7,所以也可以使用. NSURLConnection相对于 ...

  8. C#事件-使用事件需要的步骤

    事件是C#中另一高级概念,使用方法和委托相关.奥运会参加百米的田径运动员听到枪声,比赛立即进行.其中枪声是事件,而运动员比赛就是这个事件发生后的动作.不参加该项比赛的人对枪声没有反应. 从程序员的角度 ...

  9. MySQL常用命令

    数据库登陆命令: mysql -uroot -p 2.提示输入密码: 3.登陆成功: 4.数据库修改相关命令: 修改数据库的编码格式: 语法格式为:ALTER {DATABASE|SCHEMA}  [ ...

  10. mysql删除重复记录语句的方法

    例如: id name value 1 a pp 2 a pp 3 b iii 4 b pp 5 b pp 6 c pp 7 c pp 8 c iii id是主键 要求得到这样的结果 id name ...