最近在研究Java的字节码,花了点时间分析了一段十分简单的代码生成的class文件.
首先是代码:
package com.agpalace.article.java.bytecode.chapter1;
/**
* Created by dengming on 17/3/30.
*/
public class HelloWorld {
public static void main(String arg[]){
String helloWorld="Hello, world";
System.out.println(helloWorld);
}
}
这个就是Java程序员入门的程序HelloWorld。
使用javap命令,加上-verbose选项反解析得到:
/Library/Java/JavaVirtualMachines/jdk1.8.0_91.jdk/Contents/Home/bin/javap -verbose -c com.agpalace.article.java.bytecode.chapter1.HelloWorld
Classfile /Users/dengming/git/JavaBytecode/target/classes/com/agpalace/article/java/bytecode/chapter1/HelloWorld.class
Last modified 2017-3-30; size 670 bytes
MD5 checksum 16c016889ca99530664fba1fbebd6aec
Compiled from "HelloWorld.java"
public class com.agpalace.article.java.bytecode.chapter1.HelloWorld
minor version: 0
major version: 49
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#22 // java/lang/Object."<init>":()V
#2 = String #23 // Hello, world
#3 = Fieldref #24.#25 // java/lang/System.out:Ljava/io/PrintStream;
#4 = Methodref #26.#27 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #28 // com/agpalace/article/java/bytecode/chapter1/HelloWorld
#6 = Class #29 // java/lang/Object
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/agpalace/article/java/bytecode/chapter1/HelloWorld;
#14 = Utf8 main
#15 = Utf8 ([Ljava/lang/String;)V
#16 = Utf8 arg
#17 = Utf8 [Ljava/lang/String;
#18 = Utf8 helloword
#19 = Utf8 Ljava/lang/String;
#20 = Utf8 SourceFile
#21 = Utf8 HelloWorld.java
#22 = NameAndType #7:#8 // "<init>":()V
#23 = Utf8 Hello, world
#24 = Class #30 // java/lang/System
#25 = NameAndType #31:#32 // out:Ljava/io/PrintStream;
#26 = Class #33 // java/io/PrintStream
#27 = NameAndType #34:#35 // println:(Ljava/lang/String;)V
#28 = Utf8 com/agpalace/article/java/bytecode/chapter1/HelloWorld
#29 = Utf8 java/lang/Object
#30 = Utf8 java/lang/System
#31 = Utf8 out
#32 = Utf8 Ljava/io/PrintStream;
#33 = Utf8 java/io/PrintStream
#34 = Utf8 println
#35 = Utf8 (Ljava/lang/String;)V
{
public com.agpalace.article.java.bytecode.chapter1.HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 6: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/agpalace/article/java/bytecode/chapter1/HelloWorld;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=2, args_size=1
0: ldc #2 // String Hello, world
2: astore_1
3: getstatic #3 // Field java/lang/System.out:Ljava/io/PrintStream;
6: aload_1
7: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
10: return
LineNumberTable:
line 9: 0
line 10: 3
line 11: 10
LocalVariableTable:
Start Length Slot Name Signature
0 11 0 arg [Ljava/lang/String;
3 8 1 helloword Ljava/lang/String;
}
SourceFile: "HelloWorld.java"
Process finished with exit code 0
用文本编辑器打开class文件,其二进制内容是:
cafe babe 0000 0031 0024 0a00 0600 1608
0017 0900 1800 190a 001a 001b 0700 1c07
001d 0100 063c 696e 6974 3e01 0003 2829
5601 0004 436f 6465 0100 0f4c 696e 654e
756d 6265 7254 6162 6c65 0100 124c 6f63
616c 5661 7269 6162 6c65 5461 626c 6501
0004 7468 6973 0100 384c 636f 6d2f 6167
7061 6c61 6365 2f61 7274 6963 6c65 2f6a
6176 612f 6279 7465 636f 6465 2f63 6861
7074 6572 312f 4865 6c6c 6f57 6f72 6c64
3b01 0004 6d61 696e 0100 1628 5b4c 6a61
7661 2f6c 616e 672f 5374 7269 6e67 3b29
5601 0003 6172 6701 0013 5b4c 6a61 7661
2f6c 616e 672f 5374 7269 6e67 3b01 0009
6865 6c6c 6f77 6f72 6401 0012 4c6a 6176
612f 6c61 6e67 2f53 7472 696e 673b 0100
0a53 6f75 7263 6546 696c 6501 000f 4865
6c6c 6f57 6f72 6c64 2e6a 6176 610c 0007
0008 0100 0c48 656c 6c6f 2c20 776f 726c
6407 001e 0c00 1f00 2007 0021 0c00 2200
2301 0036 636f 6d2f 6167 7061 6c61 6365
2f61 7274 6963 6c65 2f6a 6176 612f 6279
7465 636f 6465 2f63 6861 7074 6572 312f
4865 6c6c 6f57 6f72 6c64 0100 106a 6176
612f 6c61 6e67 2f4f 626a 6563 7401 0010
6a61 7661 2f6c 616e 672f 5379 7374 656d
0100 036f 7574 0100 154c 6a61 7661 2f69
6f2f 5072 696e 7453 7472 6561 6d3b 0100
136a 6176 612f 696f 2f50 7269 6e74 5374
7265 616d 0100 0770 7269 6e74 6c6e 0100
1528 4c6a 6176 612f 6c61 6e67 2f53 7472
696e 673b 2956 0021 0005 0006 0000 0000
0002 0001 0007 0008 0001 0009 0000 002f
0001 0001 0000 0005 2ab7 0001 b100 0000
0200 0a00 0000 0600 0100 0000 0600 0b00
0000 0c00 0100 0000 0500 0c00 0d00 0000
0900 0e00 0f00 0100 0900 0000 4700 0200
0200 0000 0b12 024c b200 032b b600 04b1
0000 0002 000a 0000 000e 0003 0000 0009
0003 000a 000a 000b 000b 0000 0016 0002
0000 000b 0010 0011 0000 0003 0008 0012
0013 0001 0001 0014 0000 0002 0015
我所解析的内容就是这段二进制文件,将它与javap命令解析得到的内容一一对应起来。
解析结果为:
cafe babe --magic
0000 0031 --minor_version major_version
----------constants_pool---------------------
0024 --constants_pool_count
0a 0006 0016 --#1=Methodref #6.#22
08 0017 --#2=String #23
09 0018 0019 --#3=Fieldref #24.#25
0a 001a 001b --#4=Methodref #26.#27
07 001c --#5=Class #28
07 001d --#6=Class #29
01 0006 3c69 6e69 743e --#7=Utf-8 <init>
01 0003 2829 56 --#8=Utf-8 ()V
01 0004 436f 6465 --#9=Utf-9 Code
01 000f 4c69 6e65 4e75 6d62 6572 5461 626c 65 --#10=Utf8 LineNumberTable
01 0012 4c6f 6361 6c56 6172 6961 626c 6554 6162 6c65 --#11=Utf8 LocalVariableTable
01 0004 7468 6973 --#12=Utf8 this
01 0038 4c63 6f6d 2f61 6770 616c 6163 652f 6172 7469 636c
652f 6a61 7661 2f62 7974 6563 6f64 652f 6368 6170 7465 7231 2f48 656c 6c6f 576f 726c 643b --#13=Utf8 Lcom/agpalace/article/java/bytecode/chapter1/HelloWorld;
01 0004 6d61 696e --#14=Utf8 main
01 0016 285b 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 2956 --#15=Utf8 ([Ljava/lang/String;)V
01 0003 6172 67 --#16=Utf8 arg
01 0013 5b4c 6a61 7661 2f6c 616e 672f 5374 7269 6e67 3b --#17=Utf8 [Ljava/lang/String;
01 0009 6865 6c6c 6f77 6f72 64 --#18=Utf8 helloworld
01 0012 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b --#19=Utf8 Ljava/lang/String;
01 000a 536f 7572 6365 4669 6c65 --#20=Utf8 SourceFile
01 000f 4865 6c6c 6f57 6f72 6c64 2e6a 6176 61 #21=Utf8 HelloWorld.java
0c 0007 0008 --#22=NameAndType #7:#8
01 000c 4865 6c6c 6f2c 2077 6f72 6c64 --#23=Utf8 Hello,world
07 001e --#24=Class #30
0c 001f 0020 --#25=NameAndType #31:#32
07 0021 --#26=Class #33
0c 0022 0023 --#27=NameAndType #34:#35
01 0036 636f 6d2f 6167 7061 6c61 6365 2f61 7274 6963 6c65 2f6a 6176 612f 6279
7465 636f 6465 2f63 6861 7074 6572 312f 4865 6c6c 6f57 6f72 6c64 --#28=Utf8 com/agpalace/article/java/bytecode/chapter1/HelloWorld
01 0010 6a61 7661 2f6c 616e 672f 4f62 6a65 6374 --#29=Utf8 java/lang/Object
01 0010 6a61 7661 2f6c 616e 672f 5379 7374 656d --#30=Utf8 java/lang/System
01 0003 6f75 74 --#31=Utf8 out
01 0015 4c6a 6176 612f 696f 2f50 7269 6e74 5374 7265 616d 3b --#32=Utf8 Ljava/io/PrintStream;
01 0013 6a6176 612f 696f 2f50 7269 6e74 5374 7265 616d --#33=Utf8 java/io/PrintStream
01 0007 7072 696e 746c 6e #34=Utf8 println
01 0015 284c 6a61 7661 2f6c 616e 672f 5374 7269 6e67 3b29 56 --#35=Utf8 (Ljava/lang/String;)V
-------------constants_pool end--------------------
0021 --access_flag ACC_PUBLIC ACC_SUPER
0005 --this_class #5
0006 --super_class #6
0000 --interfaces_count=0
0000 --fields_count=0
----method_info----------------------------------------------------
0002 --methods_count=2
0001 0007 0008 0001 --public <init> ()V attribute_count=1
0009 0000 002f --Code attribute_length=0x2f
0001 0001 0000 0005 --max_stack=1 max_locals=1 code_length=0x5
2ab7 0001 b1 --code
0000 --exception_table_length=0
0002 --attribute_count=0x2
000a --LineNumberTable
0000 0006 --attribute_length=6 (excluding the initial six bytes)
0001 --line_number_table_length=1
0000 0006 --start_pc=0 lineNumber=6
000b --LocalVariableTable
0000 000c --attribute_length=12
0001 --local_variable_table_length=1
0000 0005 000c 000d 0000 --start_pc=0 length=0x5 this Lcom/agpalace/article/java/bytecode/chapter1/HelloWorld index=0
0009 --public static
000e 000f --main ([Ljava/lang/String;)V
0001 --attribute_count=1
0009 0000 0047 --Code attribute_length=0x47
0002 0002 0000 000b --max_stack=2 max_locals=2 code_length=0xb
1202 4cb2 0003 2bb6 0004 b1 --code
0000 --exception_table_length=0
0002 --attribute_count=0x2
000a --LineNumberTable
0000 000e --attribute_length=0xe (excluding the initial six bytes)
0003 --line_number_table_length=0x3
0000 0009 --start_pc=0 lineNumber=9
0003 000a --start_pc=3 lineNumber=10
000a 000b --start_pc=10 lineNumber=11
000b --LocalVariableTable
0000 0016 --attribute_length=0x16
0002 --local_variable_table_length=0x2
0000 000b 0010 0011 0000 --start_pc=0 length=0xb arg [Ljava/lang/String; index=0
0003 0008 0012 0013 0001 --start_pc=3 length=0x8 helloWorld Ljava/lang/String; index=1
----------method_info end ------------------------------------------
0001 --attributes_count=1
0014 --Sourcefile
0000 0002 --attribute_length=0x2
0015 -- HelloWorld.java
Java的class文件结构可以参考《Java Virtual Machine Specification SE8》,或者参考实例分析Java Class的文件结构。