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>方法中,该方法只 ...
随机推荐
- js实现前端分页页码管理
用JS实现前端分页页码管理,可以很美观的区分页码显示(这也是参考大多数网站的分页页码展示),能够有很好的用户体验,这也是有业务需要就写了一下,还是新手,经验不足,欢迎指出批评! 首先先看效果图: 这是 ...
- python通过protobuf实现rpc
由于项目组现在用的rpc是基于google protobuf rpc协议实现的,所以花了点时间了解下protobuf rpc.rpc对于做分布式系统的人来说肯定不陌生,对于rpc不了解的童鞋可以自行g ...
- IOS FMDB 获取数据库表和表中的数据
ios开发中,经常会用到数据库sqlite的知识,除了增,删,改,查之外,我们说说如何获取数据库中有多少表和表相关的内容. 前言 跟数据库使用相关的一般的增删改查的语句,这里就不做解释了.在网上有很多 ...
- Java 程序优化 (读书笔记)
--From : JAVA程序性能优化 (葛一鸣,清华大学出版社,2012/10第一版) 1. java性能调优概述 1.1 性能概述 程序性能: 执行速度,内存分配,启动时间, 负载承受能力. 性能 ...
- css选择器
常用css选择器,希望对大家有所帮助,不喜勿喷. 1.*:通用选择器 * { margin: 0; padding: 0; } 选择页面上的全部元素,通常用于清除浏览器默认样式,不推荐使用. 2.#i ...
- Android Socket连接PC出错问题及解决
最近测试问题:Android 通过Socket链接电脑,ip和端口都是正确的,也在同一网段,可android端就是报异常如下: 解决办法:测试电脑的防火墙可能开着,在控制面板把防火墙打开即可.
- NSURLSession详解
导语 现在NSURLConnection在开发中会使用的越来越少,iOS9已经将NSURLConnection废弃,现在最低版本一般适配iOS7,所以也可以使用. NSURLConnection相对于 ...
- C#事件-使用事件需要的步骤
事件是C#中另一高级概念,使用方法和委托相关.奥运会参加百米的田径运动员听到枪声,比赛立即进行.其中枪声是事件,而运动员比赛就是这个事件发生后的动作.不参加该项比赛的人对枪声没有反应. 从程序员的角度 ...
- MySQL常用命令
数据库登陆命令: mysql -uroot -p 2.提示输入密码: 3.登陆成功: 4.数据库修改相关命令: 修改数据库的编码格式: 语法格式为:ALTER {DATABASE|SCHEMA} [ ...
- 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 ...