天天看点

类的初始化和实例初始化

这里的原理和例子来源自尚硅谷的讲师宋红康(深入理解JVM)和柴林燕(Java面试题),表示非常感谢。

java程序将字节码通过类的加载子系统将类的元信息加载到方法区中,一共有三步,加载,链接,初始化。具体请看深入理解JVM。这里通过题目演示类的初始化和实例初始化。

father类

public class Father{
	private int i = test();
	private static int j = method();
	
	static{
		System.out.print("(1)");
	}
	Father(){
		System.out.print("(2)");
	}
	{
		System.out.print("(3)");
	}
	
	
	public int test(){
		System.out.print("(4)");
		return 1;
	}
	public static int method(){
		System.out.print("(5)");
		return 1;
	}
}
           

son类

public class Son extends Father{
	private int i = test();
	private static int j = method();
	static{
		System.out.print("(6)");
	}
	Son(){
//		super();//写或不写都在,在子类构造器中一定会调用父类的构造器
		System.out.print("(7)");
	}
	{
		System.out.print("(8)");
	}
	public int test(){
		System.out.print("(9)");
		return 1;
	}
	public static int method(){
		System.out.print("(10)");
		return 1;
	}
	public static void main(String[] args) {
	}
}
           

若运行son类,输出的结果为

类的初始化和实例初始化

这是为什么呢,主方法里面并没有调用任何函数?这就需要讲解一下类的初始化过程了。

类的初始化过程

类的初始化和实例初始化

所以当运行主方法时,将son和father类加载进虚拟机的方法区。main方法在son类中,要加载son类的时候需要先加载其父类father,而在初始化son的时候需要先初始化father,在初始化father时,执行方法,赋值静态的类变量的静态代码块。所以就先输出(5)(1),接下里初始化son类,也是赋值静态的类变量的静态代码块。所以输出(10)(6)。

实例的初始化过程

在上面代码的基础上,修改main方法,加上一下三行代码

Son s1 = new Son();
		System.out.println();
		Son s2 = new Son();
           

则输出结果为

类的初始化和实例初始化

其中(5)(1)(10)(6)上面为两个类初始化的输出结果,主要讨论后面的输出结果,这就涉及到实例的初始化和方法的重写了。

类的初始化和实例初始化
类的初始化和实例初始化

分析结果:我们从上知道,实例化对象就是调用方法,也就是构造器,**注意:每个构造器不管你加不加都默认有一句super();**也即是说先需要调用父类的构造器。然后在初始化非静态变量和非静态代码块,最后再执行构造器。所以过程如下

son类

* 子类的实例化方法<init>:
 * (1)super()(最前)      (9)(3)(2)
 * (2)i = test();    (9)
 * (3)子类的非静态代码块    (8)
 * (4)子类的无参构造(最后) (7)
           

father类

*  父类的实例化方法:
 * (1)super()(最前)
 * (2)i = test();
 * (3)父类的非静态代码块
 * (4)父类的无参构造(最后)
 * 
 * 非静态方法前面其实有一个默认的对象this
 * this在构造器(或<init>)它表示的是正在创建的对象,因为这里是在创建Son对象,所以
 * test()执行的是子类重写的代码(面向对象多态)
 * 
 * 这里i=test()执行的是子类重写的test()方法
 * 
           

根据这个分析可以得出结果。