java对象的初始化顺序
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
对象初始化流程:
我们根据一段代码来分析对象初始化流程:
/**
*基类包含一静态变量、包含一实例变量
*包含一个静态初始化块以及一个构造子
*/
class Base{
public static int a = 10;
public int b = 20;
static
{
System.out.println("Static Init Base " + a);
//System.out.println("Null Init " + b);
}
public Base()
{
System.out.println("Init Base " + this.b);
}
}
/**
*一级子类和基类包含的内容一样
**/
class SuperClass extends Base{
public static int a1 = getSuperStaticNumber();
public int b1 = getSuperInstanceNumber();
public SuperClass()
{
System.out.println("Init SuperClass" + this.b1); }
static
{
System.out.println("Static Init SuperClass" + a1); }
public static int getSuperStaticNumber()
{
System.out.println("Static member init");
return 100;
}
public int getSuperInstanceNumber()
{
System.out.println("Instance member init");
return 200;
}
}
/**
*二级子类为测试该代码的驱动类
*/
public class SubClass extends SuperClass{
public static int a2 = getStaticNumber();
public int b2 = getInstanceNumber();
public SubClass()
{
System.out.println("Init SubClass " + this.b2);
}
public static int getStaticNumber()
{
System.out.println("Static member init Sub");
return 1000;
}
public int getInstanceNumber()
{
System.out.println("Instance member init Sub");
return 2000;
}
public static void main(String args[])
{
new SubClass();
}
static
{
System.out.println("Static Init " + a2);
}
}
这段代码会有以下输出:
Static Init Base 10
Static member init
Static Init SuperClass 100
Static member init Sub
Static Init 1000
Init Base 20
Instance member init
Init SuperClass 200
Instance member init Sub
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类的构造函数调用完成
按照上边书写的逻辑,我们就很清楚了上边源代码的执行结果,而整个JVM 初始化某个类的流程就是按照以上逻辑进行
在构造函数调用过程,有几点是需要我们留意的,这里就不提供代码实例,有兴趣的朋友可以自己去试试
[1]如果一个类的父类没有无参数构造函数,也就是说父类自定义了一个带参数的构造函数,那么系统不会提供无参数构造函数,此时子类在调用构造函数的时候必须最开始显示调用super(param),因为在构造函数调用之前系统总会先去调用父类的构造函数
[2]若一个类定义的时候没有提供构造函数,JVM会自动为该类定义一个无参数的构造函数
[3]一个类在调用构造函数的时候,JVM隐藏了一句代码super(),前提是父类未定义构造函数或者显示定义了无参构造函数;其含义就是调用父类的构造函数,如果父类的无参数构造函数被覆盖的话需要在子类构造函数中显示调用父类带参数的构造函数
[4]当类中的成员函数遇到变量的时候,会先根据变量名在函数域即局部变量范围内去寻找该变量,如果找不到才会去寻找实例变量或者静态变量,其意思可以理解为局部变量可以和实例变量或者静态变量同名,而且会在函数调用过程优先使用,这个原因在于在函数范围内,如果调用的变量是实例变量,其中前缀this.被隐藏了。