如何实现一个Java Class解析器
来源:互联网 发布:mysql password 编辑:程序博客网 时间:2024/06/03 21:10
最近在写一个私人项目,名字叫做ClassAnalyzer
,ClassAnalyzer
的目的是能让我们对Java Class
文件的设计与结构能够有一个深入的理解。主体框架与基本功能已经完成,还有一些细节功能日后再增加。实际上JDK
已经提供了命令行工具javap
来反编译Class
文件,但本篇文章将阐明我实现解析器的思路。
Class文件
作为类或者接口信息的载体,每个Class
文件都完整的定义了一个类。为了使Java
程序可以“编写一次,处处运行”,Java虚拟机规范对Class
文件进行了严格的规定。构成Class
文件的基本数据单位是字节,这些字节之间不存在任何分隔符,这使得整个Class
文件中存储的内容几乎全部是程序运行的必要数据,单个字节无法表示的数据由多个连续的字节来表示。
根据Java
虚拟机规范,Class
文件采用一种类似于C
语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。Java
虚拟机规范定义了u1
、u2
、u4
和u8
来分别表示1
个字节、2
个字节、4
个字节和8
个字节的无符号数,无符号数可以用来描述数字、索引引用、数量值或者是字符串。表是由多个无符号数或者其它表作为数据项构成的复合数据类型,表用于描述有层次关系的复合结构的数据,因此整个Class
文件本质上就是一张表。在ClassAnalyzer
中,byte
、short
、int
和long
分别对应u1
、u2
、u4
和u8
数据类型,Class
文件被描述为如下Java
类。
1234567891011121314151617181920
如何解析
组成Class
文件的各个数据项中,例如魔数、Class
文件的版本、访问标志、类索引和父类索引等数据项,它们在每个Class
文件中都占用固定数量的字节,在解析时只需要读取相应数量的字节。除此之外,需要灵活处理的主要包括4
部分:常量池、字段表集合、方法表集合和属性表集合。字段和方法都可以具备自己的属性,Class
本身也有相应的属性,因此,在解析字段表集合和方法表集合的同时也包含了属性表集合的解析。
常量池占据了Class
文件很大一部分的数据,用于存储所有的常量信息,包括数字和字符串常量、类名、接口名、字段名和方法名等。Java
虚拟机规范定义了多种常量类型,每一种常量类型都有自己的结构。常量池本身是一个表,在解析时有几点需要注意。
每个常量类型都通过一个
u1
类型的tag
来标识。表头给出的常量池大小(
constantPoolCount
)比实际大1
,例如,如果constantPoolCount
等于47
,那么常量池中有46
项常量。- 常量池的索引范围从
1
开始,例如,如果constantPoolCount
等于47
,那么常量池的索引范围为1 ~ 46
。设计者将第0
项空出来的目的是用于表达“不引用任何一个常量池项目”。 - 如果一个
CONSTANT_Long_info
或CONSTANT_Double_info
结构的项在常量池中的索引为n
,则常量池中下一个有效的项的索引为n+2
,此时常量池中索引为n+1
的项有效但必须被认为不可用。 CONSTANT_Utf8_info
型常量的结构中包含一个u1
类型的tag
、一个u2
类型的length
和由length
个u1
类型组成的bytes
,这length
字节的连续数据是一个使用MUTF-8
(Modified UTF-8)
编码的字符串。MUTF-8
与UTF-8
并不兼容,主要区别有两点:一是null
字符会被编码成2
字节(0xC0
和0x80
);二是补充字符是按照UTF-16
拆分为代理对分别编码的,相关细节可以看这里(变种UTF-8)。
属性表用于描述某些场景专有的信息,Class
文件、字段表和方法表都有相应的属性表集合。Java
虚拟机规范定义了多种属性,ClassAnalyzer
目前实现了对常用属性的解析。与常量类型的数据项不同,属性并没有一个tag
来标识属性的类型,但是每个属性都包含有一个u2
类型的attribute_name_index
,attribute_name_index
指向常量池中的一个CONSTANT_Utf8_info
类型的常量,该常量包含着属性的名称。在解析属性时,ClassAnalyzer
正是通过attribute_name_index
指向的常量对应的属性名称来得知属性的类型。
字段表用于描述类或者接口中声明的变量,字段包括类级变量以及实例级变量。字段表的结构包含一个u2
类型的access_flags
、一个u2
类型的name_index
、一个u2
类型的descriptor_index
、一个u2
类型的attributes_count
和attributes_count
个attribute_info
类型的attributes
。我们已经介绍了属性表的解析,attributes
的解析方式与属性表的解析方式一致。
Class
的文件方法表采用了和字段表相同的存储格式,只是access_flags
对应的含义有所不同。方法表包含着一个重要的属性:Code
属性。Code
属性存储了Java
代码编译成的字节码指令,在ClassAnalyzer
中,Code
对应的Java
类如下所示(仅列出了类属性)。
1234567891011121314151617181920
在Code
属性中,codeLength
和code
分别用于存储字节码长度和字节码指令,每条指令即一个字节(u1
类型)。在虚拟机执行时,通过读取code
中的一个个字节码,并将字节码翻译成相应的指令。另外,虽然codeLength
是一个u4
类型的值,但是实际上一个方法不允许超过65535
条字节码指令。
代码实现
ClassAnalyzer
的源码已放在了GitHub上。在ClassAnalyzer
的README中,我以一个类的Class
文件为例,对该Class
文件的每个字节进行了分析,希望对大家的理解有所帮助。
Demo
TestClass.java
package org.tinylcy;public class TestClass implements Cloneable { public static final String TAG = "tinylcy"; private int num; public void inc() { num++; } public int exception() { int x; try { x = 1; return x; } catch (Exception e) { x = 2; return x; } finally { x = 3; } } public static void showTag() { System.out.println(TAG); }}
TestClass.class
cafe babe 0000 0031 0030 0a00 0800 1f090005 0020 0700 2109 0022 0023 0700 24080025 0a00 2600 2707 0028 0700 2901 00035441 4701 0012 4c6a 6176 612f 6c61 6e672f53 7472 696e 673b 0100 0d43 6f6e 7374616e 7456 616c 7565 0100 036e 756d 01000149 0100 063c 696e 6974 3e01 0003 28295601 0004 436f 6465 0100 0f4c 696e 654e756d 6265 7254 6162 6c65 0100 124c 6f63616c 5661 7269 6162 6c65 5461 626c 65010004 7468 6973 0100 174c 6f72 672f 74696e79 6c63 792f 5465 7374 436c 6173 733b0100 0369 6e63 0100 0965 7863 6570 74696f6e 0100 0328 2949 0100 0178 0100 01650100 154c 6a61 7661 2f6c 616e 672f 45786365 7074 696f 6e3b 0100 0773 686f 77546167 0100 0a53 6f75 7263 6546 696c 6501000e 5465 7374 436c 6173 732e 6a61 76610c00 0f00 100c 000d 000e 0100 136a 6176612f 6c61 6e67 2f45 7863 6570 7469 6f6e0700 2a0c 002b 002c 0100 156f 7267 2f74696e 796c 6379 2f54 6573 7443 6c61 73730100 0774 696e 796c 6379 0700 2d0c 002e002f 0100 106a 6176 612f 6c61 6e67 2f4f626a 6563 7401 0013 6a61 7661 2f6c 616e672f 436c 6f6e 6561 626c 6501 0010 6a617661 2f6c 616e 672f 5379 7374 656d 0100036f 7574 0100 154c 6a61 7661 2f69 6f2f5072 696e 7453 7472 6561 6d3b 0100 136a6176 612f 696f 2f50 7269 6e74 5374 7265616d 0100 0770 7269 6e74 6c6e 0100 15284c6a 6176 612f 6c61 6e67 2f53 7472 696e673b 2956 0021 0005 0008 0001 0009 00020019 000a 000b 0001 000c 0000 0002 00060002 000d 000e 0000 0004 0001 000f 00100001 0011 0000 002f 0001 0001 0000 00052ab7 0001 b100 0000 0200 1200 0000 06000100 0000 0600 1300 0000 0c00 0100 00000500 1400 1500 0000 0100 1600 1000 01001100 0000 3900 0300 0100 0000 0b2a 59b40002 0460 b500 02b1 0000 0002 0012 0000000a 0002 0000 000c 000a 000d 0013 0000000c 0001 0000 000b 0014 0015 0000 00010017 0018 0001 0011 0000 00ae 0001 00050000 0018 043c 1b3d 063c 1cac 4d05 3c1b3e06 3c1d ac3a 0406 3c19 04bf 0004 00000004 0008 0003 0000 0004 0011 0000 0008000d 0011 0000 0011 0013 0011 0000 00020012 0000 002a 000a 0000 0012 0002 00130004 0018 0006 0013 0008 0014 0009 0015000b 0016 000d 0018 000f 0016 0011 00180013 0000 0034 0005 0002 0006 0019 000e0001 0009 0008 001a 001b 0002 000b 00060019 000e 0001 0000 0018 0014 0015 00000015 0003 0019 000e 0001 0009 001c 00100001 0011 0000 0025 0002 0000 0000 0009b200 0412 06b6 0007 b100 0000 0100 12000000 0a00 0200 0000 1d00 0800 1e00 01001d00 0000 0200 1e
Running the examples
public class ClassFileTest { @Test public void classfile() throws Exception { File file = new File("/path/to/TestClass.class"); FileInputStream inputStream = new FileInputStream(file); ClassReader.analyze(inputStream); }}
Output
magic = cafebabeminorVersion = 0majorVersion = 49constantPoolCount = 48cpInfo[1] = ConstantMethodRefInfo{classIndex=8, nameAndTypeIndex=31}cpInfo[2] = ConstantFieldRefInfo{classIndex=5, nameAndTypeIndex=32}cpInfo[3] = ConstantClassInfo{index=33}cpInfo[4] = ConstantFieldRefInfo{classIndex=34, nameAndTypeIndex=35}cpInfo[5] = ConstantClassInfo{index=36}cpInfo[6] = ConstantClassInfo{index=37}cpInfo[7] = ConstantMethodRefInfo{classIndex=38, nameAndTypeIndex=39}cpInfo[8] = ConstantClassInfo{index=40}cpInfo[9] = ConstantClassInfo{index=41}cpInfo[10] = ConstantUtf8Info{bytesValue='TAG'}cpInfo[11] = ConstantUtf8Info{bytesValue='Ljava/lang/String;'}cpInfo[12] = ConstantUtf8Info{bytesValue='ConstantValue'}cpInfo[13] = ConstantUtf8Info{bytesValue='num'}cpInfo[14] = ConstantUtf8Info{bytesValue='I'}cpInfo[15] = ConstantUtf8Info{bytesValue='<init>'}cpInfo[16] = ConstantUtf8Info{bytesValue='()V'}cpInfo[17] = ConstantUtf8Info{bytesValue='Code'}cpInfo[18] = ConstantUtf8Info{bytesValue='LineNumberTable'}cpInfo[19] = ConstantUtf8Info{bytesValue='LocalVariableTable'}cpInfo[20] = ConstantUtf8Info{bytesValue='this'}cpInfo[21] = ConstantUtf8Info{bytesValue='Lorg/tinylcy/TestClass;'}cpInfo[22] = ConstantUtf8Info{bytesValue='inc'}cpInfo[23] = ConstantUtf8Info{bytesValue='exception'}cpInfo[24] = ConstantUtf8Info{bytesValue='()I'}cpInfo[25] = ConstantUtf8Info{bytesValue='x'}cpInfo[26] = ConstantUtf8Info{bytesValue='e'}cpInfo[27] = ConstantUtf8Info{bytesValue='Ljava/lang/Exception;'}cpInfo[28] = ConstantUtf8Info{bytesValue='showTag'}cpInfo[29] = ConstantUtf8Info{bytesValue='SourceFile'}cpInfo[30] = ConstantUtf8Info{bytesValue='TestClass.java'}cpInfo[31] = ConstantNameAndTypeInfo{nameIndex=15, descriptorIndex=16}cpInfo[32] = ConstantNameAndTypeInfo{nameIndex=13, descriptorIndex=14}cpInfo[33] = ConstantUtf8Info{bytesValue='java/lang/Exception'}cpInfo[34] = ConstantClassInfo{index=42}cpInfo[35] = ConstantNameAndTypeInfo{nameIndex=43, descriptorIndex=44}cpInfo[36] = ConstantUtf8Info{bytesValue='org/tinylcy/TestClass'}cpInfo[37] = ConstantUtf8Info{bytesValue='tinylcy'}cpInfo[38] = ConstantClassInfo{index=45}cpInfo[39] = ConstantNameAndTypeInfo{nameIndex=46, descriptorIndex=47}cpInfo[40] = ConstantUtf8Info{bytesValue='java/lang/Object'}cpInfo[41] = ConstantUtf8Info{bytesValue='java/lang/Cloneable'}cpInfo[42] = ConstantUtf8Info{bytesValue='java/lang/System'}cpInfo[43] = ConstantUtf8Info{bytesValue='out'}cpInfo[44] = ConstantUtf8Info{bytesValue='Ljava/io/PrintStream;'}cpInfo[45] = ConstantUtf8Info{bytesValue='java/io/PrintStream'}cpInfo[46] = ConstantUtf8Info{bytesValue='println'}cpInfo[47] = ConstantUtf8Info{bytesValue='(Ljava/lang/String;)V'}accessFlags = 21, public super thisClass = 5, this class name = org/tinylcy/TestClasssuperClass = 8, super class name = java/lang/ObjectinterfacesCount = 1interfaces[0] = 9, interface name = java/lang/CloneablefieldsCount = 2fields[0] = FieldInfo{accessFlags=25: public static final , nameIndex=10 [name = TAG], descriptorIndex=11 [descriptor = Ljava/lang/String;], attributesCount=1, attributes=[]}fields[1] = FieldInfo{accessFlags=2: private , nameIndex=13 [name = num], descriptorIndex=14 [descriptor = I], attributesCount=0, attributes=[]}methodsCount = 4methods[0] = MethodInfo{accessFlags=1: public , nameIndex=15 [name = <init>], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=47, maxStack=1, maxLocals=1, codeLength=5, code=[42, -73, 0, 1, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=6, lineNumberTableLength=1, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=6}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=12, localVariableTableLength=1}]}]}methods[1] = MethodInfo{accessFlags=1: public , nameIndex=22 [name = inc], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=57, maxStack=3, maxLocals=1, codeLength=11, code=[42, 89, -76, 0, 2, 4, 96, -75, 0, 2, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=10, lineNumberTableLength=2, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=12}, LineNumberInfo{startPc=10, lineNumber=13}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=12, localVariableTableLength=1}]}]}methods[2] = MethodInfo{accessFlags=1: public , nameIndex=23 [name = exception], descriptorIndex=24 [descriptor = ()I], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=174, maxStack=1, maxLocals=5, codeLength=24, code=[4, 60, 27, 61, 6, 60, 28, -84, 77, 5, 60, 27, 62, 6, 60, 29, -84, 58, 4, 6, 60, 25, 4, -65], exceptionTableLength=4, exceptionTable=[ExceptionInfo{startPc=0, endPc=4, handlerPc=8, catchType=3}, ExceptionInfo{startPc=0, endPc=4, handlerPc=17, catchType=0}, ExceptionInfo{startPc=8, endPc=13, handlerPc=17, catchType=0}, ExceptionInfo{startPc=17, endPc=19, handlerPc=17, catchType=0}], attributesCount=2, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=42, lineNumberTableLength=10, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=18}, LineNumberInfo{startPc=2, lineNumber=19}, LineNumberInfo{startPc=4, lineNumber=24}, LineNumberInfo{startPc=6, lineNumber=19}, LineNumberInfo{startPc=8, lineNumber=20}, LineNumberInfo{startPc=9, lineNumber=21}, LineNumberInfo{startPc=11, lineNumber=22}, LineNumberInfo{startPc=13, lineNumber=24}, LineNumberInfo{startPc=15, lineNumber=22}, LineNumberInfo{startPc=17, lineNumber=24}]}, LocalVariableTable{attributeNameIndex=19 [attribute name = LocalVariableTable], attributeLength=52, localVariableTableLength=5}]}]}methods[3] = MethodInfo{accessFlags=9: public static , nameIndex=28 [name = showTag], descriptorIndex=16 [descriptor = ()V], attributesCount=1, attributes=[Code{attributeNameIndex=17 [attribute name = Code], attributeLength=37, maxStack=2, maxLocals=0, codeLength=9, code=[-78, 0, 4, 18, 6, -74, 0, 7, -79], exceptionTableLength=0, exceptionTable=[], attributesCount=1, attributes=[LineNumberTable{attributeNameIndex=18 [attribute name = LineNumberTable], attributeLength=10, lineNumberTableLength=2, lineNumberTable=[LineNumberInfo{startPc=0, lineNumber=29}, LineNumberInfo{startPc=8, lineNumber=30}]}]}]}attributesCount = 1attributes[0] = SourceFile{attributeNameIndex=29 [attribute name = SourceFile], attributeLength=2, sourceFileIndex=30}
Bytes analysis
cafe babe : magic0000 : minor version0034 : major version0030 : constant pool count0a : tag00 08 : class index00 1f : nameAndType index09 : tag0005 : class index0020 : nameAndType index07 : tag00 21 : index09 : tag0022 : class index0023 : nameAndType index07 : tag00 24 : index08 : tag0025 : index0a : tag0026 : class index0027 : nameAndType index07 : tag0028 : index07 : tag00 29 : index01 : tag0003 : length5441 47 : bytes01 : tag0012 : length4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b : bytes01 : tag00 0d : 1343 6f6e 7374 616e 7456 616c 7565 : bytes01 : tag00 03 : length6e 756d : bytes01 : tag00 01 : length49 : bytes01 : tag00 06 : length3c 696e 6974 3e : bytes01 : tag0003 : length2829 56 : bytes01 : tag0004 : length436f 6465 : bytes01 : tag00 0f : length4c 696e 654e 756d 6265 7254 6162 6c65 : bytes01 : tag00 12 : length4c 6f63 616c 5661 7269 6162 6c65 5461 626c 65 : bytes01 : tag0004 : length7468 6973 : bytes01 : tag00 17 : length4c 6f72 672f 7469 6e79 6c63 792f 5465 7374 436c 6173 733b : bytes01 : tag00 03 : length69 6e63 : bytes01 : tag00 09 : length65 7863 6570 7469 6f6e : bytes01 : tag00 03 : length28 2949 : bytes01 : tag00 01 : length78 : bytes01 : tag00 01 : length65 : bytes01 : tag00 15 : length4c 6a61 7661 2f6c 616e 672f 4578 6365 7074 696f 6e3b : bytes01 : tag00 07 : length73 686f 7754 6167 : bytes01 : tag00 0a : length53 6f75 7263 6546 696c 65 : bytes01 : tag000e : length5465 7374 436c 6173 732e 6a61 7661 : byte0c : tag00 0f : name index00 10 : descriptor index0c : tag000d : name index000e : descriptor index01 : tag00 13 : length6a 6176 612f 6c61 6e67 2f45 7863 6570 7469 6f6e : bytes07 : tag00 2a : index0c : tag002b : name index002c : descriptor index01 : tag00 15 : length6f 7267 2f74 696e 796c 6379 2f54 6573 7443 6c61 7373 : bytes01 : tag00 07 : length74 696e 796c 6379 : bytes07 : tag00 2d : index0c : tag002e : name index002f : descriptor index01 : tag00 10 : length6a 6176 612f 6c61 6e67 2f4f 626a 6563 74 : bytes01 : tag0013 : length6a61 7661 2f6c 616e 672f 436c 6f6e 6561 626c 65 : bytes01 : tag0010 : length6a61 7661 2f6c 616e 672f 5379 7374 656d : bytes01 : tag00 03 : length6f 7574 : bytes01 : tag00 15 : length4c 6a61 7661 2f69 6f2f 5072 696e 7453 7472 6561 6d3b : bytes01 : tag00 13 : length6a 6176 612f 696f 2f50 7269 6e74 5374 7265 616d : bytes01 : tag00 07 : length70 7269 6e74 6c6e : bytes01 : tag00 15 : length28 4c6a 6176 612f 6c61 6e67 2f53 7472 696e 673b 2956 bytes0021 : access flags0005 : this class0008 : super class0001 : interfaces count0009 : interfaces0002 : fields count0019 : access flags000a : name index000b : descriptor index0001 : attributes count000c : attribute name index0000 0002 : attribute length0006 : constant value index0002 : access flags000d : name index000e : descriptor index0000 : attribute count0004 : methods count0001 : access flags000f : name index0010 : descriptor index0001 : attributes count0011 : attribute name index0000 002f : attribute length0001 : max stack0001 : max locals0000 0005 : code length2ab7 0001 b1 : code00 00 : exception table length00 02 : attributes count00 12 : attribute name index00 0000 06 : attribute length00 01 : line number table length00 00 : start pc00 06 : line number00 13 : attribute name index00 0000 0c : attribute length00 01 : local variable table length00 00 : start pc00 05 : length00 14 : name index00 15 : descriptor index00 00 : index00 01 : access flags00 16 : name index00 10 : descriptor index00 01 : attributes count00 11 : attribute name index00 0000 39 : attribute length00 03 : max stack00 01 : max locals00 0000 0b : code length2a 59b4 0002 0460 b500 02b1 : code0000 : exception table length0002 : attributes count0012 : attribute name index0000 000a : attribute length0002 : line number table length0000 : start pc000c : line number000a : start pc000d : line number0013 : attribute name index0000 000c : attribute length0001 : local variable table length0000 : start pc000b : length0014 : name index0015 : descriptor index0000 : index0001 : access flags0017 : name index0018 : descriptor index0001 : attributes count0011 : attribute name index0000 00ae : attribute length0001 : max stack0005 : max locals0000 0018 : code length043c 1b3d 063c 1cac 4d05 3c1b 3e06 3c1d ac3a 0406 3c19 04bf : code0004 : exception table length0000 : start pc0004 : end pc0008 : handler pc0003 : catch type0000 : start pc0004 : end pc0011 : handler pc0000 : catch type0008 : start pc000d : end pc0011 : handler pc0000 : catch type0011 : start pc0013 : end pc0011 : handler pc0000 : catch type0002 : attributes count0012 : attribute name index0000 002a : attribute length000a : line number table length0000 : start pc0012 : line number0002 : start pc0013 : line number0004 : start pc0018 : line number0006 : start pc0013 : line number0008 : start pc0014 : line number0009 : start pc0015 : line number000b : start pc0016 : line number000d : start pc0018 : line number000f : start pc0016 : line number0011 : start pc0018 : line number0013 : attribute name index0000 0034 : attribute length0005 : local variable table length0002 : start pc0006 : length0019 : name index000e : descriptor index0001 : index0009 : start pc0008 : length001a : name index001b : descriptor index0002 : index000b : start pc0006 : length0019 : name index000e : descriptor index0001 : index0000 : start pc0018 : length0014 : name index0015 : descriptor index0000 : index0015 : start pc0003 : length0019 : name index000e : descriptor index0001 : index0009 : access flags001c : name index0010 : descriptor index0001 : attributes count0011 : attribute name index0000 0025 : attribute length0002 : max stack0000 : max locals0000 0009 : code lengthb200 0412 06b6 0007 b1 : code00 00 : exception table length00 01 : attributes count00 12 : attribute name index00 0000 0a : attribute length00 02 : line number table00 00 : start pc00 1d : line number00 08 : start pc00 1e : line number00 01 : attributes count 00 1d : attribute name index00 0000 02 : attribute length00 1e : source file index
- 如何实现一个Java Class解析器
- 如何实现一个Java Class解析器
- 如何实现一个Java Class 解析器,我们需要做的还有很多
- 如何实现一个 Git Diff 解析器
- Java class文件中 StackMapTable Attribute如何解析?
- java class文件格式解析
- Java Class 文件解析
- java class文件解析
- JAVA CLASS 文件解析
- 一个java文件如何放两个public class 类
- JVM 如何装载和初始化一个Java class(类)
- 我是一个Java class
- 我是一个Java class
- 我是一个Java class
- 我是一个Java class
- 我是一个Java class
- 我是一个java class
- 我是一个java class
- noip数据结构与算法 之 基础小算法 1 一维前缀和维护
- 算法作业20
- MyBatis查询结果集映射到JavaBean原理浅谈
- vs masm汇编运行出现 LINK1104 无法打开Debug/xx**.obj,exe
- 总体性能——物理模块性能
- 如何实现一个Java Class解析器
- POJ 1350 Cabric Number Problem 笔记
- 数据库第七章 概念结构设计
- IDEA tomcat乱码
- 总体性能——动画模块性能
- Fast-rcnn总结
- Linux系统下安装 rz/sz命令及使用
- 转。java IO
- WinXP 32bit下安装theano和Keras