Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序
当创建一个对象时,各种成员变量及构造方法的初始化或调用顺序是怎样的呢?
(1).如果类尚未加载,则先初始化静态成员变量和静态代码块,再初始化成员变量,最后调用相应的构造方法;
(2).如果类已经加载过了,则静态成员变量已经初始过了,静态代码块也已执行,这时只需初始化成员变量,再调用构造方法就可以了;
(3).如果类还有父类,则按(1)或(2)的顺序先初始化父类,再初始化子类。
下面以例子详细说明。
包human中定义了四个类,分别为Person、Student、DustMan、TestMain;其中,Student是Person的子类。
Person类的代码如下:
package human;
public class Person {
String name;
String gender;
//test:成员变量的初始化是否在构造方法调用之前 2017.11.01
public Person() {
System.out.println("Person constructor:Person()");
}
DustMan dustTest = new DustMan();
static {
System.out.println("Person:initialization of static code block");
}
static String citizenship = "Chinese"; //test:静态成员变量与静态代码块的初始化顺序 2017.11.01
//test:子类用super显式调用父类构造方法时,各变量及构造方法初始化或调用顺序 2017.11.01
public Person(String n, String g) {
this.name = n;
this.gender = g;
System.out.println("Person constructor:Person(n,g)");
}
}
Student类的代码如下:
package human;
public class Student extends Person {
String stuNumber;
int score;
static String testIni = "test";
static {
System.out.println("Student:testIni = " + testIni);
}
//test:成员变量的初始化是否在构造方法调用之前 2017.11.01
public Student() {
System.out.println("Student constructor:Student()");
}
//test:子类用super显式调用父类构造方法时,各变量及构造方法初始化或调用顺序 2017.11.01
public Student(String n, String g) {
super(n,g);
System.out.println("Student constructor:Student(n,g)");
}
}
DustMan类的代码如下:
package human;
public class DustMan {
public DustMan() {
System.out.println("DustMan constructor");
System.out.println("change value of the static variable citizenship " + "\"" + Person.citizenship + "\"");
Person.citizenship = "US";
System.out.println(" to " + "\"" + Person.citizenship + "\"");
}
}
TestMain类的代码如下:
package human;
public class TestMain {
public static void main(String[] args) {
Student stuTest = new Student();
Student stuTest2 = new Student("liu","female");
System.out.println("citizenship = " + Person.citizenship);
}
在TestMain类中执行,输出结果如下:
Person:initialization of static code block
Student:testIni = test
DustMan constructor
change value of the static variable citizenship "Chinese"
to "US"
Person constructor:Person()
Student constructor:Student()
DustMan constructor
change value of the static variable citizenship "US"
to "US"
Person constructor:Person(n,g)
Student constructor:Student(n,g)
citizenship = US
下面对输出结果进行分析:
(1).执行第一条语句,创建对象stuTest,Student stuTest = new Student();
<1>.输出的第1行:Person:initialization of static code block
可以看出,虽然创建的是Student类对象,但先加载的是父类,加载时执行Person类的静态代码块,有第一行输出。
<2>.输出的第2行:Student:testIni = test
加载过父类后,并没有接着初始父类的成员变量及调用构造方法,而是接着加载了子类Student,加载时执行Student的静态代码块,有第二行输出。
<3>.输出的第3行:DustMan constructor
Person类和Student类都加载后,开始初始化Person类的成员变量,有一个变量是DustMan类型的,即DustMan dustTest = new DustMan();dustTest的定义虽然在无参构造方法的后面,但根据输出结果看,先初始化的对象dustTest,后调用的构造方法,也就是说成员变量的初始化在构造方法的调用之前。
<4>,输出的第4行和第5行:change value of the static variable citizenship "Chinese"
to "US"
可以看出,在Person的构造方法调用之前,静态成员变量citizenship已经被初始为“Chinese”了,在DustMan的构造方法中又被修改为“US”。
<5>.输出的第6行:Person constructor:Person()
Person类的成员变量初始化完成后,接着调用构造方法Person()。
<6>.输出的第7行:Student constructor:Student()
Person类构造方法调用后,接着初始化子类成员变量,并调用构造方法。
(2).第一条语句已经执行完,接着执行第二条语句Student stuTest2 = new Student("liu","female");
<7>.输出的第8行:DustMan constructor
很明显,创建第二个Student对象stuTest2时,父类和子类的静态代码块都没有再执行,直接初始化成员变量。
<8>输出的第9行和第10行:change value of the static variable citizenship "US"
to "US"
citizenship的值由第<4>步改为“US”后就没有发生变化,说明静态成员变量也没有再次初始化为"Chinese"。
<9>.输出的第11行:Person constructor:Person(n,g)
父类的成员变量初始化后,接着调用构造方法,这次调用的不是无参构造方法,而是Person(n,g);Student的构造方法Student(n,g)里用super(n,g)显式的调用了父类的构造方法,说明要调用父类哪个构造方法是由子类的构造方法决定的。
<10>.输出的第12行:Student constructor:Student(n,g)
父类构造方法调用后,接着初始化子类成员变量,并调用子类构造方法。
<11>.输出的第13行:citizenship = US
再次确认citizenship的值没有重新初始化。
(3).在Person的静态代码块中添加一行System.out.println("citizenship = " + citizenship);,如下所示:
static {
System.out.println("Person:initialization of static code block");
System.out.println("citizenship = " + citizenship);
}
static String citizenship = "Chinese"; //test:静态成员变量与静态代码块的初始化顺序 2017.11.01
出现Cannot reference a field before it is defined的错误,说明静态代码块的执行和静态成员变量的初始化是按定义的顺序执行的。
总结:
(1).首次使用类时,先加载类,加载时初始类的静态成员变量,执行静态代码块;
静态成员变量和静态代码块的顺序按定义的顺序来;
静态成员变量和静态代码块都只在类加载时初始化或执行一次。
(2).如果有父类,则先加载父类,再加载子类。
(3).new一个对象时,父类子类都加载后,先初始化父类的成员变量,再调用父类的构造方法;
调用父类的哪个构造方法要看new时调用的子类的哪个构造方法,看子类的这个构造方法是如何使用super(参数),执行与super的参数一致的父类构造方法。
(4).父类调用过构造方法后,再初始化子类成员变量,再调用子类的构造方法。
Java学习笔记11---静态成员变量、静态代码块、成员变量及构造方法的初始化或调用顺序的更多相关文章
- java 对象的初始化流程(静态成员、静态代码块、普通代码块、构造方法)
一.java对象初始化过程 第一步,加载该类,一个java对象在初始化前会进行类加载,在JVM中生成Class对象.加载一个类会进行如下操作,下面给出递归描述.(关于Class对象详见反射 点击这里) ...
- java 子类、父类中静态代码块、字段,非静态代码块、字段以及构造函数的初始化顺序和次数
一个类中的数据初始化顺序是面试官非常喜欢出的面试题之一,本文用一个实例来介绍java中子类.父类中静态代码块.字段,非静态代码块.字段以及构造函数的执行顺序和次数. 一.包结构
- 0013 Java学习笔记-面向对象-static、静态变量、静态方法、静态块、单例类
static可以修饰哪些成员 成员变量---可以修饰 构造方法---不可以 方法---可以修饰 初始化块---可以修饰 内部类(包括接口.枚举)---可以修饰 总的来说:静态成员不能访问非静态成员 静 ...
- java 静态变量 静态代码块 加载顺序问题
在网上看了一个这样的题目 public class StaticTest { public static void main(String[] args) { staticFunction(); } ...
- Android(java)学习笔记188:关于构造代码块,构造函数的一道面试题(华为面试题)
1.源码是: package text; public class TestStaticCon { public static int a = 0; static { a = 10; System.o ...
- Android(java)学习笔记131:关于构造代码块,构造函数的一道面试题(华为面试题)
1. 代码实例: package text; public class TestStaticCon { public static int a = 0; static { a = 10; System ...
- java新手笔记11 类的静态属性、方法(单例)
1.Person类 package com.yfs.javase; public class Person { String name;//每个对象上分配 与对象绑定 int age; char se ...
- Java类的装载过程和静态代码块
在Java中,类装载器把一个类装入Java虚拟机中,要经过三个步骤来完成:装载.连接和初始化,其中连接又可以分成校验.准备和解析三步,除了解析外,其它步骤是严格按照顺序完成的,各个步骤的主要工作如下: ...
- Java学习笔记(三)——静态导入,package-info,Fall-through
[前面的话] 算是真正的放松了好几天时间,没有看任何书,没有任何任务,今天是过完年后的第一天上班时间,我又开始了我的学习之路,感觉还没有老,怎么心态越来越平静了,进入工作状态,就好好努力工作,新的一年 ...
随机推荐
- 【Struts2的执行流程,这个博主写的很详细】
http://blog.csdn.net/wjw0130/article/details/46371847
- Libcurl的编译_HTTP/HTTPSclient源代码演示样例
HTTP/HTTPSclient源代码演示样例 环境: zlib-1.2.8 openssl-1.0.1g curl-7.36 Author: Kagula LastUpdateDate: 2 ...
- Android中相机和相冊使用分析
Android中相机和相冊使用分析 欢迎转载,但请尊重原创(文章来自不易,转载请标明转载出处,谢谢) 在手机应用程序中,使用自带的相机拍照以及相冊选择喜欢的图片是最常见只是的用户需求,那么怎么合理使用 ...
- macox下编译snappy静态库
源代码地址:https://github.com/google/snappy 下载 git clone https://github.com/google/snappy 编译 进入snappy源代码文 ...
- 一道题Wrong Answer之后该何去何从?
写程序手不稳是个大毛病,往往会让一份能AC的代码变成99.995%正确,失之毫厘谬以千里,近期十场个人赛非常少有能一次AC的经历,细致想想除了根本逻辑上的错误.大概都是跪在这些细节上: 1.输出格式, ...
- libmemcached的安装及測试
1.安装memcached ~$ wget http://memcached.googlecode.com/files/memcached-1.2.8.tar.gz. $ tar xvzf lmemc ...
- canvas图形函数
function drawStar(cobj,x, y, radius1, radius2, num, drawType, color) {//参数:画笔,圆心X.圆心Y,半径1,半径2,形状边,实心 ...
- 在Docker中运行asp.net core 跨平台应用程序
概述 Docker已经热了有一两年了,而且我相信这不是一个昙花一现的技术,而是一个将深远影响我们日后开发和部署.运营应用系统的一种创新(很多人将其作为devops的一种非常重要的基石).学习docke ...
- 对jbox2d引擎的一些回顾与思考(swing实现demo)
JBox2d回顾与思考 jbox2d 是 box2d 的java移植,感觉国内网络上针对jbox2d的教程还比较少(通常是box2d).回顾一下这几天的学习历程顺便写下博主的所思所想. swing实现 ...
- MFC学习之CWinApp类
CWinApp是一个基类,你通过它来继承Windows应用程序对象.应用程序对象为你提供了初始化应用程序(以及它的每一个实例 和运行应用程序所需的成员函数.它实现主事件循环并把事件分发给MFC中其他类 ...