这一篇主要针对最简单的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 ; .........
接下去开始分析每一个自己的含义:
- 0X CA FE BA BE 四个字节:表示魔数(magic),作用在于区分是否是class 文件;
- 0X 00 00 两个字节:表示此版本号(minor_version),
- 0X 00 2E 两个字节:表示主版本号(major_version),可以发现jdk 1.6.0_24 的主版本号为 46,
- 0X 00 1D 两个字节:表示常量池的个数(constant_pool_count),这里说明共有28个常量(要减1),常量池列表的索引从1开始,没有索引为0的常量,但是0索引也被计数在数量中,所有需要减1;接下去开始是常量池的信息了,还记得cp_info 的结构吗?第一个字节为tag,后面根据tag值不一样而不一样;
- 第一个常量: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();方法。
- 第二个常量: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
- 第三个常量:tag=0X 08, 为一个constant_String 类型(String 类型的字符串),根据它的定义后面的两个字节属于它,String_index=0X00 12,查看第18号常量池 为“hello world” 正是我们想要的输出的内容;
- 第四个常量: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;)方法。
- 第五个常量:tag=OX 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 15,查看第21号常量,为HelloWorld ,表示我们写的类HelloWorld;
- 第六个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 16,查看第22号常量,为 java/lang/Object ,表示object类;
- 第七个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 06 表示后面有6个字节属于它的内容:bytes=0X 3C 69 6E 69 74 3E 即是:<init>;由前面可以知道为object的intit方法;
- 第八个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 03 表示后面有3个字节属于它的内容:bytes=0X 28 29 56 即是: ()V;由前面可以知道,这个表示object的intit方法的描述符:表示没有参数,返回值为void;
- 第九个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 04 表示后面有4个字节属于它的内容:bytes=0X 43 6F 64 65 即是: Code,
- 第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 ;
- 第11个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 04表示后面有4个字节属于它的内容:bytes=0X 6D 61 69 6E 即是: main ;表示main()方法;
- 第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; 中的第一个[表示一维数组),
- 第13个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0A表示后面有10个字节属于它的内容:bytes=0X 53 6F 75 72 63 65 46 69 6C 65 即是: SourceFile ;
- 第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,可以知道这个是我们的文件名字;
- 第15个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 07,descriptor_index=00 08;由前面可以知道,这个是对object的intit方法的总体描述,包含名字和描述符;
- 第16个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 17,查看23号常量池,表示java/lang/System类;
- 第17个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 18,descriptor_index=00 19,由前面可以知道,这个是对 Ljava/io/PrintStream类型的out字段的描述;
- 第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,我们想要输出的常量
- 第19个常量:tag=0X 07,为一个constant_Class类型(对类或者接口的符号引用),根据它的定义后面的2个字节属于它,name_index=0X00 1A,查看26号常量池,表示java/io/PrintStream类;
- 第20个常量:tag=0X 0C,为一个constant_namdAndType类型(字段方法的部分符号引用),根据它的定义后面的4个字节属于它,name_index=0X00 1B,descriptor_index=00 1C,查看27、28号常量,是对println 方法的描述,表示返回值为void,参数为一个String;
- 第21个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 0A表示后面有10个字节属于它的内容:bytes=48 65 6C 6C 6F 57 6F 72 6C 64
即是: HelloWorld ;表示我们的类名
- 第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 ,
- 第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
- 第24个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 03表示后面有3个字节属于它的内容:bytes= 6F 75 74 即是:out
- 第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;
- 第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
- 第27个常量:tag=0X 01,为一个constant_UTF8类型(utf8编码的字符串),根据它的定义后面的长度可变,length=0X00 07表示后面有7个字节属于它的内容:bytes=00000116h: 70 72 69 6E 74 6C 6E 即是: println
- 第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,至此常量池的解析就结束了。
- 0X 00 21 两个字节: 表示 access_flags,这里为0x0021。根据access_flags表可以查到,该值是0x0020和0x0001两者的和,即该类的修饰符为ACC_PUBLIC+ACC_SUPER,前者表示该类是public类型,后者表示采用invokespecial指令特殊处理对超类的调用
- 0X 00 05 两个字节:表示this_class;它是一个对常量池表项的索引,指向5号常量池;查看5号常量池正是HelloWorld
- 0X 00 06 两个字节:表示 super_class:它也是一个对常量池表象的索引,指向6号常量池;表示为object类;
- 0X 00 00 两个字节:表示interfaces_count,表示直接实现或者该解决扩展的超接口为0个;没有实现任何接口
- 0X 00 00 两个字节:表示feild_count,表示该类没有申明字段;
- 0X 00 02 两个字节:表示method_count,表示该类申明了2个方法,接下去是这两个方法的相信信息
- 第一个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 的结构定义:
-
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个字节属于这个属性,这里不暂时不展开。
- 第二个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个字节属于这个属性,这里不暂时不展开。
- 去掉前面的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
相关推荐
public class HelloWorld implements Action { private String message; public String execute() { message = "Hello, World!\n"; message += "The time is:\n"; message += System.currentTimeMillis(); ...
每个class文件的结构遵循特定的规范,以确保JVM能够正确解读并加载。 1. **类文件结构**: - **魔数**:标识文件是否为合法的class文件,固定值0CAFEBABE。 - **版本号**:包括Minor和Major版本号,表示该class...
10. **示例**:创建名为`Hello.jar`的JAR包,包含`HelloWorld.class`类,并使用清单文件`manifest.mf`: ```sh jar cvfm Hello.jar manifest.mf HelloWorld.class ``` 11. **清单文件示例**:清单文件通常包含...
例如,`javac HelloWorld.java`会生成`HelloWorld.class`。然后,通过`java`命令运行程序,如`java HelloWorld`。实验还涉及了多包管理,创建了位于`a`包下的`A`类和`b`包下的`B`类,`B`类中实例化了`A`类的对象。 ...
通过java命令运行编译后的.class文件。 ```bash java HelloWorld ``` 3. Java与数据库的交互: - 使用JDBC进行数据库操作: JDBC(Java Database Connectivity)是一种技术,允许Java程序通过JDBC API连接和...
- 如果编译成功,则会在同一目录下生成`HelloWorld.class`文件。 - **运行程序**: - 输入`java HelloWorld`运行程序。 - 屏幕上将显示`Hello World`。 #### 五、Java基础语法要点 - **大小写敏感**:Java区分...
- **意义**:编译Java源代码文件,如果一切正常,会生成`HelloWorld.class`文件。 ##### 5.4 运行:`java HelloWorld` - **命令**:在终端中输入`java HelloWorld`。 - **意义**:运行编译后的Java程序,输出`...
- 编译Java程序:`javac HelloWorld.java`,这将生成一个`HelloWorld.class`字节码文件。 - 运行Java程序:`java HelloWorld`,这将在控制台打印出"hello,java!"。 6. **Applet程序** - Applet是能在网页中运行...
public class HelloWorld { public static void main(String[] args) { System.out.println("Hello, World!"); } } ``` 接下来,nmm15.com和nmm30com可能指的是两个不同的网站或者网络资源,或者是某种服务的...
<parameter name="ServiceClass">helloWorld ``` 这里有几个关键点: - `<service>` 标签定义了 Web 服务的基本属性。 - `name` 属性指定了服务的名称。 - `scope` 属性设为 `application` 表示这是一个应用...
* Class:每个 Java 文件应该包含类定义,例如:public class HelloWorld { ... }。 * Class Fields:每个 Java 文件应该包含类字段定义,例如:private int count;。 DEMO 简介 在中期开发平台中,我们提供了一个...
示例:javac HelloWorld.java ``` - **常见选项** - `-g`:生成完整的调试信息。 - `-g:none`:不生成任何调试信息。 - `-g:{lines,vars,source}`:仅生成特定类型的调试信息。 - `-nowarn`:忽略警告信息。...
public class HelloWorldApp { public static void main(String[] args) { System.out.println("Hello World!"); } } ``` 这一步骤演示了如何利用IDE提供的模板进行代码编写,是Java编程的基础实践之一。 #### ...
编译器会生成.class文件,它包含了程序的字节码,可以被Java虚拟机(JVM)执行。 在对“Hello, World!”程序代码进行逐行解读时,本部分向初学者介绍了System.out.println()方法,这是向标准输出流(通常是控制台)...
#### 标题理解:“一个简单的C#脚本示例,它会输出'Hello, World!'到控制台” 该标题介绍了一个基础的C#程序示例,用于输出经典的“Hello, World!”字符串到控制台。这通常作为学习任何编程语言的第一个程序,用于...
response.getWriter().println("Hello, World!"); } } ``` 记得在`web.xml`中注册这个Servlet: ```xml <servlet-name>HelloWorldServlet <servlet-class>...
<property name="message" value="Hello World!" /> ``` - **步骤二:定义前端控制器** 创建一个`DispatcherServlet`类,该类负责处理HTTP请求,并调用相应的控制器处理请求。 ```java public class ...