java对象的初始化过程

1.当不含static成员时,先看实例:


如图所示,我们先定义相关类,Building, House(继承Building), Villa(继承House), 同时,House有成员变量LivingRoom, LivingRoom有成员变量Bed和Desk。具体如下代码:

//建筑
class Building {
	public Building() {
		System.out.println("Building");
	}
}

//房子
class House extends Building{
	public LivingRoom livingRoom = new LivingRoom();//卧室
	
	public House() {
		System.out.println("House");
	}
}

//别墅
class Villa extends House{
	public Villa () {
		System.out.println("Villa");
	}
}

//卧室
class LivingRoom {
	public Bed bedFirst = new Bed();//床
	public Desk deskFirst = new Desk();//桌子
	
	public LivingRoom () {
		System.out.println("LivingRoom");
	}
}

//床
class Bed {
	public Bed () {
		System.out.println("Bed");
	}
}

//桌子
class Desk {
	public Desk () {
		System.out.println("Desk");
	}
}
此时,我们new Villa():
public class InitializeDemo {
	@Test
	public void testInitialize() {
		Villa villa = new Villa();
	}
}

执行结果为:
Building
Bed
Desk
LivingRoom
House
Villa

解析:

    1.1 我们new一个对象A时,首先会先创建A类的父类B的实例对象,如果B类仍有父类C,会先创建父类C的对象,以此类推,是一个递归的创建过程;

    1.2 当该类的父类对象已经全部创建并初始化成功时,会对该类进行创建和初始化。但是,在对该类进行初始化时,会先初始该类对象的成员变量,再执行该类的构造方法。

    1.3 成员变量的初始化和代码块的执行顺序,是由它们的声明顺序决定的,按顺序依次初始化或执行,但均在构造器方法之前执行。

在此例中,我们在创建Villa对象时,会先试着创建Villa的父类House的对象,但House也有父类Building, Building还有父类Object。因此,实际上,本例中会先创建Object对象并初始化,在Object对象创建并初始化成功后,会创建Building对象,Building对象没有成员变量,所以直接执行构造器,打印出Building。

接着,开始创建House对象,House对象有成员变量livingRoom,因此,会先初始化livingRoom,创建LivingRoom时,也会先创建LivingRoom的父类Object对象并初始化,其次再创建LivingRoom实例,LivingRoom同样有成员变量Bed和Desk,因而会按两个成员变量的定义顺序,先后创建Bed和Desk对象并初始化,先后打印出了Bed和Desk。初始化成员变量成功后,执行LivingRoom的构造器,打印LivingRoom。 初始化LivingRoom成功后,开始执行House的构造器,打印House。

最后,在House初始化成功后,执行了Villa的构造器,打印出Villa。初始化成功。


2. 当有static成员时

  2.1 静态成员变量只会被初始化一次,静态化代码块只会被执行一次,在该类第一次被JVM加载时

  2.2 会先加载父类字节码,再加载子类字节码,如果有创建某类的实例对象,也是在该类的父类和该类的字节码加载完成,即静态成员初始化或执行完成之后,才会实例化该类父类的实例对象和该类的实例对象

  2.3 静态成员变量的初始化和静态化代码块的执行顺序,是由它们的声明顺序决定的,按顺序依次初始化或执行

class Family {
	
	Family (Class className) {
		System.out.println("创建Family对象");
		System.out.println(className.getName());
	}
}

class Person {
	
	Person() {
		System.out.println("创建Person对象");
	}
	
	public static Family family = new Family(Person.class);
	
	static {
		System.out.println("执行Person静态代码块");
	}
	
	{
		System.out.println("执行Person代码块");
	}
}

public class Student extends Person {
	
	public Student() {
		System.out.println("创建student对象");
	}
	
	{
		System.out.println("执行Student代码块");
	}
	
	static {
		System.out.println("执行Student静态代码块");
	}
	
	public static Family staticFamily = new Family(Student.class);
	
	@Test
	public void test() {
		System.out.println("=============");
	}
	
	public Family family = new Family(Student.class);
	
}

执行结果:

创建Family对象
com.tca.thinkInJava.chap7.Person
执行Person静态代码块
执行Student静态代码块
创建Family对象
com.tca.thinkInJava.chap7.Student
执行Person代码块
创建Person对象
执行Student代码块
创建Family对象
com.tca.thinkInJava.chap7.Student
创建student对象
=============

分析:

1. 首先在执行@Test方法时,必须创建Student的实例对象

2. 要创建Student的实例对象,第一步会先加载Student父类Person和Student类的字节码,并对相关静态成员变量进行初始化,执行静态代码块。 

3. 首先加载父类Person字节码,静态成员变量public static Family family优于静态代码块前声明,所以先对静态成员变量family进行初始化。创建Famlily对象,打印“创建Family对象",  "com.tca.thinkInJava.chap7.Person"。再执行静态代码块,打印"执行Person静态代码块"。

4. 加载完Person字节码后,再加载Student字节码。静态代码块在静态成员public static Family staticFamily之前声明,所以先执行静态代码块,打印"执行Student静态代码块",再进行成员变量初始化,执行"创建Family对象", "com.tca.thinkInJava.chap7.Student"。Student字节码加载完毕。

5. 创建Student父类Person的实例对象,创建实例对象时,先进行非静态成员变量初始化和代码块的执行,再执行构造器方法。所以先打印"执行Person代码块",  再打印"创建Person对象"。父类对象创建和初始化完毕。

6. 创建子类对象Student,先进行非静态成员变量初始化和代码块的执行,再执行构造器方法。代码块的声明在非静态成员变量public Family family声明之前,所以先执行代码块, 打印"执行Student代码块", 再对family进行初始化,创建Family对象,打印"创建Family对象", "com.tca.thinkInJava.chap7.Student",最后执行构造器,打印"创建student对象"。子类对象创建和初始化完毕。

7. 执行test测试方法

猜你喜欢

转载自blog.csdn.net/tca0819/article/details/80355489