Java类初始化机制

  • 类的初始化步骤
  1. 加载:将.class文件从磁盘加载到内存,然后在堆区创建一个java.lang.Class对象,这个对象封装了类的全部信息。
  2. 连接:确保被加载的.class文件符合规范,如果符合规范则为类的静态变量分配内存并赋予默认值。
  3. 初始化:为类的静态变量赋予正确的值(所谓正确是指用户赋予的值)。

在连接过程中,静态变量的默认值赋值规则为:整形赋值为0,浮点型赋值为0.0,布尔型赋值为false,引用类型赋值为null。如,

public class Test1 {

	private static int i;// 默认初始化为0
	private static short j;// 默认初始化为0
	private static long k;// 默认初始化为0
	private static byte o;// 默认初始化为0
	private static String str;// 默认初始化为null
	private static boolean flag;// 默认初始化为false
	private static float f;// 默认初始化为0.0
	private static double d;// 默认初始化为0.0

	public static void main(String args[]) {
		init();
	}

	private static void init() {
		System.out.println("int i= " + i + " short j= " + j + " long k= " + k
				+ " byte o= " + o + " String str=" + str + " flag= " + flag
				+ " float f=" + f + " double d=" + d);

	}
}

输出结果为:

int i= 0 short j= 0 long k= 0 byte o= 0 String str=null flag= false float f=0.0 double d=0.0

类的静态变量首先按照上述规则赋予默认值,然后才会初始化为自定义的值,如,

/**
 * 加载的时候给静态变量赋予默认值 然后 初始化自定义的值
 * @lsl
 */
 class ClassLoaderTest {
	
	private static ClassLoaderTest clt=new ClassLoaderTest();
	public static int counter1;  
	public static int counter2=0;
	private ClassLoaderTest(){
		counter1++;
		counter2++;
	}
	public static ClassLoaderTest getInstance(){
		return clt;
	}
}

public class ClassLoaderTestMain{
	
	public static void main(String args[]){
		
		ClassLoaderTest clt=ClassLoaderTest.getInstance();//主动使用:调用类的静态方法(会引起类的初始化)
		System.out.println("counter1= "+clt.counter1);
		System.out.println("counter2= "+clt.counter2);
	}
}

输出结果为:

counter1= 1
counter2= 0

执行顺序为:

第一步,为静态变量赋予默认值,clt=null,counter1=0,counter2=0;

第二步,为静态变量赋予自定义值,首先执行构造函数,使得counter1=1,counter2=1,然后执行

public static int counter1;  
public static int counter2=0;
第一行不做任何操作,第二行将counter2赋值为0。可以进一步想象,如果第一句修改为 public static int counter1=2; 则输出结果将是counter1=2,counter2=0;

  • 对类的主动使用会导致类的初始化操作,主动使用一共包括六种
  1. 虚拟机启动时被作为启动类的类;
  2. 创建类的实例(new Object(););
  3. 访问类的静态变量、或者为静态变量赋值;
  4. 调用类的静态方法;
  5. 初始化一个类的子类时对父类的主动使用;
  6. 通过反射使用该类。
第一种,也是最为直观的一种,执行启动类(包含main函数的public类)会导致该启动类初始化。如,

public class Child {

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) {//启动类入口

	}
}

输出结果为:

static block of class Child
注意类的初始化并没有执行构造函数,而是仅针对静态块和静态变量。


第二种,创建类的实例,会导致类的初始化。如,

class Parent {
	static int i;

	static {
		System.out.println(i+"-static block of class Parent");
	}

	public Parent() {
		System.out.println("constructor of class Parent");
	}

	public static void method() {
		System.out.println("method of class Parent");
	}
}

public class Child {

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) {
		new Parent();//创建类的实例

	}
}

输出结果为:

static block of class Child
0-static block of class Parent
constructor of class Parent

注意初始化多个类时,类间的初始化顺序,以及new一个对象时,静态语句和构造函数的执行顺序。


第三种,访问类的静态变量,或者为类的静态变量赋值,会导致类的初始化。如,

class Parent {
	static int i;

	static {
		System.out.println(i+"-static block of class Parent");
	}

	public Parent() {
		System.out.println("constructor of class Parent");
	}

	public static void method() {
		System.out.println("method of class Parent");
	}
}

public class Child {

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) {
		System.out.println(Parent.i);//访问类的静态变量
 }
}

输出结果为:

static block of class Child
0-static block of class Parent
0

这一种也比较容易理解,类的初始化是初始化类的静态变量,或者静态块,当你访问一个类的静态变量时,被访问的静态变量所在类会初始化该变量,以免无法访问。


第四种,调用类的静态方法会导致类的初始化。如,

class Parent {
	static int i;

	static {
		System.out.println(i+"-static block of class Parent");
	}

	public Parent() {
		System.out.println("constructor of class Parent");
	}

	public static void method() {
		System.out.println("method of class Parent");
	}
}

public class Child {

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) {
		Parent.method();//调用类的静态方法
	}
}
输出结果为:

static block of class Child
0-static block of class Parent
method of class Parent

第五种,初始化子类会导致父类的初始化。


class Parent {
	static int i;

	static {
		System.out.println(i+"-static block of class Parent");
	}

	public Parent() {
		System.out.println("constructor of class Parent");
	}

	public static void method() {
		System.out.println("method of class Parent");
	}
}

public class Child extends Parent{

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) {//作为启动类
	
	}
}

输出结果为:

0-static block of class Parent
static block of class Child

可见,初始化子类时,会首先初始化父类。( 注意,初始化时针对静态变量或静态代码块,构造函数在初始化时不一定执行,除非是通过创建对象这种方式进行初始化


第六种,反射是对类的主动使用,会导致类的初始化。如,

package jvm;

class Parent {
	static int i;

	static {
		System.out.println(i+"-static block of class Parent");
	}

	public Parent() {
		System.out.println("constructor of class Parent");
	}

	public static void method() {
		System.out.println("method of class Parent");
	}
}

public class Child extends Parent{

	public Child() {
		System.out.println("constructor of class Child");
	}

	static {
		System.out.println("static block of class Child");
	}

	public static void main(String[] args) throws ClassNotFoundException {
		Class.forName("jvm.Parent");//反射
	}
}

输出结果为:

0-static block of class Parent
static block of class Child

----------------------End----------------------

除了上述6种对类的主动使用外,其它对类的使用(Object object;)都不会引起类的初始化操作。


(总结不当之处,敬请指正)


  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值