源代码
class Base {
public static int a = 10;//1
public int b = 20;//9
static {
System.out.println("Static Init Base"+a);//2
}
public Base() {
System.out.println("Init Base"+this.b); //10
}
}
class SuperClass extends Base {
public static int a1 = getSuperStaticNumber();//4
public int b1 = getSuperInstanceNumber(); //12
public SuperClass() {
System.out.println("Init SuperClass"+this.b1);//13
}
static {
System.out.println("Static Init SuperClass"+a1);//5
}
public static int getSuperStaticNumber() {
System.out.println("Static member init");//3
return 100;
}
public int getSuperInstanceNumber() {
System.out.println("Instance member init");//11
return 200;
}
}
public class SubClass extends SuperClass {
public static int a2 = getStaticNumber();//7
public int b2 = getInstanceNumber();//15
public SubClass() {
System.out.println("Init SubClass"+this.b2); //16
}
public static int getStaticNumber() {
System.out.println("Static member init Sub");//6
return 1000;
}
public int getInstanceNumber() {
System.out.println("Instance member init Sub");//14
return 2000;
}
public static void main(String[] args)
{
new SubClass();
}
static {
System.out.println("Static Init"+a2);//8
}
}
结合代码分析步骤
一、首先是带有static的先初始化。先是静态变量初始化,然后静态代码块初始化。
1.Base类中的
1)静态成员函数,无
1)静态成员变量a //1
2)静态初始化块 //2 Static Init Base 10
2.SuperClass类中的
1)静态成员函数 //3 Static member init
2)静态成员变量a1 //4
3)静态初始化块 //5 Static Init SuperClass 100
3.SubClass类中的
1)静态成员函数
//6 Static member init Sub
2)静态成员变量a2 //7
3)静态初始化块 //8 Static Init 1000
二、静态变量和代码块初始化完毕后,开始对类进行实例化操作,初始化实例变量和构造函数。
1.Base类中的
1)成员函数 ,无
2)成员变量b初始化 //9
3)构造函数 //10 Init Base 20
2.SuperClass类中的
1)成员函数 //11 Instance member init
2)成员变量b初始化 //12
3)构造函数 //13 Init SuperClass 200
3.SubClass类中的
1)成员函数 //14 Instance member init Sub
2)成员变量b初始化 //15
3)构造函数 //16 Init SubClass 2000
总结一句话:先父类,后子类。先静态,后实例。成员函数->成员变量->构造函数。
具体文字流程
[1]对象在初始化过程,JVM会先去搜索该类的顶级父类,
直到搜索到我们所定义的SubClass继承树上直接继承于Object类的子类,在这里就是Base类;
[2]然后JVM会先加载Base类,然后初始化Base类的静态变量a,
然后执行Base类的静态初始化块,按照这样第一句话会输出:Static Init Base 10
【*:此时该类还未调用构造函数,构造函数是实例化的时候调用的】
[3]然后JVM按照继承树往下搜索,继续加载Base类的子类,
按照静态成员函数->静态成员变量->静态初始化块的顺序往下递归,
直到加载完我们使用的对象所在的类。
[4]类加载完了过后开始对类进行实例化操作,
这个过程还是会先搜索到直接继承于Object类的子类,在这里就是Base类;
[5]JVM会实例化Base类的成员函数,然后实例化成员变量,最后调用Base类的构造函数;
[6]之后,JVM会递归往继承树下边进行调用,顺序还是遵循:成员函数->成员变量->构造函数;
[7]最后直到SubClass类的构造函数调用完成
注意事项
[1]如果一个类的父类没有无参数构造函数,也就是说父类自定义了一个带参数的构造函数,
那么系统不会提供无参数构造函数,此时子类在调用构造函数的时候必须最开始显示调用super(param),
因为在构造函数调用之前系统总会先去调用父类的构造函数。
[2]若一个类定义的时候没有提供构造函数,JVM会自动为该类定义一个无参数的构造函数
[3]一个类在调用构造函数的时候,JVM隐藏了一句代码super(),
前提是父类未定义构造函数或者显示定义了无参构造函数;其含义就是调用父类的构造函数,
如果父类的无参数构造函数被覆盖的话需要在子类构造函数中显示调用父类带参数的构造函数
[4]当类中的成员函数遇到变量的时候,
会先根据变量名在函数域即局部变量范围内去寻找该变量,如果找不到才会去寻找实例变量或者静态变量。
其意思可以理解为局部变量可以和实例变量或者静态变量同名,
而且会在函数调用过程优先使用,
这个原因在于在函数范围内,如果调用的变量是实例变量,其中前缀this.被隐藏了。