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>方法中,该方法只 ...
随机推荐
- ABP文档 - 本地化
文档目录 本节内容: 简介 应用语言 本地化源 XML文件 注册XML本地化源 JSOn文件 注册JSON本地化源 资源文件 自定义源 获取一个本地文本 在服务端 在MVc控制器里 在MVC视图里 在 ...
- SQLServer事务同步下如何收缩日志
事务同步是SQLServer做读写分离的一种常用的方式. 随着业务数据的不断增长,数据库积攒了大量的日志,为了腾出硬盘空间,需要对数据库日志进行清理 订阅数据库的日志清理 因为订阅数据库所有的数据都来 ...
- iOS开源项目周报0105
由OpenDigg 出品的iOS开源项目周报第四期来啦.我们的iOS开源周报集合了OpenDigg一周来新收录的优质的iOS开发方面的开源项目,方便iOS开发人员便捷的找到自己需要的项目工具等. He ...
- $.extend()的实现源码 --(源码学习1)
目标: $.extend({ add:function(a,b){ return a + b; } }) console.log($.a ...
- JavaScript的继承实现方式
1.使用call或apply方法,将父对象的构造函数绑定在子对象上 function A(){ this.name = 'json'; } function B(){ A.call(this); } ...
- 在Sublime Text 3上安装代码格式化插件CodeFormatter
1.了解CodeFormatter插件 在Sublime Text 3中编写代码,为了能让我们的代码格式变得漂亮整洁,需要一个能自动格式代码的插件.这里发现CodeFormatter插件不错,它能支持 ...
- 基于netty http协议栈的轻量级流程控制组件的实现
今儿个是冬至,所谓“冬大过年”,公司也应景五点钟就放大伙儿回家吃饺子喝羊肉汤了,而我本着极高的职业素养依然坚持留在公司(实则因为没饺子吃没羊肉汤喝,只能呆公司吃食堂……).趁着这一个多小时的时间,想跟 ...
- C++中的const
一,C++中const的基本知识 1.C++中const的基本概念 1.const是定义常量的关键字,表示只读,不可以修改. 2.const在定义常量的时候必须要初始化,否则报错,因为常量无法修改,只 ...
- 使用 JavaScript 和 canvas 做精确的像素碰撞检测
原文地址:Pixel accurate collision detection with Javascript and Canvas 译者:nzbin 我正在开发一个需要再次使用碰撞检测的游戏.我通常 ...
- mybatis plugins实现项目【全局】读写分离
在之前的文章中讲述过数据库主从同步和通过注解来为部分方法切换数据源实现读写分离 注解实现读写分离: http://www.cnblogs.com/xiaochangwei/p/4961807.html ...