转载: Java虚拟机类加载机制——案例分析

在《Java虚拟机类加载机制》一文中详细阐述了类加载的过程,并举了几个例子进行了简要分析,在文章的最后留了一个悬念给各位,这里来揭开这个悬念。建议先看完《Java虚拟机类加载机制》这篇再来看这个,印象会比较深刻,如若不然,也没什么关系~~

下面是程序代码:

package jvm.classload;

public class StaticTest
{
public static void main(String[] args)
{
staticFunction();
} static StaticTest st = new StaticTest(); 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");
} int a=110;
static int b =112;
}

问题是:请问这段程序的输出是什么?

  这个是我在论坛上看到的一个问题,我觉得比较金典。

  一般对于这类问题,小伙伴们脑海中肯定浮现出这样的knowledge:

Java中赋值顺序:

  1. 父类的静态变量赋值
  2. 自身的静态变量赋值
  3. 父类成员变量赋值
  4. 父类块赋值
  5. 父类构造函数赋值
  6. 自身成员变量赋值
  7. 自身块赋值
  8. 自身构造函数赋值

ok,按照这个理论输出是什么呢?答案输出:1 4,这样正确嚒?肯定不正确啦,这里不是说上面的规则不正确,而是说不能简单的套用这个规则。

  正确的答案是:

2
3
a=110,b=0
1
4

是不是有点不可思议?且听我一一道来,这里主要的点之一:实例初始化不一定要在类初始化结束之后才开始初始化。

类的生命周期是:加载->验证->准备->解析->初始化->使用->卸载,只有在准备阶段和初始化阶段才会涉及类变量的初始化和赋值,因此只针对这两个阶段进行分析;

类的准备阶段需要做是为类变量分配内存并设置默认值,因此类变量st为null、b为0;(需要注意的是如果类变量是final,编译时javac将会为value生成ConstantValue属性,在准备阶段虚拟机就会根据ConstantValue的设置将变量设置为指定的值,如果这里这么定义:static final int b=112,那么在准备阶段b的值就是112,而不再是0了。)

类的初始化阶段需要做是执行类构造器(类构造器是编译器收集所有静态语句块和类变量的赋值语句按语句在源码中的顺序合并生成类构造器,对象的构造方法是(),类的构造方法是(),可以在堆栈信息中看到),因此先执行第一条静态变量的赋值语句即st = new StaticTest (),此时会进行对象的初始化,对象的初始化是先初始化成员变量再执行构造方法,因此打印2->设置a为110->执行构造方法(打印3,此时a已经赋值为110,但是b只是设置了默认值0,并未完成赋值动作),等对象的初始化完成后继续执行之前的类构造器的语句,接下来就不详细说了,按照语句在源码中的顺序执行即可。

这里面还牵涉到一个冷知识,就是在嵌套初始化时有一个特别的逻辑。特别是内嵌的这个变量恰好是个静态成员,而且是本类的实例。

这会导致一个有趣的现象:“实例初始化竟然出现在静态初始化之前”。

其实并没有提前,你要知道java记录初始化与否的时机。

看一个简化的代码,把关键问题解释清楚:

public class Test {
public static void main(String[] args) {
func();
}
static Test st = new Test();
static void func(){}
}

根据上面的代码,有以下步骤:

  1. 首先在执行此段代码时,首先由main方法的调用触发静态初始化。
  2. 在初始化Test 类的静态部分时,遇到st这个成员。
  3. 但凑巧这个变量引用的是本类的实例。
  4. 那么问题来了,此时静态初始化过程还没完成就要初始化实例部分了。是这样么?
  5. 从人的角度是的。但从java的角度,一旦开始初始化静态部分,无论是否完成,后续都不会再重新触发静态初始化流程了。
  6. 因此在实例化st变量时,实际上是把实例初始化嵌入到了静态初始化流程中,并且在楼主的问题中,嵌入到了静态初始化的起始位置。这就导致了实例初始化完全至于静态初始化之前。这也是导致a有值b没值的原因。
  7. 最后再考虑到文本顺序,结果就显而易见了。

详细看到这里,心中大概有个结论了吧,如果对于类的加载机制比较模糊的话,可以参考开篇推荐的博文。

Java虚拟机类加载机制——案例分析的更多相关文章

  1. 【转载】Java虚拟机类加载机制与案例分析

    出处:https://blog.csdn.net/u013256816/article/details/50829596 https://blog.csdn.net/u013256816/articl ...

  2. [转]Java虚拟机类加载机制

    原文地址:http://blog.csdn.net/u013256816/article/details/50829596 看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎 ...

  3. 深入理解Java虚拟机---类加载机制(简略版)

    类加载机制 谈起类加载机制,在这里说个题外话,当初本人在学了两三个月的Java后,只了解了一些皮毛知识,就屁颠屁颠得去附近学校的招聘会去蹭蹭面试经验,和HR聊了一会后开始了技术面试,前抛出了两个简单的 ...

  4. 面试官,不要再问我“Java虚拟机类加载机制”了

    关于Java虚拟机类加载机制往往有两方面的面试题:根据程序判断输出结果和讲讲虚拟机类加载机制的流程.其实这两类题本质上都是考察面试者对Java虚拟机类加载机制的了解. 面试题试水 现在有这样一道判断程 ...

  5. java虚拟机类加载机制和双亲委派模型

    java虚拟机类加载机制:虚拟机把描述类的数据从class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的java类型. 类的生命周期是从类被加载到虚拟机内存中,到卸 ...

  6. 面试官,不要再问我“Java虚拟机类加载机制”了(转载)

    关于Java虚拟机类加载机制往往有两方面的 面试题:根据程序判断输出结果和讲讲虚拟机类加载机制的流程.其实这两类题本质上都是考察面试者对Java虚拟机类加载机制的了解. 面试题试水 现在有这样一道判断 ...

  7. 深度分析:Java虚拟机类加载机制、过程与类加载器

    虚拟机类加载机制是把描述类的数据从 Class 文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被虚拟机直接使用的 Java 类型. ​ 需要注意的是 Java 语言与其他编译时需要进 ...

  8. Java虚拟机类加载机制

    看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的.随着编程经验的日积月累,越来越感觉到了解虚拟机相关要领的重要性.闲话不多说,老规矩 ...

  9. Java 虚拟机类加载机制

    看到这个题目,很多人会觉得我写我的java代码,至于类,JVM爱怎么加载就怎么加载,博主有很长一段时间也是这么认为的.随着编程经验的日积月累,越来越感觉到了解虚拟机相关要领的重要性.闲话不多说,老规矩 ...

随机推荐

  1. profile、bashrc、bash_profile之间的区别和联系

    /etc/profile:此文件为系统的每个用户设置环境信息,当用户第一次登录时,该文件被执行.并从/etc/profile.d目录的配置文件中搜集shell的设置. 英文描述为: # /etc/pr ...

  2. windows api线程

    一.1.定义入口函数static void  threadFunc(void);//在TestDlg.h里面声明 void CTestDlg::threadFunc(void) //在TestDlg. ...

  3. BZOJ3687:bitset STL

    [bzoj3687][FJ2014集训]简单题 2014年9月14日1,8212 [题目描述]小呆开始研究集合论了,他提出了关于一个数集四个问题:1. 子集的异或和的算术和.2. 子集的异或和的异或和 ...

  4. Java CSV操作(导出和导入)

    Java CSV操作(导出和导入)  CSV是逗号分隔文件(Comma Separated Values)的首字母英文缩写,是一种用来存储数据的纯文本格式,通常用于电子表格或数据库软件.在 CSV文件 ...

  5. dictionaryWithObjectsAndKeys

    NSDictionary    dictionaryWithObjectsAndKeys NSDictionary *parmDic = [NSDictionary dictionaryWithObj ...

  6. mysql 修改数据库的列

    alter table tableName oldcolumn newcolumn datatype;

  7. SqlSever基础 一个条件group by 一列有两个内容,分组并查看每个内容有多少行,并用as起名

    镇场诗:---大梦谁觉,水月中建博客.百千磨难,才知世事无常.---今持佛语,技术无量愿学.愿尽所学,铸一良心博客.------------------------------------------ ...

  8. BZOJ 3144 切糕(最小割)

    题目链接:http://61.187.179.132/JudgeOnline/problem.php?id=3144 题意: 思路:我们假设没有那个D的限制.这样就简 单了.贪心的话,我们只要在每一个 ...

  9. css选择器选择顺序是从右往左的,为什么?

    https://segmentfault.com/q/1010000000713509 为什么 CSS 选择器解析的时候是从右往左? CSS 的后代选择器本身就是一种在标准里面不那么推荐的方式. 首先 ...

  10. 图片轮播的JS写法,通用涉及多个轮播

    本代码是借鉴大神的代码分析理解后,自己改写的!有不足指出希望给为大神指点. 核心只有一个JS,里面包含了css样式. 展示效果图: