----------------------android培训、java培训、期待与您交流! ----------------------
通过下面一道题来分析一下一个类的创建过程。
写出运行结果:
class ClassA{
static {
System.out.println("In ClassA Static");
}
public ClassA(){
System.out.println("ClassA()");
}
}
class ClassB{
static {
System.out.println("In ClassB Static");
}
public ClassB(){
System.out.println("ClassB()");
}
}
class ClassC extends ClassB{
static{
System.out.println("In ClassC Static");
}
public ClassC(){
System.out.println("ClassC()");
}
}
class MyClass {
static ClassA ca = new ClassA();
ClassC cc = new ClassC();
static{
System.out.println("In MyClass Static");
}
public MyClass(){
System.out.println("MyClass()");
}
}
public class TestMain{
public static void main(String args[]){
MyClass mc1 = new MyClass();
MyClass mc2 = new MyClass();
System.out.println(mc1.cc == mc2.cc);
System.out.println(mc1.ca == mc2.ca);
}
}
分析:
该题需要创建两个MyClass 对象。
一般而言,创建对象的过程如下:
1) 分配空间
2) 递归构造父类对象
3) 初始化本类属性
4) 调用本类构造方法
如果某个类是JVM 运行中第一次遇到,则会进行类加载的动作。类加载会初始化该类
的静态属性,并执行该类的静态初始化代码块。
因此,本题中创建的两个MyClass 对象,依次会进行如下步骤:
1) 加载MyClass 类,并初始化其静态属性
2) 为MyClass 分配空间
3) 递归构造MyClass 的父类对象。
4) 初始化MyClass 属性
5) 调用MyClass 的构造方法。
至此,第一个对象创建完成。之后创建第二个对象时,由于类加载已经完成,因此跳过
类加载的步骤,即:
6) 为MyClass 分配空间
7) 递归构造MyClass 的父类对象
8) 初始化MyClass 属性
9) 调用MyClass 的构造方法。
经过9 个步骤,两个对象创建完毕。
其中,在第1 步时,类加载时会初始化其静态属性,之后会执行静态初始化代码块,因
此对第1 步进行细分:
1.1 初始化ca 属性
1.2 执行MyClass 的静态初始化代码块。
在1.1 执行时,初始化ca 属性会创建ClassA 对象。由于这是第一次在程序中用到ClassA
对象,因此会执行对ClassA 对象的类加载。即:1.1 步可以细分为以下步骤:
1.1.1 加载ClassA 类
1.1.2 创建ClassA 对象
在初始化MyClass 属性时,需要创建ClassC 对象。而程序执行到第4 步时是第一次遇
到ClassC 类型的对象,因此会执行ClassC 的类加载。因此,对第4 步和第8 步进行细化:
第4 步:初始化MyClass 属性:
4.1 加载ClassC
4.2 为ClassC 分配空间
4.3 递归构造ClassC 的父类对象
4.4 初始化ClassC 属性
4.5 调用ClassC 的构造方法
第8 步,初始化MyClass 属性:
8.1 为ClassC 分配空间
8.2 递归构造ClassC 的父类对象
8.3 初始化ClassC 属性
8.4 调用ClassC 的构造方法
对于4.1 而言,为了创建ClassC 对象,必须获取ClassC 类的信息。而获得ClassC 类完
整信息的前提,是获得ClassB 类的信息。由于是第一次遇到ClassB 和ClassC,因此会先加
载ClassB,之后加载ClassC。细分之后,4.1 分为以下两步:
4.1.1 加载ClassB
4.1.2 加载ClassC
完整列出所有步骤如下:
1.1.1 加载ClassA 类 输出In ClassA Static
1.1.2 创建ClassA 对象 输出ClassA()
1.2 执行MyClass 的静态初始化代码块 输出In Static MyClass
2 分配MyClass 的空间 无输出
3 递归构造MyClass 的父类对象 无输出
4.1.1 加载ClassB 输出 In ClassB Static
4.1.2 加载ClassC 输出In ClassC Static
4.2 分配ClassC 的空间 无输出
4.3 构造ClassC 的父类对象(ClassB) 输出ClassB()
4.4 初始化ClassC 属性 无输出
4.5 调用ClassC 的构造方法 输出ClassC()
5 调用MyClass 的构造方法 输出MyClass()
6 为MyClass 分配空间 无输出
7 递归构造MyClass 的父类对象 无输出
8.1 为ClassC 分配空间 无输出
8.2 递归构造ClassC 的父类对象 ClassB()
8.3 初始化ClassC 的属性 无输出
8.4 调用ClassC 的构造方法 ClassC()
9 调用MyClass 的构造方法 MyClass()
运行结果:
In ClassA Static
ClassA()
In Static MyClass
In ClassB Static
In ClassC Static
ClassB()
ClassC()
MyClass()
ClassB()
ClassC()
MyClass()
总结:
一个类的创建过程:
可以简单的分为一下几步:
1、加载本类
2、分配内存空间
3、递归调用父类构造方法
4、递归为父类分配空间
5、递归初始化父类属性
6、递归创建父类对象
7、创建子类对象
执行顺序:静态成员变量--->静态代码块--->成员变量--->代码块
注意:静态成员变量和静态代码块只在类加载的时候执行一次,以后再创建对象不再执行。
----------------------android培训、java培训、期待与您交流! ----------------------