当前位置:首页 > 开发 > 编程语言 > 编程 > 正文

HelloWorld.class 文件的解读

发表于: 2011-07-04   作者:诸葛不亮   来源:转载   浏览次数:
摘要: 这一篇主要针对最简单的HelloWorld的class文件进行分析,按照上一篇文章的结构去实例化的分析一个class文件。 下面是java源文件     public class HelloWorld{ public static void main(String [] arvgs){ System.out.println("hello world

这一篇主要针对最简单的HelloWorld的class文件进行分析,按照上一篇文章的结构去实例化的分析一个class文件。

下面是java源文件

 

 

public class HelloWorld{
	public static void main(String [] arvgs){
	  System.out.println("hello world");
}
}

 

 运行 javac HelloWorld.java 得到的class 文件如下:

 

00000000h: CA FE BA BE 00 00 00 2E 00 1D 0A 00 06 00 0F 09 ; 漱壕............
00000010h: 00 10 00 11 08 00 12 0A 00 13 00 14 07 00 15 07 ; ................
00000020h: 00 16 01 00 06 3C 69 6E 69 74 3E 01 00 03 28 29 ; .....<init>...()
00000030h: 56 01 00 04 43 6F 64 65 01 00 0F 4C 69 6E 65 4E ; V...Code...LineN
00000040h: 75 6D 62 65 72 54 61 62 6C 65 01 00 04 6D 61 69 ; umberTable...mai
00000050h: 6E 01 00 16 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 ; n...([Ljava/lang
00000060h: 2F 53 74 72 69 6E 67 3B 29 56 01 00 0A 53 6F 75 ; /String;)V...Sou
00000070h: 72 63 65 46 69 6C 65 01 00 0F 48 65 6C 6C 6F 57 ; rceFile...HelloW
00000080h: 6F 72 6C 64 2E 6A 61 76 61 0C 00 07 00 08 07 00 ; orld.java.......
00000090h: 17 0C 00 18 00 19 01 00 0B 68 65 6C 6C 6F 20 77 ; .........hello w
000000a0h: 6F 72 6C 64 07 00 1A 0C 00 1B 00 1C 01 00 0A 48 ; orld...........H
000000b0h: 65 6C 6C 6F 57 6F 72 6C 64 01 00 10 6A 61 76 61 ; elloWorld...java
000000c0h: 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74 01 00 10 6A ; /lang/Object...j
000000d0h: 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D 01 ; ava/lang/System.
000000e0h: 00 03 6F 75 74 01 00 15 4C 6A 61 76 61 2F 69 6F ; ..out...Ljava/io
000000f0h: 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B 01 00 13 ; /PrintStream;...
00000100h: 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 ; java/io/PrintStr
00000110h: 65 61 6D 01 00 07 70 72 69 6E 74 6C 6E 01 00 15 ; eam...println...
00000120h: 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69 ; (Ljava/lang/Stri
00000130h: 6E 67 3B 29 56 00 21 00 05 00 06 00 00 00 00 00 ; ng;)V.!.........
00000140h: 02 00 01 00 07 00 08 00 01 00 09 00 00 00 1D 00 ; ................
00000150h: 01 00 01 00 00 00 05 2A B7 00 01 B1 00 00 00 01 ; .......*?.?...
00000160h: 00 0A 00 00 00 06 00 01 00 00 00 01 00 09 00 0B ; ................
00000170h: 00 0C 00 01 00 09 00 00 00 25 00 02 00 01 00 00 ; .........%......
00000180h: 00 09 B2 00 02 12 03 B6 00 04 B1 00 00 00 01 00 ; ..?...?.?....
00000190h: 0A 00 00 00 0A 00 02 00 00 00 03 00 08 00 04 00 ; ................
000001a0h: 01 00 0D 00 00 00 02 00 0E                      ; .........

 

 

接下去开始分析每一个自己的含义:

 

  1.  0X CA FE BA BE  四个字节:表示魔数(magic),作用在于区分是否是class 文件;
  2.  0X 00 00 两个字节:表示此版本号(minor_version),
  3.  0X 00 2E 两个字节:表示主版本号(major_version),可以发现jdk 1.6.0_24 的主版本号为 46,

  4.  0X 00 1D 两个字节:表示常量池的个数(constant_pool_count),这里说明共有28个常量(要减1),常量池列表的索引从1开始,没有索引为0的常量,但是0索引也被计数在数量中,所有需要减1;接下去开始是常量池的信息了,还记得cp_info 的结构吗?第一个字节为tag,后面根据tag值不一样而不一样;

  5. 第一个常量:tag=0X 0A 为一个 constant_methodref 类型(对一个类中申明的方法的符号引用),根据它的定义,后面四个字节属于它,class_index=0X00 06,name_and_type_index=0X00 0F ; 
         (1)、首先看class_index,顾名思义,表示这个方法所属于的类在常量池中的索引,查看第6号常量池,是一个constant_class,正是我们想要的,根据constant_class的定义;跟踪到22号常量池,可以看到这个方法属于Object类;
          (2)、第二个name_and_type_index:表示这个方法所对应的name_and_type类型在常量池中的索引;查看第15号常量池,正好是我们需要的constant_namdAndType类型的定义,继续查看constant_namdAndType的定义,发现名字和描述符,分别指向第7号和8号常量池,即 void init();方法。

  6. 第二个常量:tag=0X 09为一个constant_Fieldref 类型(对一个字段的符号的引用),根据它的定义后面四个字节属于它,class_index=0X00 10 , name_and_type_index = 0X 00 11
         (1)、同样先看class_index:表示这个字段所属的类,跟踪到16号常量池为constant_Class类型,并且指向第23号常量池,看23号常量池,表示这个字段属于 java/lang/System方法;
         (2)、name_and_type_index :表示name_and_type类型在常量池中的索引;查看17号常量池为constant_namdAndType类型,指向24、25号常量,表示字段名字为out,类型为 Ljava/io/PrintStream
     
  7. 第三个常量:tag=0X 08, 为一个constant_String 类型(String 类型的字符串),根据它的定义后面的两个字节属于它,String_index=0X00 12,查看第18号常量池 为“hello world” 正是我们想要的输出的内容;

  8. 第四个常量:tag=0X 0A, 为一个 constant_methodref 类型(对一个类中申明的方法的符号引用),根据它的定义,后面四个字节属于它,class_index=0X00 13,name_and_type_index=0X00 14
         (1)、首先看class_index,顾名思义,表示这个方法所属于的类在常量池中的索引,查看第19号常量池,是一个constant_class,正是我们想要的,根据constant_class的定义;跟踪到26号常量池,可以看到这个方法属于java/io/PrintStream类;
          (2)、第二个name_and_type_index:表示这个方法所对应的name_and_type类型在常量池中的索引;查看第20号常量池,正好是我们需要的constant_namdAndType类型的定义,继续查看constant_namdAndType的定义,发现名字和描述符,分别指向第27号和28号常量池,即 void println( (Ljava/lang/String;)方法。

  9. 第五个常量:tag=OX 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 15,查看第21号常量,为HelloWorld ,表示我们写的类HelloWorld;

  10. 第六个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 16,查看第22号常量,为 java/lang/Object ,表示object类;

  11. 第七个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 06 表示后面有6个字节属于它的内容:bytes=0X 3C 69 6E 69 74  3E 即是:<init>;由前面可以知道为object的intit方法;

  12. 第八个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 03 表示后面有3个字节属于它的内容:bytes=0X 28 29 56  即是: ()V;由前面可以知道,这个表示object的intit方法的描述符:表示没有参数,返回值为void;

  13. 第九个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 04 表示后面有4个字节属于它的内容:bytes=0X  43 6F 64 65  即是: Code, 

  14. 第10个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0F 表示后面有15个字节属于它的内容:bytes=0X 4C 69 6E 65 4E 75 6D 62 65 72 54 61 62 6C 65  即是: LineNumberTable  ; 

  15. 第11个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 04表示后面有4个字节属于它的内容:bytes=0X 6D 61 69 6E 即是: main ;表示main()方法;

  16. 第12个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 16表示后面有22个字节属于它的内容:bytes=0X 28 5B 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72  69 6E 67 3B 29 56   即是:  ([Ljava/lang/String;)V;有前面可以这个这个表示main方法的描述符,即返回值为void,参数为 string[] ([Ljava/lang/String; 中的第一个[表示一维数组),

  17. 第13个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0A表示后面有10个字节属于它的内容:bytes=0X 53 6F 75 72 63 65 46 69 6C 65              即是: SourceFile ;

  18. 第14个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0F表示后面有15个字节属于它的内容:bytes=0X  48 65 6C 6C 6F 57 6F 72 6C 64 2E 6A 61 76 61  即是: HelloWorld.java,可以知道这个是我们的文件名字;

  19. 第15个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 07,descriptor_index=00 08;由前面可以知道,这个是对object的intit方法的总体描述,包含名字和描述符;

  20. 第16个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 17,查看23号常量池,表示java/lang/System类;

  21. 第17个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 18,descriptor_index=00 19,由前面可以知道,这个是对 Ljava/io/PrintStream类型的out字段的描述;

  22. 第18个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0B表示后面有11个字节属于它的内容:bytes=0X 68 65 6C 6C 6F 20 77 6F 72 6C 64         即是: hello world,我们想要输出的常量

  23. 第19个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 1A,查看26号常量池,表示java/io/PrintStream类;

  24. 第20个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 1B,descriptor_index=00 1C,查看27、28号常量,是对println  方法的描述,表示返回值为void,参数为一个String;

  25. 第21个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0A表示后面有10个字节属于它的内容:bytes=48 65 6C 6C 6F 57 6F 72 6C 64  
     即是: HelloWorld ;表示我们的类名
           
  26. 第22个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 10表示后面有16个字节属于它的内容:bytes= 6A 61 76 61 2F 6C 61 6E 67 2F 4F 62 6A 65 63 74  即是:  java/lang/Object , 

  27. 第23个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 10表示后面有16个字节属于它的内容:bytes=  6A 61 76 61 2F 6C 61 6E 67 2F 53 79 73 74 65 6D  即是:  java/lang/System

  28. 第24个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 03表示后面有3个字节属于它的内容:bytes=   6F 75 74    即是:out 

  29. 第25个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 15表示后面有21个字节属于它的内容:bytes=  4C 6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72 65 61 6D 3B    即是: Ljava/io/PrintStream;

  30. 第26个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 13表示后面有19个字节属于它的内容:bytes=6A 61 76 61 2F 69 6F 2F 50 72 69 6E 74 53 74 72  65 61 6D    即是:  java/io/PrintStream

  31. 第27个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 07表示后面有7个字节属于它的内容:bytes=00000116h: 70 72 69 6E 74 6C 6E   即是: println   

  32. 第28个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 15表示后面有7个字节属于它的内容:bytes= 28 4C 6A 61 76 61 2F 6C 61 6E 67 2F 53 74 72 69  6E 67 3B 29 56 即是:  (Ljava/lang/String;)V,至此常量池的解析就结束了。

  33. 0X 00 21 两个字节: 表示 access_flags,这里为0x0021。根据access_flags表可以查到,该值是0x00200x0001两者的和,即该类的修饰符为ACC_PUBLIC+ACC_SUPER,前者表示该类是public类型,后者表示采用invokespecial指令特殊处理对超类的调用

  34. 0X 00 05 两个字节:表示this_class;它是一个对常量池表项的索引,指向5号常量池;查看5号常量池正是HelloWorld

  35.  0X 00 06 两个字节:表示 super_class:它也是一个对常量池表象的索引,指向6号常量池;表示为object类;

  36. 0X 00 00 两个字节:表示interfaces_count,表示直接实现或者该解决扩展的超接口为0个;没有实现任何接口

  37. 0X 00 00 两个字节:表示feild_count,表示该类没有申明字段;

  38. 0X 00 02 两个字节:表示method_count,表示该类申明了2个方法,接下去是这两个方法的相信信息

  39. 第一个method_info的结构:根据上一章节的内容,接下去的2个字节表示
     (1)、access_flags=0X 00 01,表示是一个ACC_PUBLIC 的方法,
     (2)、在两个字节0X 00 07 表示 name_index,表示常量池中第7个常量为<init>,即是 <init>方法,
     (3)、在接下两个字节 0X00 08 表示desciptor_index,表示常量池第8个常量为 ()V ,即是没有参数,返回值为void;,
     (4)、在接下去两个字节0X 00 01 表示attribute_count,表示有1个attribute,
     (5)、接下去表示一个attribute_info 的结构;查看attribute_info 的结构定义:

  40. attribute_info {        
     u2 attribute_name_index;
     u4 attribute_length;
     u1 info[attribute_length];
        }
       1)、所以 在接下去的两个字节 0X 00 09,查看第9好常量池为Code,然后code_attribute的定义:


    Code_attribute {        
            u2 attribute_name_index;
             u4 attribute_length;
             u2 max_stack;
             u2 max_locals;
             u4 code_length;
             u1 code[code_length];
             u2 exception_table_length;
             {       u2 start_pc;
                    u2 end_pc;
                    u2 handler_pc;
                    u2 catch_type;
             }       exception_table[exception_table_length];
             u2 attributes_count;
             attribute_info attributes[attributes_count];
        }
         
    在看这个结构体 attribute_name_index =0X 00 09,然后4个字节0X 00 00 00 1D表示长度 为29个字节说明接下去的29个字节属于这个属性,这里不暂时不展开。 

  41. 第二个method_info的结构:去掉前面的29个字节,
    (1)、接下去的2个字节表示access_flags=0X 00 09,表示是一个ACC_PUBLIC和ACC_STATIC 的方法,
    (2)、在两个字节0X 00 0B表示 name_index,表示常量池中第11个常量为main ,即是 main 方法,
    (3)、在接下两个字节 0X00 0C 表示desciptor_index,表示常量池第12个常量为([Ljava/lang/Str ing;)V,即是参数为String [],返回值为void;
    (4)、在接下去两个字节0X 00 01 表示attribute_count,表示有1个attribute,索引接下去表示一个attribute_info 的结构;所有查看attribute_info 的结构定义:
     
    attribute_info {        
     u2 attribute_name_index;
     u4 attribute_length;
     u1 info[attribute_length];
        }
     1)、所以 在接下去的两个字节 0X 00 09,查看第9好常量池为Code,然后code_attribute的定义:

    Code_attribute {
             u2 attribute_name_index;
             u4 attribute_length;
             u2 max_stack;
             u2 max_locals;
             u4 code_length;
             u1 code[code_length];
             u2 exception_table_length;
             {       u2 start_pc;
                    u2 end_pc;
                    u2 handler_pc;
                    u2 catch_type;
             }       exception_table[exception_table_length];
             u2 attributes_count;
             attribute_info attributes[attributes_count];
        }
     在看这个结构体 attribute_name_index =0X 00 09,然后4个字节0X 00 00 00 25表示长度 为37个字节说明接下去的37个字节属于这个属性,这里不暂时不展开。


  42. 去掉前面的37个字节,接下去的两个字节0X 00 01 表示接下去有一个attributes_info结构,参照前面的定义,(1)、0X 00 0D表示 attribute_name_index,13号常量为 SourceFile,表示属性名字为SourceFile; 该属性是一个可选的定长属性,并且在class文件中只有一个sourcefile_atrribute存在,对于给定的ClassFile结构的attributes列表中不能有多于一的SourceFile属性;查阅SourceFile_attribute表可知,
    sourceFile_attribute{
       U2  attribute_name_index ;
       U4  attribute_length;
       U2   sourcefile_index;
    }
     
     (1)、下面的
    4个字节为attribute_length项,其值为0x00 00 00 02,它表示在该项后面还有2个字节的信息,这个长度永远为2。
      (2)、根据SourceFile_attribute表,最后的这两个字节是sourcefile_index项,该项的值是一个对CONSTANT_Utf8_info结构的常量池表项的索引,其信息表示的是该Class文件的源文件名称。在这里值为0x00 0E,14号常量池表项存储的信息可解析为“HelloWorld.java”,这是该Class文件的源文件名称(不包括路径)

到此整个 HelloWord.class 解析结束。。下一节。我们将通过几个例子说明怎么利用读懂的class文件的格式。

 

 

本站支持 pay for your wishes

HelloWorld.class 文件的解读

  • 0

    开心

    开心

  • 0

    板砖

    板砖

  • 0

    感动

    感动

  • 0

    有用

    有用

  • 0

    疑问

    疑问

  • 0

    难过

    难过

  • 0

    无聊

    无聊

  • 0

    震惊

    震惊

编辑推荐
Windows平台内开发操作系统,在用Cygwin版的GCC编译源文件是遇到这样一个问题,如果使用gcc –c boo
1.目的 大型软件系统开发时,某些Java组件可能涉及到多种数据库或中间件系统的连接和应用,例如一
1.目的 大型软件系统开发时,某些Java组件可能涉及到多种数据库或中间件系统的连接和应用,例如一
1.目的 大型软件系统开发时,某些Java组件可能涉及到多种数据库或中间件系统的连接和应用,例如一
1.启动一个WEB项目的时候,容器(如:Tomcat)会去读它的配置文件web.xml.读两个节点: <listener>
要研究mysql,最好的资源莫过于源码了,所以本人打算通过调试源码的方式来深入理解mysql的点点滴滴
以下内容源于对 PEP-0263 的翻译和解读,同时给出了一些网上网友的说法。 ======== 我是分割线 ====
转自:http://xdang.org/post-602.html 以下原文: 反编译 — 在apk文件中能得到什么 最近在做andro
MVP MVP 是一种广泛使用的UI 架构模式,适用于基于事件驱动的应用框架,比如ASP.NET Web Forms 和Wi
目的: 程序分析:用于分析程序,动态生成proxy等。 程序生成:可在内存中生成java类并编译,所谓的ju
版权所有 IT知识库 CopyRight © 2009-2015 IT知识库 IT610.com , All Rights Reserved. 京ICP备09083238号