一、类文件结构概述
计算机只识0和1
代码编译的结果从本地机器码到字节码是一个很重大意义的转变。
文件的数据项
把上面的文件数据项转化成图如下:
主次版本号
常量池:
包含两大类常量:字面量(Literal)和符号引用(Symbolic References)
字面量包括:文本字符串,声明为final的常量值等
符号引用(编译原理方面概念):
类和接口的全限定名(Fully Qualified Name)
字段的名称和描述符(Descriptor)
方法的名称和描述符
常量在存储的时候常量表
二、获取class文件示例一下
这里是在windows环境下打开CMD,到JDK安装目录下执行命令
使用javap -verbose Test(备注.class文件) 看不到所有内容
用法: javap <options> <classes>
其中, 可能的选项包括:
-help --help -? 输出此用法消息
-version 版本信息
-v -verbose 输出附加信息
-l 输出行号和本地变量表
-public 仅显示公共类和成员
-protected 显示受保护的/公共类和成员
-package 显示程序包/受保护的/公共类
和成员 (默认)
-p -private 显示所有类和成员
-c 对代码进行反汇编
-s 输出内部类型签名
-sysinfo 显示正在处理的类的
系统信息 (路径, 大小, 日期, MD5 散列)
-constants 显示最终常量
-classpath <path> 指定查找用户类文件的位置
-cp <path> 指定查找用户类文件的位置
-bootclasspath <path> 覆盖引导类文件的位置
改下命令输出到文件中
我们现在可以打开其中一个看下内容如下,想要看懂的话还需要参照常量池中的14种常量项的结构总表
常量池中的14种常量项的结构总表
三、开始进入学习
先看下我们打开的demo文件整体结构图(常量池和内容信息也在字节码文件信息中由于特殊内容比较多,所以单独拉出来)
原始文件打开如下解析:
Classfile /D:/JD_SoftInstaller/RD_softInstaller/JDK/bin/Test.class
Last modified 2019-1-18; size 2889 bytes
MD5 checksum 6242eda79aea8128ea49a2dd0652454e
Compiled from "Test.java"
public class test.Test
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #46.#93 // java/lang/Object."<init>":()V
#2 = Class #94 // java/io/File
#3 = String #95 // C:\Users\XXXXXX\Desktop\dbData\goodsExtListUpdate.txt
#4 = Methodref #2.#96 // java/io/File."<init>":(Ljava/lang/String;)V
#5 = Methodref #2.#97 // java/io/File.createNewFile:()Z
#6 = Class #98 // java/io/BufferedWriter
#7 = Class #99 // java/io/FileWriter
#8 = Methodref #7.#100 // java/io/FileWriter."<init>":(Ljava/io/File;)V
#9 = Methodref #6.#101 // java/io/BufferedWriter."<init>":(Ljava/io/Writer;)V
#10 = Methodref #45.#102 // test/Test.readAndWrite:(ILjava/io/BufferedWriter;)V
#11 = Class #103 // java/lang/Exception
#12 = Methodref #6.#104 // java/io/BufferedWriter.flush:()V
#13 = Methodref #6.#105 // java/io/BufferedWriter.close:()V
#14 = String #106 // C:\Users\XXXXXX\Desktop\dbData\goodsExtList.txt
#15 = Class #107 // java/io/InputStreamReader
#16 = Class #108 // java/io/FileInputStream
#17 = Methodref #16.#100 // java/io/FileInputStream."<init>":(Ljava/io/File;)V
#18 = String #109 // GBK
#19 = Methodref #15.#110 // java/io/InputStreamReader."<init>":(Ljava/io/InputStream;Ljava/lang/String;)V
#20 = Class #111 // java/io/BufferedReader
#21 = Methodref #20.#112 // java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
#22 = String #113 //
#23 = Methodref #20.#114 // java/io/BufferedReader.readLine:()Ljava/lang/String;
#24 = Class #115 // java/lang/String
#25 = Methodref #24.#116 // java/lang/String.getBytes:(Ljava/lang/String;)[B
#26 = Methodref #24.#117 // java/lang/String."<init>":([BLjava/lang/String;)V
#27 = String #118 // hash
#28 = Methodref #24.#119 // java/lang/String.contains:(Ljava/lang/CharSequence;)Z
#29 = String #120 // CREATE TABLE `gold_pocket_goods_ext0` (
#30 = Class #121 // java/lang/StringBuilder
#31 = Methodref #30.#93 // java/lang/StringBuilder."<init>":()V
#32 = Methodref #30.#122 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#33 = String #123 // \n
#34 = Methodref #30.#124 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#35 = Methodref #6.#125 // java/io/BufferedWriter.write:(Ljava/lang/String;)V
#36 = String #126 // set @sharding = 'gold_pocket_goods_ext
#37 = Methodref #30.#127 // java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
#38 = String #128 // ID hash ' ;
#39 = Fieldref #129.#130 // java/lang/System.out:Ljava/io/PrintStream;
#40 = Methodref #131.#132 // java/io/PrintStream.println:(Ljava/lang/String;)V
#41 = String #133 // CREATE TABLE `gold_pocket_goods_ext
#42 = String #134 // ` (
#43 = Class #135 // java/lang/NullPointerException
#44 = Methodref #43.#93 // java/lang/NullPointerException."<init>":()V
#45 = Class #136 // test/Test
#46 = Class #137 // java/lang/Object
#47 = Utf8 <init>
#48 = Utf8 ()V
#49 = Utf8 Code
#50 = Utf8 LineNumberTable
#51 = Utf8 LocalVariableTable
#52 = Utf8 this
#53 = Utf8 Ltest/Test;
#54 = Utf8 main
#55 = Utf8 ([Ljava/lang/String;)V
#56 = Utf8 e
#57 = Utf8 Ljava/lang/Exception;
#58 = Utf8 args
#59 = Utf8 [Ljava/lang/String;
#60 = Utf8 writename
#61 = Utf8 Ljava/io/File;
#62 = Utf8 out
#63 = Utf8 Ljava/io/BufferedWriter;
#64 = Utf8 StackMapTable
#65 = Class #59 // "[Ljava/lang/String;"
#66 = Class #94 // java/io/File
#67 = Class #98 // java/io/BufferedWriter
#68 = Class #103 // java/lang/Exception
#69 = Utf8 Exceptions
#70 = Class #138 // java/io/IOException
#71 = Utf8 readAndWrite
#72 = Utf8 (ILjava/io/BufferedWriter;)V
#73 = Utf8 pathname
#74 = Utf8 Ljava/lang/String;
#75 = Utf8 filename
#76 = Utf8 reader
#77 = Utf8 Ljava/io/InputStreamReader;
#78 = Utf8 br
#79 = Utf8 Ljava/io/BufferedReader;
#80 = Utf8 line
#81 = Utf8 nullPoint
#82 = Utf8 Ljava/lang/NullPointerException;
#83 = Utf8 i
#84 = Utf8 I
#85 = Class #115 // java/lang/String
#86 = Class #107 // java/io/InputStreamReader
#87 = Class #111 // java/io/BufferedReader
#88 = Class #135 // java/lang/NullPointerException
#89 = Class #139 // java/io/FileNotFoundException
#90 = Class #140 // java/io/UnsupportedEncodingException
#91 = Utf8 SourceFile
#92 = Utf8 Test.java
#93 = NameAndType #47:#48 // "<init>":()V
#94 = Utf8 java/io/File
#95 = Utf8 C:\Users\XXXXXX\Desktop\dbData\goodsExtListUpdate.txt
#96 = NameAndType #47:#141 // "<init>":(Ljava/lang/String;)V
#97 = NameAndType #142:#143 // createNewFile:()Z
#98 = Utf8 java/io/BufferedWriter
#99 = Utf8 java/io/FileWriter
#100 = NameAndType #47:#144 // "<init>":(Ljava/io/File;)V
#101 = NameAndType #47:#145 // "<init>":(Ljava/io/Writer;)V
#102 = NameAndType #71:#72 // readAndWrite:(ILjava/io/BufferedWriter;)V
#103 = Utf8 java/lang/Exception
#104 = NameAndType #146:#48 // flush:()V
#105 = NameAndType #147:#48 // close:()V
#106 = Utf8 C:\Users\XXXX\Desktop\dbData\goodsExtList.txt
#107 = Utf8 java/io/InputStreamReader
#108 = Utf8 java/io/FileInputStream
#109 = Utf8 GBK
#110 = NameAndType #47:#148 // "<init>":(Ljava/io/InputStream;Ljava/lang/String;)V
#111 = Utf8 java/io/BufferedReader
#112 = NameAndType #47:#149 // "<init>":(Ljava/io/Reader;)V
#113 = Utf8
#114 = NameAndType #150:#151 // readLine:()Ljava/lang/String;
#115 = Utf8 java/lang/String
#116 = NameAndType #152:#153 // getBytes:(Ljava/lang/String;)[B
#117 = NameAndType #47:#154 // "<init>":([BLjava/lang/String;)V
#118 = Utf8 hash
#119 = NameAndType #155:#156 // contains:(Ljava/lang/CharSequence;)Z
#120 = Utf8 CREATE TABLE `gold_pocket_goods_ext0` (
#121 = Utf8 java/lang/StringBuilder
#122 = NameAndType #157:#158 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#123 = Utf8 \n
#124 = NameAndType #159:#151 // toString:()Ljava/lang/String;
#125 = NameAndType #160:#141 // write:(Ljava/lang/String;)V
#126 = Utf8 set @sharding = 'gold_pocket_goods_ext
#127 = NameAndType #157:#161 // append:(I)Ljava/lang/StringBuilder;
#128 = Utf8 ID hash ' ;
#129 = Class #162 // java/lang/System
#130 = NameAndType #62:#163 // out:Ljava/io/PrintStream;
#131 = Class #164 // java/io/PrintStream
#132 = NameAndType #165:#141 // println:(Ljava/lang/String;)V
#133 = Utf8 CREATE TABLE `gold_pocket_goods_ext
#134 = Utf8 ` (
#135 = Utf8 java/lang/NullPointerException
#136 = Utf8 test/Test
#137 = Utf8 java/lang/Object
#138 = Utf8 java/io/IOException
#139 = Utf8 java/io/FileNotFoundException
#140 = Utf8 java/io/UnsupportedEncodingException
#141 = Utf8 (Ljava/lang/String;)V
#142 = Utf8 createNewFile
#143 = Utf8 ()Z
#144 = Utf8 (Ljava/io/File;)V
#145 = Utf8 (Ljava/io/Writer;)V
#146 = Utf8 flush
#147 = Utf8 close
#148 = Utf8 (Ljava/io/InputStream;Ljava/lang/String;)V
#149 = Utf8 (Ljava/io/Reader;)V
#150 = Utf8 readLine
#151 = Utf8 ()Ljava/lang/String;
#152 = Utf8 getBytes
#153 = Utf8 (Ljava/lang/String;)[B
#154 = Utf8 ([BLjava/lang/String;)V
#155 = Utf8 contains
#156 = Utf8 (Ljava/lang/CharSequence;)Z
#157 = Utf8 append
#158 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#159 = Utf8 toString
#160 = Utf8 write
#161 = Utf8 (I)Ljava/lang/StringBuilder;
#162 = Utf8 java/lang/System
#163 = Utf8 Ljava/io/PrintStream;
#164 = Utf8 java/io/PrintStream
#165 = Utf8 println
{
public test.Test();
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 9: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ltest/Test;
public static void main(java.lang.String[]) throws java.io.IOException;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=5, locals=4, args_size=1
0: new #2 // class java/io/File
3: dup
4: ldc #3 // String C:\Users\XXXXXXX\Desktop\dbData\goodsExtListUpdate.txt
6: invokespecial #4 // Method java/io/File."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokevirtual #5 // Method java/io/File.createNewFile:()Z
14: pop
15: new #6 // class java/io/BufferedWriter
18: dup
19: new #7 // class java/io/FileWriter
22: dup
23: aload_1
24: invokespecial #8 // Method java/io/FileWriter."<init>":(Ljava/io/File;)V
27: invokespecial #9 // Method java/io/BufferedWriter."<init>":(Ljava/io/Writer;)V
30: astore_2
31: iconst_0
32: aload_2
33: invokestatic #10 // Method readAndWrite:(ILjava/io/BufferedWriter;)V
36: goto 48
39: astore_3
40: aload_2
41: invokevirtual #12 // Method java/io/BufferedWriter.flush:()V
44: aload_2
45: invokevirtual #13 // Method java/io/BufferedWriter.close:()V
48: return
Exception table:
from to target type
31 36 39 Class java/lang/Exception
LineNumberTable:
line 15: 0
line 16: 10
line 17: 15
line 20: 31
line 25: 36
line 22: 39
line 23: 40
line 24: 44
line 26: 48
LocalVariableTable:
Start Length Slot Name Signature
40 8 3 e Ljava/lang/Exception;
0 49 0 args [Ljava/lang/String;
10 39 1 writename Ljava/io/File;
31 18 2 out Ljava/io/BufferedWriter;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 39
locals = [ class "[Ljava/lang/String;", class java/io/File, class java/io/BufferedWriter ]
stack = [ class java/lang/Exception ]
frame_type = 8 /* same */
Exceptions:
throws java.io.IOException
public static void readAndWrite(int, java.io.BufferedWriter) throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException, java.io.IOException;
descriptor: (ILjava/io/BufferedWriter;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=5, locals=7, args_size=2
0: ldc #14 // String C:\Users\XXXXX\Desktop\dbData\goodsExtList.txt
2: astore_2
3: new #2 // class java/io/File
6: dup
7: aload_2
8: invokespecial #4 // Method java/io/File."<init>":(Ljava/lang/String;)V
11: astore_3
12: new #15 // class java/io/InputStreamReader
15: dup
16: new #16 // class java/io/FileInputStream
19: dup
20: aload_3
21: invokespecial #17 // Method java/io/FileInputStream."<init>":(Ljava/io/File;)V
24: ldc #18 // String GBK
26: invokespecial #19 // Method java/io/InputStreamReader."<init>":(Ljava/io/InputStream;Ljava/lang/String;)V
29: astore 4
31: new #20 // class java/io/BufferedReader
34: dup
35: aload 4
37: invokespecial #21 // Method java/io/BufferedReader."<init>":(Ljava/io/Reader;)V
40: astore 5
42: ldc #22 // String
44: astore 6
46: aload 5
48: invokevirtual #23 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
51: astore 6
53: aload 6
55: ifnull 270
58: new #24 // class java/lang/String
61: dup
62: aload 5
64: invokevirtual #23 // Method java/io/BufferedReader.readLine:()Ljava/lang/String;
67: ldc #18 // String GBK
69: invokevirtual #25 // Method java/lang/String.getBytes:(Ljava/lang/String;)[B
72: ldc #18 // String GBK
74: invokespecial #26 // Method java/lang/String."<init>":([BLjava/lang/String;)V
77: astore 6
79: aload 6
81: ldc #27 // String hash
83: invokevirtual #28 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z
86: ifne 123
89: aload 6
91: ldc #29 // String CREATE TABLE `gold_pocket_goods_ext0` (
93: invokevirtual #28 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z
96: ifne 123
99: aload_1
100: new #30 // class java/lang/StringBuilder
103: dup
104: invokespecial #31 // Method java/lang/StringBuilder."<init>":()V
107: aload 6
109: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
112: ldc #33 // String \n
114: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
117: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
120: invokevirtual #35 // Method java/io/BufferedWriter.write:(Ljava/lang/String;)V
123: aload 6
125: ldc #27 // String hash
127: invokevirtual #28 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z
130: ifeq 195
133: iload_0
134: ifeq 163
137: new #30 // class java/lang/StringBuilder
140: dup
141: invokespecial #31 // Method java/lang/StringBuilder."<init>":()V
144: ldc #36 // String set @sharding = 'gold_pocket_goods_ext
146: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
149: iload_0
150: invokevirtual #37 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
153: ldc #38 // String ID hash ' ;
155: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
158: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
161: astore 6
163: getstatic #39 // Field java/lang/System.out:Ljava/io/PrintStream;
166: aload 6
168: invokevirtual #40 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
171: aload_1
172: new #30 // class java/lang/StringBuilder
175: dup
176: invokespecial #31 // Method java/lang/StringBuilder."<init>":()V
179: aload 6
181: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
184: ldc #33 // String \n
186: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
189: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
192: invokevirtual #35 // Method java/io/BufferedWriter.write:(Ljava/lang/String;)V
195: aload 6
197: ldc #29 // String CREATE TABLE `gold_pocket_goods_ext0` (
199: invokevirtual #28 // Method java/lang/String.contains:(Ljava/lang/CharSequence;)Z
202: ifeq 53
205: iload_0
206: ifeq 235
209: new #30 // class java/lang/StringBuilder
212: dup
213: invokespecial #31 // Method java/lang/StringBuilder."<init>":()V
216: ldc #41 // String CREATE TABLE `gold_pocket_goods_ext
218: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
221: iload_0
222: invokevirtual #37 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
225: ldc #42 // String ` (
227: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
230: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
233: astore 6
235: getstatic #39 // Field java/lang/System.out:Ljava/io/PrintStream;
238: aload 6
240: invokevirtual #40 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
243: aload_1
244: new #30 // class java/lang/StringBuilder
247: dup
248: invokespecial #31 // Method java/lang/StringBuilder."<init>":()V
251: aload 6
253: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
256: ldc #33 // String \n
258: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
261: invokevirtual #34 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
264: invokevirtual #35 // Method java/io/BufferedWriter.write:(Ljava/lang/String;)V
267: goto 53
270: goto 300
273: astore_2
274: iinc 0, 1
277: iload_0
278: sipush 512
281: if_icmpge 292
284: iload_0
285: aload_1
286: invokestatic #10 // Method readAndWrite:(ILjava/io/BufferedWriter;)V
289: goto 300
292: new #43 // class java/lang/NullPointerException
295: dup
296: invokespecial #44 // Method java/lang/NullPointerException."<init>":()V
299: athrow
300: return
Exception table:
from to target type
0 270 273 Class java/lang/NullPointerException
LineNumberTable:
line 30: 0
line 31: 3
line 32: 12
line 34: 31
line 36: 42
line 37: 46
line 38: 53
line 40: 58
line 41: 79
line 42: 99
line 45: 123
line 46: 133
line 47: 137
line 49: 163
line 50: 171
line 52: 195
line 53: 205
line 54: 209
line 56: 235
line 57: 243
line 69: 270
line 62: 273
line 63: 274
line 64: 277
line 65: 284
line 67: 292
line 71: 300
LocalVariableTable:
Start Length Slot Name Signature
3 267 2 pathname Ljava/lang/String;
12 258 3 filename Ljava/io/File;
31 239 4 reader Ljava/io/InputStreamReader;
42 228 5 br Ljava/io/BufferedReader;
46 224 6 line Ljava/lang/String;
274 26 2 nullPoint Ljava/lang/NullPointerException;
0 301 0 i I
0 301 1 out Ljava/io/BufferedWriter;
StackMapTable: number_of_entries = 9
frame_type = 255 /* full_frame */
offset_delta = 53
locals = [ int, class java/io/BufferedWriter, class java/lang/String, class java/io/File, class java/io/InputStreamReader, class java/io/BufferedReader, class java/lang/String ]
stack = []
frame_type = 251 /* same_frame_extended */
offset_delta = 69
frame_type = 39 /* same */
frame_type = 31 /* same */
frame_type = 39 /* same */
frame_type = 255 /* full_frame */
offset_delta = 34
locals = [ int, class java/io/BufferedWriter ]
stack = []
frame_type = 66 /* same_locals_1_stack_item */
stack = [ class java/lang/NullPointerException ]
frame_type = 252 /* append */
offset_delta = 18
locals = [ class java/lang/NullPointerException ]
frame_type = 250 /* chop */
offset_delta = 7
Exceptions:
throws java.io.FileNotFoundException, java.io.UnsupportedEncodingException, java.io.IOException
}
SourceFile: "Test.java"
四、解析内容讲解
1、字节码文件信息
开头的7行信息包括:Class文件当前所在位置,最后修改时间,文件大小,MD5值,编译自哪个文件,类的全限定名,jdk次版本号,主版本号。 然后紧接着的是该类的访问标志:ACC_PUBLIC, ACC_SUPER,访问标志的含义如下:
2、常量池信息
截取部分内容对比原代码红色框内容
在常量池中,该段代码分布情况。
Constant pool:
#1 = Methodref #46.#93 // java/lang/Object."<init>":()V
#2 = Class #94 // java/io/File
#3 = String #95 // C:\Users\XXXXXX\Desktop\dbData\goodsExtListUpdate.txt
第一个常量是一个方法定义,指向了第46和第93个常量。以此类推查看第46和第93个常量。
最后可以拼接成第一个常量右侧的注释内容:
java/lang/Object."<init>":()V
这段可以理解为该类的实例构造器的声明,由于Main类没有重写构造方法,所以调用的是父类的构造方法。此处也说明了Main类的直接父类是Object。 该方法默认返回值是V, 也就是void,无返回值。
对于后面的V
对于数组类型,每一位使用一个前置的"[“字符来描述,如定义一个java.lang.String[][]类型的维数组,将被记录为”[[Ljava/lang/String;"
3、内容的拆分先提下字段的含义:
对于类的字段access_flags标识有如下几个含义
对于方法access_flags标识有如下几个含义
属性预定义的标识有如下定义:
4、对于本文demo中属性结构如下:
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
Exception table:
LineNumberTable:
LocalVariableTable:
StackMapTable: number_of_entries = 2
Exceptions:
5、那么code的内容结构是什么样的?
这里重点说明一点code_length,同事一个u4类型的长度值,理论上最大值可以达到2^32-1,但是虚拟机中限制了一个方法长度不允许超过65535条字节码指令。如果不是刻意的话,或者复杂的Jsp文件的话,那么应该不会导致编译失败。
LineNumberTable
该属性的作用是描述源码行号与字节码行号(字节码偏移量)之间的对应关系。可以使用 -g:none 或-g:lines选项来取消或要求生成这项信息,如果选择不生成LineNumberTable,当程序运行异常时将无法获取到发生异常的源码行号,也无法按照源码的行数来调试程序。
LocalVariableTable
该属性的作用是描述帧栈中局部变量与源码中定义的变量之间的关系。可以使用 -g:none 或 -g:vars来取消或生成这项信息,如果没有生成这项信息,那么当别人引用这个方法时,将无法获取到参数名称,取而代之的是arg0, arg1这样的占位符。
在这里需要引入的另外一个LocalVariableTypeTable。仅仅是把记录的字段描述符的descriptior_index替换成了字段的特征签名
(Signature)由于描述附中泛型的参数化类型被擦除掉,描述符就不能准确描述泛型类型了,所以才需要这个变量属性LocalVariableTypeTable。对于非泛型类型来说,描述符合特征签名描述的信息基本一致。
5.1异常表的属性结构:
引入深入理解Java虚拟机中的案例如下
我们这里的代码demo示例如下
public static void main(java.lang.String[]) throws java.io.IOException;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=5, locals=4, args_size=1
0: new #2 // class java/io/File
3: dup
4: ldc #3 // String C:\Users\liuxiaocheng\Desktop\dbData\goodsExtListUpdate.txt
6: invokespecial #4 // Method java/io/File."<init>":(Ljava/lang/String;)V
9: astore_1
10: aload_1
11: invokevirtual #5 // Method java/io/File.createNewFile:()Z
14: pop
15: new #6 // class java/io/BufferedWriter
18: dup
19: new #7 // class java/io/FileWriter
22: dup
23: aload_1
24: invokespecial #8 // Method java/io/FileWriter."<init>":(Ljava/io/File;)V
27: invokespecial #9 // Method java/io/BufferedWriter."<init>":(Ljava/io/Writer;)V
30: astore_2
31: iconst_0
32: aload_2
33: invokestatic #10 // Method readAndWrite:(ILjava/io/BufferedWriter;)V
36: goto 48
39: astore_3
40: aload_2
41: invokevirtual #12 // Method java/io/BufferedWriter.flush:()V
44: aload_2
45: invokevirtual #13 // Method java/io/BufferedWriter.close:()V
48: return
Exception table:
from to target type
31 36 39 Class java/lang/Exception
LineNumberTable:
line 15: 0
line 16: 10
line 17: 15
line 20: 31
line 25: 36
line 22: 39
line 23: 40
line 24: 44
line 26: 48
LocalVariableTable:
Start Length Slot Name Signature
40 8 3 e Ljava/lang/Exception;
0 49 0 args [Ljava/lang/String;
10 39 1 writename Ljava/io/File;
31 18 2 out Ljava/io/BufferedWriter;
StackMapTable: number_of_entries = 2
frame_type = 255 /* full_frame */
offset_delta = 39
locals = [ class "[Ljava/lang/String;", class java/io/File, class java/io/BufferedWriter ]
stack = [ class java/lang/Exception ]
frame_type = 8 /* same */
Exceptions:
throws java.io.IOException
stack
最大操作数栈,JVM运行时会根据这个值来分配栈帧(Frame)中的操作栈深度,此处为1
locals:
局部变量所需的存储空间,单位为Slot, Slot是虚拟机为局部变量分配内存时所使用的最小单位,为4个字节大小。方法参数(包括实例方法中的隐藏参数this),显示异常处理器的参数(try catch中的catch块所定义的异常),方法体中定义的局部变量都需要使用局部变量表来存放。值得一提的是,locals的大小并不一定等于所有局部变量所占的Slot之和,因为局部变量中的Slot是可以重用的。
args_size:
方法参数的个数,这里是1,因为每个实例方法都会有一个隐藏参数this,如果方法声明为static 那么这里就会显示为0
start 表示该局部变量在哪一行开始可见,length表示可见行数,Slot(虚拟机为局部变量分配内存所使用的最小单位,对于byte,char,float,int ,short,boolean,和returnAddress等长度不超过32位的数据类型,每个局部变量占用1个Slot,而double和long这两种64位的数据类型则需要两个Slot来存放),Name是变量名称,然后是类型签名。
StackMapTable:
这个属性在虚拟机类加载的字节码验证阶段被新类型检查验证器(Type Checker)使用,目的在于代替以前比较消耗性能的基于数据流分析的类型推导验证器。一个方法的code属性最多只能有一个StackMapTable属性,否则抛出ClassFormatError异常。
Exception table:
异常表实际上是Java代码的一部分,编译器使用异常表而不是简单的跳转命令来实现Java异常及finally处理机制
Exceptions:与异常表不一样,这里是在方法throws抛出的时候列举的异常
Signature:
在任何类,接口,初始化方法或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Types),则Signature属性为他记录泛型签名信息,之所以专门使用这样的一个属性去记录泛型类型,是因为Java语言的泛型采用的是擦除法实现的伪泛型。
Signature结构如下:
signature_index项的值必须是一个对常量池的有效索引。常量池在该索引处的项必须是CONSTANT_Utf8_info结构,标识类签名,表示类签名、方法类型签名或字段类型签名。
StackMapTable结构如下:
SourceFile: "Test.java"
用于记录生成这个Class文件的源码文件名称,可选。
可以使用 -g:none 或-g:sources选项来取消或要求生成这项信息,
我们这里没有提到的还有常量和内部类属性
常量ConstantValue属性结构
InnerClasses内部类属性结构
number_of_classes
inner_class_access_flags
Deprecated和Synthetic属性
BootstrapMethods属性
bootstrap_method
bootstrap_methods[]数组中每个成员都需要包含的内容如下