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
[前面的话] 算是真正的放松了好几天时间,没有看任何书,没有任何任务,今天是过完年后的第一天上班时间,我又开始了我的学习之路,感觉还没有老,怎么心态越来越平静了,进入工作状态,就好好努力工作,新的一年 ...
随机推荐
- Python+Selenium webdriver Api
# -*- coding: utf-8 -*- from selenium import webdriver browser = webdriver.Firefox() #browser.set_wi ...
- Ubuntu使用之Svn命令小技巧
注: [svn Path]:是指要代替码分支的server绝对路径 [Path]:是指终端相对当前文件夹的相对路径.假设是在当前文件夹下,就省略路径 ①.取svnserver的代码: svn co [ ...
- iOS 获取导航栏和状态栏的高度
CGRect rect = [[UIApplication sharedApplication] statusBarFrame]; 状态栏的高度: float status height = rec ...
- LeetCode OJ 之 Ugly Number II (丑数-二)
题目: Write a program to find the n-th ugly number. Ugly numbers are positive numbers whose prime fact ...
- 剑指offer面试题14-调整数组顺序使奇数位于偶数前面
题目: 输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得全部奇数位于数组的前半部分.全部偶数位于数组的后半部分. 前后分的这个.,让我想起来高速排序.好吧,就用这个做. 考虑到了排序的可扩 ...
- JAVA入门[14]-Spring MVC AOP
一.基本概念 1.AOP简介 DI能够让相互协作的软件组件保持松散耦合:而面向切面编程(aspect-oriented programming,AOP)允许你把遍布应用各处的功能分离出来形成可重用的组 ...
- CI环境配置
CI:php的MVC框架M(模型model):与数据库打交道的,一般情况下数据库里面的一张表对应一个Model,在里面对应该表的增删改查的操作V(视图view):用户看到的界面,其中很多数据是从数据库 ...
- 在java项目中加入百度富文本编辑器
富文本编辑器在项目中很常见,他可以将文本,图片等信息存入数据库,在编辑一些图文混排的信息的时候很有用,比如商城项目的商品详情页,包含很多带有样式的文字和图片. 此前一直使用的百度的富文本编辑器uedi ...
- Caused by: org.apache.ibatis.exceptions.TooManyResultsException: Expected one result (or null) to be returned by selectOne(), but found: 2
异常信息 Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with na ...
- Chef 自动化运维:初探 cookbook
cookbook 概述 Chef 意为"厨房",我们要做"菜",自然需要有"菜谱".事实上在 Chef 中分发到各服务器节点的不是" ...