//Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver;
10: new #18;
//class HashMap ②
13: dup
14: invokespecial #19;
//Method java/util/HashMap."
17: putstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
20: getstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
23: ldc #23;
//String 0
25: ldc #25;
//String 北京市
27: invokeinterface #31, 3;
//InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object; ③
32: pop 33: returnprivate com.ccb.framework.enums.CachingEnumResolver();
Code: 0: aload_0 1: invokespecial #34;
//Method java/lang/Object."
//Method initEnums:()V ④ 7: returnpublic static void initEnums();
Code: 0: getstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
⑤ 3: ifnonnull 24 6: getstatic #44;
//Field java/lang/System.out:Ljava/io/PrintStream;
9: ldc #46;
//String CODE_MAP_CACHE为空,问题在这里开始暴露.
11: invokevirtual #52;
//Method java/io/PrintStream.println:(Ljava/lang/String;)V 14: new #18;
//class HashMap 17: dup 18: invokespecial #19;
//Method java/util/HashMap."
//Field CODE_MAP_CACHE:Ljava/util/Map;
24: getstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
27: ldc #54;
//String 1 29: ldc #25;
//String 北京市 31: invokeinterface #31, 3;
//InterfaceMethod java/util/Map.put:(Ljava/lang/Object;
Ljava/lang/Object;)Ljava/lang/Object;
⑦ 36: pop 37: getstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
40: ldc #56;
//String 2 42: ldc #58;
//String 云南省 44: invokeinterface #31, 3;
//InterfaceMethod java/util/Map.put:(Ljava/lang/Object;Ljava/lang/Object;)Ljava/lang/Object;
⑧ 49: pop 50: returnpublic java.util.Map getCache();
Code: 0: getstatic #21;
//Field CODE_MAP_CACHE:Ljava/util/Map;
3: invokestatic #66;
//Method java/util/Collections.unmodifiableMap:(Ljava/util/Map;)Ljava/util/Map;
6: areturnpublic static com.ccb.framework.enums.CachingEnumResolver getInstance();
Code: 0: getstatic #16;
//Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver;
⑨ 3: areturn}
如果上面[清单一]显示,清单内容是在 JDK1.4 环境下的字节码内容,可能这份清单对于很大部分兄弟来说确实没有多少吸引力,因为这些 JVM 指令确实不像源代码那样漂亮易懂。但它的的确确是查找和定位问题最直接的办法,我们想要的答案就在这份 JVM 指令清单里。
现在,让我们对该类从类初始化到对象实例初始化全过程分析[清单一]中的代码执行轨迹。
如前面所述,类初始化是在类真正可用时的最后一项前阶工作,该阶段负责对所有类正确的初始化值,此项工作是线程安全的,JVM会保证多线程同步。
第1步:调用类初始化方法 CachingEnumResolver.
第2步:进入
第3步:让我们顺着执行顺序向下看,"④" 行,该行所在方法就是该类的构造器,该方法先调用父类的构造器
第4步:"⑤" 行,该行获取 "CODE_MAP_CACHE" 字段值,其运行时该字段值为 null。注意,问题已经开始显现了。(作为程序员的你一定是希望该字段已经被初始化过了,而事实上它还没有被初始化)。通过判断,由于该字段为 NULL,因此程序将继续执行到 "⑥" 行,将该字段实例化为 HashMap()。

