Java类加载与初始化机制实例分析

今天看到一个关于类加载与初始化顺序的一个例子,虽然有点怪,但懂了真的很有意思,也能反应出理解的深度,还是先看代码吧

public class StaticTest
{
    public static void main(String[] args)
    {
        staticFunction();
    }
    static StaticTest st = new StaticTest();//第9行

    static
    {
        System.out.println("1");
    }

    {
        System.out.println("2");
    }

    StaticTest()
    {
        System.out.println("3");
        System.out.println("a="+a+",b="+b);
    }

    public static void staticFunction(){
        System.out.println("4");
    }
    static int b = 112;//第27行
    int a = 110;
    
}
各位,能看出输出结果么,结果是

2
3
a=110,b=0
1
4

我相信很多人都和我开始一样没看懂为啥静态变量b输出0,而非静态变量a是110。不慌,往下看。
这里写图片描述

概念

静态初始化:在使用到类的任意元素时初始化,对内部的静态变量,静态块进行执行,并且按照程序给定顺序(不论是块还是成员变量),只此一次

实例初始化:在调用构造方法时初始化,对类中非静态成员变量初始化,执行构造块(没有只此一次)


程序执行步骤

这里设计到的关键步骤在于准备初始化两个阶段



程序入口位于main方法,main方法在StaticTest类中,所以开始静态初始化staticTest类

当执行到第9行也就是

    static StaticTest st = new StaticTest();//第9行

时,因为需要构造实例,所以在静态初始化的半路又跑去执行实例初始化去了

实例初始化先后执行了构造块输出了2, 然后对a赋了值,再去执行构造函数(这时候b还没有赋值!!!!!),输出a=110,b=0。实例初始化结束

继续执行没执行完的静态初始化,输出静态块中的1,给b赋值112,静态初始化结束

最后输出main中的4,程序结束


再度分析

 问:为什么b是0?

答:最关键的是在于内嵌初始化,这里的静态初始化中途又加了一个实例初始化,蛋疼的是b的赋值还在该实例初始化之后,在准备阶段分配空间时大家都有默认值,基本数值类型是0,引用是null,所以b默认值是0,实例化时输出的也是0


问:实例初始化中途使用到未被赋值的静态变量,该变量不会去赋值吗?

答:首先静态初始化肯定在实例初始化之前,这里是静态初始化中途遇到需要实例初始化的静态变量,所以才去调用

的实例初始化,实例初始化会觉得用到的静态变量已经被赋了值了,它便不再去管静态变量的值是否是默认值还是已经赋了

值,所以不会去给未被赋值的静态变量赋值

程序改动

改动1:把static int b = 112;放到第九行之前,也就是说把b的赋值放到内嵌的实例初始化之前,结果中b=112,说明确实是顺序问题导致b没被赋值

      改动2:或者把main方法中的StaticFunction()改成new StaticTest(),这时的b输出为112,进一步证明内嵌了实例初始化过程,实例初始化结束后最终完成未完成的静态初始化(b赋值112),再执行的main方法,这一次输出的a=110,b=112


关于类加载详细信息,可以看http://blog.csdn.net/u013256816/article/details/50829596



猜你喜欢

转载自blog.csdn.net/lyandyhk/article/details/50970984