科技行者

行者学院 转型私董会 科技行者专题报道 网红大战科技行者

知识库

知识库 安全导航

至顶网软件频道基础软件解析Java类和对象的初始化过程(3)

解析Java类和对象的初始化过程(3)

  • 扫一扫
    分享文章到微信

  • 扫一扫
    关注官方公众号
    至顶头条

本文主要对类和对象初始化全过程进行分析,通过一个实际问题引入,将源代码转换成JVM字节码后,对JVM执行过程的关键点进行全面解析。

作者:天新网 来源:天新网 2007年9月3日

关键字:

  • 评论
  • 分享微博
  • 分享邮件

在与初始化时机相关的类装载时机问题上,Java虚拟机规范并没有对其做严格的定义,这就使得JVM在实现上可以根据自己的特点提供采用不同的装载策略。我们可以思考一下Jboss AOP框架的实现原理,它就是在对你的class文件装载环节做了手脚--插入了AOP的相关拦截字节码,这使得它可以对程序员做到完全透明化,哪怕你用new操作符创建出的对象实例也一样能被AOP框架拦截--与之相对应的Spring AOP,你必须通过他的BeanFactory获得被AOP代理过的受管对象,当然Jboss AOP的缺点也很明显--他是和JBOSS服务器绑定很紧密的,你不能很轻松的移植到其它服务器上。嗯~……,说到这里有些跑题了,要知道AOP实现策略足可以写一本厚厚的书了,嘿嘿,就此打住。

说了这么多,类的初始化时机就是在“在首次主动使用时”,那么,哪些情形下才符合首次主动使用的要求呢?

首次主动使用的情形:

◆创建某个类的新实例时--new、反射、克隆或反序列化;

◆调用某个类的静态方法时;

◆使用某个类或接口的静态字段或对该字段赋值时(final字段除外);

◆调用Java的某些反射方法时;

◆初始化某个类的子类时;

◆在虚拟机启动时某个含有main()方法的那个启动类。

除了以上几种情形以外,所有其它使用JAVA类型的方式都是被动使用的,他们不会导致类的初始化。

我的问题究竟出在哪里

好了,了解了JVM的类初始化与对象初始化机制后,我们就有了理论基础,也就可以理性的去分析问题了。

下面让我们来看看前面[清单一]的JAVA源代码反组译出的字节码:

[清单三]

public class com.ccb.Framework.enums.CachingEnumResolver extendsjava.lang.Object{

 static {};

 Code: 0: new #2;

 //class CachingEnumResolver

 3: dup

 4: invokespecial #14;

 //Method "<init>":()V ①

 7: putstatic #16;

 //Field SINGLE_ENUM_RESOLVER:Lcom/ccb/framework/enums/CachingEnumResolver;

 10: new #18;

 //class HashMap ②

 13: dup

 14: invokespecial #19;

 //Method java/util/HashMap."<init>":()V

 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."<init>":()V 4: invokestatic #37;

 //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."<init>":()V ⑥ 21: putstatic #21;

 //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指令清单里。

现在,让我们对该类从类初始化到对象实例初始化全过程分析[清单一]中的代码执行轨迹。

    • 评论
    • 分享微博
    • 分享邮件
    邮件订阅

    如果您非常迫切的想了解IT领域最新产品与技术信息,那么订阅至顶网技术邮件将是您的最佳途径之一。

    重磅专题
    往期文章
    最新文章