初始化顺序
初始化顺序
静态初始化
主动使用会导致类的初始化,其超类均将在该类的初始化之前被初始化,但通过子类访问父类的静态字段或方法时,对于子类
- 无论直接通过
new 创建出来的,还是通过反射、克隆、序列化创建的) 创建某个类新的实例 - 使用某个类的静态方法
- 访问某个类或接口的静态字段
- 调用
JavaAPI 中的某些反射方法 - 初始化某个类的子类
( 要求其祖先类都要被初始化,否则无法正确访问其继承的成员) - 启动某个标明为启动类的类
( 含有main() 方法)
下面我们用例子来阐述下类初始化的流程
public class GrandPa {
static {
System.out.println("祖父静态初始化");
}
}
public class Parent extends GrandPa {
static String language = "Chinese";
static {
System.out.println("父类静态初始化");
}
{
System.out.println("父类实例初始化");
}
Parent() {
System.out.println("父类构造函数");
}
}
public class Child extends Parent {
static {
System.out.println("子类静态初始化");
}
{
System.out.println("子类实例初始化");
}
Child() {
System.out.println("子类构造函数");
}
public static void main(String args[]) {
Child child = new Child();
}
}
public class PassiveAccessTest {
public static void main(String[] args) {
System.out.println(Child.language);
}
}
//输出结果
/*
祖父静态初始化
父类静态初始化
Chinese
*/
而如果我们在Child
类中访问本类继承自父类的静态变量,会得到如下顺序
祖父静态初始化
父类静态初始化
子类静态初始化
Chinese
实例初始化
类的初始化会从祖先类到子类、按出现顺序,对类变量的初始化语句、静态初始化语句块依次进行初始化。而对类实例的初始化也类似,会从祖先类到子类、按出现顺序,对类成员的初始化语句、实例初始化块、构造方法依次进行初始化。
当我们在子类中初始化子类时,即
public static void main(String args[]) {
Child child = new Child();
}
其输出效果为
祖父静态初始化
父类静态初始化
子类静态初始化
父类实例初始化
父类构造函数
子类实例初始化
子类构造函数
而如果我们为 Child
添加如下属性
static Child child = new Child();
那么此时实例构造过程会被提前到静态初始化之前,其输出为
祖父静态初始化
父类静态初始化
父类实例初始化 // 此时父类实例初始化在子类静态初始化之前了
父类构造函数
子类实例初始化
子类构造函数
子类静态初始化
父类实例初始化
父类构造函数
子类实例初始化
子类构造函数
下面看一个复杂点的例子
class ComplexInitialization implements Cloneable {
public static int k = 0;
public static ComplexInitialization t1 = new ComplexInitialization("t1");
public static ComplexInitialization t2 = new ComplexInitialization("t2");
public static int i = print("i");
public static int n = 99;
public int j = print("j");
{
print("构造块");
}
static {
print("静态块");
}
public ComplexInitialization(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
++i;
}
public static int print(String str) {
System.out.println((++k) + ":" + str + " i=" + i + " n=" + n);
++n;
return ++i;
}
public static void main(String[] args) {
ComplexInitialization t = new ComplexInitialization("init");
}
}
其输出为
首先T类被加载、连接后进行初始化,会先对字段k、t1、t2、i、n以及static块进行初始化。
1:j i=0 n=0
t1实例的初始化会初始化实例成员j,(实际上先进行父类实例内容的初始化)先调用静态方法print,并执行实例初始化块{},输出
2:构造块 i=1 n=1
随后调用t1实例的构造函数,输出:
3:t1 i=2 n=2
类似有t2实例的初始化:
4:j i=3 n=3
构造块 i=4 n=4
5:构造块 i=4 n=4
6:t2 i=5 n=5
i的初始化:
7:i i=6 n=6
n的初始化和静态块的初始化:
8:静态块 i=7 n=99
t实例的初始化:
9:j i=8 n=100
10:构造块 i=9 n=101
11:init i=10 n=102
构造函数顺序
子类是不继承父类的构造器(构造方法或者构造函数)的,它只是调用(隐式或显式
class SuperClass {
private int n;
SuperClass(){
System.out.println("SuperClass()");
}
SuperClass(int n) {
System.out.println("SuperClass(int n)");
this.n = n;
}
}
// SubClass 类继承
class SubClass extends SuperClass{
private int n;
SubClass(){ // 自动调用父类的无参数构造器
System.out.println("SubClass");
}
public SubClass(int n){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass(int n):"+n);
this.n = n;
}
}
// SubClass2 类继承
class SubClass2 extends SuperClass{
private int n;
SubClass2(){
super(300); // 调用父类中带有参数的构造器
System.out.println("SubClass2");
}
public SubClass2(int n){ // 自动调用父类的无参数构造器
System.out.println("SubClass2(int n):"+n);
this.n = n;
}
}
public class TestSuperSub{
public static void main (String args[]){
System.out.println("------SubClass 类继承------");
SubClass sc1 = new SubClass();
SubClass sc2 = new SubClass(100);
System.out.println("------SubClass2 类继承------");
SubClass2 sc3 = new SubClass2();
SubClass2 sc4 = new SubClass2(200);
}
}
/**
------SubClass 类继承------
SuperClass()
SubClass
SuperClass(int n)
SubClass(int n):100
------SubClass2 类继承------
SuperClass(int n)
SubClass2
SuperClass()
SubClass2(int n):200
**/