JAVA构造时成员初始化的陷阱
让我们先来看两个类: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);
}
}
原因分析:
- 陈皓博客
- Java Tutor - Visualize Java code execution to learn Java online (also visualize Python, Java, JavaScript, TypeScript, Ruby, C, and C++ code)
JAVA构造时成员初始化的陷阱的更多相关文章
- Java 构造时成员初始化的陷阱
1.首先列出代码 Base.java public class Base { Base() { preProcess(); } void preProcess() {} } Derived.java ...
- Java中的成员初始化顺序和内存分配过程
Java中的成员初始化顺序和内存分配过程 原帖是这样描述的: http://java.dzone.com/articles/java-object-initialization?utm_source= ...
- java类的成员初始化顺序和初始化块知识
java类的成员初始化顺序和初始化块知识 转自:http://blog.csdn.net/lgfeng218/article/details/7606735 属性.方法.构造方法和自由块都是类中的成员 ...
- Java类的成员初始化顺序
Java类的成员初始化顺序 2017-06-01 代码: public class InitializeSequence { public static void main(String[] args ...
- Java继承时的初始化顺序
Java程序在启动和运行时,需要首先完成初始化的工作.在涉及到继承.static成员变量等因素时,初始化的顺序就复杂起来.下面以一个例子说明继承时的Java初始化顺序. 例子: class Insec ...
- Java 类的成员初始化顺序
做个简单笔录,就当是重温下基础知识. 1.先看代码: package com.test; public class Test { public static void main(String[] ar ...
- java 编译时的初始化顺序
有的时候,java的初始化会对我的工作照成很大影响,所以简单介绍一下, 首先介绍简单的变量的初始化:在类的内部,变量定义的先后顺序决定了初始化的顺序,即使变量定义散布于方法定义之间,它也会先于构造器和 ...
- JAVA构造MAP并初始化MAP
第一种方法:static块初始化 public class Demo{ private static final Map<String, String> myMap; static { m ...
- Java类和对象初始化
类的生命周期: Java类的初始化: 本阶段负责为类变量赋正确的初始值.(类变量即静态变量) Java编译器把所有的类变量初始化语句和静态初始化器通通收集到<clinit>方法中,该方法只 ...
随机推荐
- EasyMesh - A Two-Dimensional Quality Mesh Generator
EasyMesh - A Two-Dimensional Quality Mesh Generator eryar@163.com Abstract. EasyMesh is developed by ...
- ExtJS 4.2 Grid组件的单元格合并
ExtJS 4.2 Grid组件本身并没有提供单元格合并功能,需要自己实现这个功能. 目录 1. 原理 2. 多列合并 3. 代码与在线演示 1. 原理 1.1 HTML代码分析 首先创建一个Grid ...
- 关于面试题 Array.indexof() 方法的实现及思考
这是我在面试大公司时碰到的一个笔试题,当时自己云里雾里的胡写了一番,回头也曾思考过,最终没实现也就不了了之了. 昨天看到有网友说面试中也碰到过这个问题,我就重新思考了这个问题的实现方法. 对于想进大公 ...
- virtualbox linux虚拟机相关
linux虚拟机设置为静态IP 在virtualbox中安装好linux虚拟机后,如果采用的是NAT方式的话,linux虚拟机默认采用dhcp方式自动上网,而且用的是NetworkManager服务而 ...
- Hawk 6. 编译和扩展开发
Hawk是开源项目,因此任何人都可以为其贡献代码.作者也非常欢迎使用者能够扩展出更有用的插件. 编译 编译需要Visual Stuido,版本建议使用2015, 2010及以上没有经过测试,但应该可以 ...
- Linux上如何查看物理CPU个数,核数,线程数
首先,看看什么是超线程概念 超线程技术就是利用特殊的硬件指令,把两个逻辑内核模拟成两个物理芯片,让单个处理器都能使用线程级并行计算,进而兼容多线程操作系统和软件,减少了CPU的闲置时间,提高的CPU的 ...
- canvas与html5实现视频截图功能
这段时间一直在研究canvas,突发奇想想做一个可以截屏视频的功能,然后把图片拉去做表情包,哈哈哈哈哈哈~~ 制作方法: 1.在页面中加载视频 在使用canvas制作这个截图功能时,首先必须保证页面上 ...
- 升级npm
查看npm的所有版本 运行命令: npm view npm versions 命令运行后,会输出到目前为止npm的所有版本. [ '1.1.25', '1.1.70', '1.1.71', '1.2. ...
- Android之三种网络请求解析数据(最佳案例)
AsyncTask解析数据 AsyncTask主要用来更新UI线程,比较耗时的操作可以在AsyncTask中使用. AsyncTask是个抽象类,使用时需要继承这个类,然后调用execute()方法. ...
- 安卓自定义组合控件--toolbar
最近在学习安卓APP的开发,用到了toolbar这个控件, 最开始使用时include layout这种方法,不过感觉封装性不好,就又改成了自定义组合控件的方式. 使用的工具为android stud ...