从类的加载过程分析静态变量和静态块

大家先看下这段代码的运行结果

从类的加载过程分析静态变量和静态块

       这里要求输出id和sid的值,如果不了解类加载过程的话,很多人想当然的觉得id和sid都是1,这是一种很常见的错误,下面我们从类加载过程来分析这段代码。我们知道一个类的生命周期包括:加载、验证、准备、解析、初始化、使用和卸载7个阶段,而类的加载过程也就是前面五个阶段所执行的具体动作。并且加载、验证、准备、初始化这几个阶段顺序是确定的,类的加载过程必须按这种顺序按部就班地开始。

       就这段代码而言,我们只讨论准备和初始化阶段。因为在类的加载过程中只有这两个阶段是和静态区直接挂钩的。先说准备阶段,我们看下周大大怎么说的

从类的加载过程分析静态变量和静态块

总结一句话就是:在准备阶段会给静态变量分配内存并初始化一个默认值。注意是默认值,还没有到初始化阶段。所以对于这段代码来说,在准备阶段,person = null;id = 0;sid = 0。

准备阶段完了之后我们再看初始化阶段,同样是周大大说的:

从类的加载过程分析静态变量和静态块

划线的地方基本是核心思想,意思就是准备阶段会给类变量一个默认值,然后初始化阶段就是我们自己赋给这个类变量的值,也就是显示初始化。注意静态语句是在初始化阶段执行的,准备阶段并不会执行。并且初始化阶段执行顺序是按照源文件的顺序决定的。

现在我们来看代码:找到main方法,要求输出id和sid,这里访问的id是静态变量,所以会加载person类。

准备阶段:按顺序执行,person = null;id = 0; sid = 0;完事

初始化阶段:person = new Person();很显然实例化person了,这时候会调用构造方法,而调用构造方法会先执行构造块,因为java编译的时候会默认将构造块里面的代码放在构造器代码体的前面。所以最先输出:构造块,然后id++,sid++,这时候id = 1;sid = 1。person初始化完事。
接着第二行id,这里并没有给id初始化,所以id还是1;
再到sid,初始化值为0;所以sid = 0;
再执行静态块,第二行输出:静态块。这时候类加载完成,接着输出id和sid的值,也就是1和0.

所以我们再控制台看到的结果是:

从类的加载过程分析静态变量和静态块