背景:通过上一篇查看字节码文件知道如何查看java字节码文件后,可以继续仔细研究下字节码文件的内容,看看里面究竟承载了哪些内容
借用jclasslib插件的一张截图,可以看到字节码文件主要分为6个部分:
一、General Information
Major version: 52 代表 jdk 1.8,51代表 jdk 1.7
Minor version:代表jdk的次版本号
Constant pool count/Interfaces count/Methods count/Fields count/Attributes count :分别代表常量池数量、继承接口数、方法数量、类字段数量、类属性数量
Access flags:标识该类或接口的访问属性,各种访问属性如下图
二、Constant Pool 常量池
常量池,里面定义了类、方法、接口中涉及到的常量,包括类、方法、字段的名称、类型等等
Interfaces
类(接口)继承的接口Fields
从常量池中解析出来的类接口字段,常量池中类型为Fieldref的即类的字段
字段举例:
字段的各个属性如下:
cp_info:constantPool_info,表示常量池信息
Name: 字段名称,cp_info_#18对应常量池中的#18,如下图
Descriptor:字段类型,cp_info_#19如下图:
Access flags:字段的访问类型
对应字节码内容
其中Fieldref表明是类的字段,分别看#16和#61是什么
1.#16如下:
引用#76如下:
2.#61如下:
引用#18,#19如下:
三、Methods 方法
从方法表中解析出来的类(接口)中定义的方法
举例:
一个方法主要包括:
- Name:方法名称
- Descriptor:方法描述符
- Access flags:方法访问属性
- Code:代码
其中Code包括以下几个属性:
1.LineNumberTable:行号表 - start_pc; // 字节码的行号,即偏移量
- line_number; // 源码的行号
2.LocalVariableTable:局部变量表,方法中用到的局部变量这里都能看到
- start_pc; // 局部变量起始偏移量
- length; //局部变量作用范围长度
- name_index; //局部变量名称,指向常量池索引
- descriptor_index; //局部变量描述符,指向常量池索引
- index; //所在局部变量数组的索引位置, 如果为long或double在index和index+1
- Attributes
类(接口)的属性
通过javap查看的字节码内容,分为3个部分,jclasslib是对这些信息进行了一些解析整合:
通用信息:
Classfile /Users/kisrosen/05_PrivateProject/MailContent.class
Last modified 2017-2-3; size 2196 bytes
MD5 checksum d58da5b7eb14cacb8456ec74b829c9ae
Compiled from "MailContent.java"
public class com.wow.mailutils.MailContent
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
常量池:
Constant pool:
#1 = Methodref #17.#60 // java/lang/Object."<init>":()V
#2 = Fieldref #16.#61 // com/wow/mailutils/MailContent.title:Ljava/lang/String;
#3 = Fieldref #16.#62 // com/wow/mailutils/MailContent.toNames:Ljava/util/List;
#4 = Fieldref #16.#63 // com/wow/mailutils/MailContent.ccNames:Ljava/util/List;
#5 = Fieldref #16.#64 // com/wow/mailutils/MailContent.mailFrom:Ljava/lang/String;
#6 = Fieldref #16.#65 // com/wow/mailutils/MailContent.mailBody:Ljava/lang/String;
#7 = Class #66 // java/lang/StringBuilder
#8 = Methodref #7.#60 // java/lang/StringBuilder."<init>":()V
#9 = InterfaceMethodref #67.#68 // java/util/List.iterator:()Ljava/util/Iterator;
#10 = InterfaceMethodref #69.#70 // java/util/Iterator.hasNext:()Z
#11 = InterfaceMethodref #69.#71 // java/util/Iterator.next:()Ljava/lang/Object;
#12 = Class #72 // java/lang/String
#13 = Methodref #7.#73 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#14 = String #74 // ,
#15 = Methodref #7.#75 // java/lang/StringBuilder.toString:()Ljava/lang/String;
#16 = Class #76 // com/wow/mailutils/MailContent
#17 = Class #77 // java/lang/Object
#18 = Utf8 title
#19 = Utf8 Ljava/lang/String;
#20 = Utf8 toNames
#21 = Utf8 Ljava/util/List;
#22 = Utf8 Signature
#23 = Utf8 Ljava/util/List<Ljava/lang/String;>;
#24 = Utf8 ccNames
#25 = Utf8 mailFrom
#26 = Utf8 mailBody
#27 = Utf8 <init>
#28 = Utf8 ()V
#29 = Utf8 Code
#30 = Utf8 LineNumberTable
#31 = Utf8 LocalVariableTable
#32 = Utf8 this
#33 = Utf8 Lcom/wow/mailutils/MailContent;
#34 = Utf8 getTitle
#35 = Utf8 ()Ljava/lang/String;
#36 = Utf8 setTitle
#37 = Utf8 (Ljava/lang/String;)V
#38 = Utf8 getToNames
#39 = Utf8 ()Ljava/util/List;
#40 = Utf8 ()Ljava/util/List<Ljava/lang/String;>;
#41 = Utf8 setToNames
#42 = Utf8 (Ljava/util/List;)V
#43 = Utf8 LocalVariableTypeTable
#44 = Utf8 (Ljava/util/List<Ljava/lang/String;>;)V
#45 = Utf8 getCcNames
#46 = Utf8 setCcNames
#47 = Utf8 getMailFrom
#48 = Utf8 setMailFrom
#49 = Utf8 getMailBody
#50 = Utf8 setMailBody
#51 = Utf8 getToNamesString
#52 = Utf8 toName
#53 = Utf8 toNameString
#54 = Utf8 Ljava/lang/StringBuilder;
#55 = Utf8 StackMapTable
#56 = Class #66 // java/lang/StringBuilder
#57 = Class #78 // java/util/Iterator
#58 = Utf8 SourceFile
#59 = Utf8 MailContent.java
#60 = NameAndType #27:#28 // "<init>":()V
#61 = NameAndType #18:#19 // title:Ljava/lang/String;
#62 = NameAndType #20:#21 // toNames:Ljava/util/List;
#63 = NameAndType #24:#21 // ccNames:Ljava/util/List;
#64 = NameAndType #25:#19 // mailFrom:Ljava/lang/String;
#65 = NameAndType #26:#19 // mailBody:Ljava/lang/String;
#66 = Utf8 java/lang/StringBuilder
#67 = Class #79 // java/util/List
#68 = NameAndType #80:#81 // iterator:()Ljava/util/Iterator;
#69 = Class #78 // java/util/Iterator
#70 = NameAndType #82:#83 // hasNext:()Z
#71 = NameAndType #84:#85 // next:()Ljava/lang/Object;
#72 = Utf8 java/lang/String
#73 = NameAndType #86:#87 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
#74 = Utf8 ,
#75 = NameAndType #88:#35 // toString:()Ljava/lang/String;
#76 = Utf8 com/wow/mailutils/MailContent
#77 = Utf8 java/lang/Object
#78 = Utf8 java/util/Iterator
#79 = Utf8 java/util/List
#80 = Utf8 iterator
#81 = Utf8 ()Ljava/util/Iterator;
#82 = Utf8 hasNext
#83 = Utf8 ()Z
#84 = Utf8 next
#85 = Utf8 ()Ljava/lang/Object;
#86 = Utf8 append
#87 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;
#88 = Utf8 toString
方法表:
{
public com.wow.mailutils.MailContent();
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 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
public java.lang.String getTitle();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field title:Ljava/lang/String;
4: areturn
LineNumberTable:
line 35: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
public void setTitle(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #2 // Field title:Ljava/lang/String;
5: return
LineNumberTable:
line 39: 0
line 40: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/wow/mailutils/MailContent;
0 6 1 title Ljava/lang/String;
public java.util.List<java.lang.String> getToNames();
descriptor: ()Ljava/util/List;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #3 // Field toNames:Ljava/util/List;
4: areturn
LineNumberTable:
line 43: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
Signature: #40 // ()Ljava/util/List<Ljava/lang/String;>;
public void setToNames(java.util.List<java.lang.String>);
descriptor: (Ljava/util/List;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #3 // Field toNames:Ljava/util/List;
5: return
LineNumberTable:
line 47: 0
line 48: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/wow/mailutils/MailContent;
0 6 1 toNames Ljava/util/List;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 6 1 toNames Ljava/util/List<Ljava/lang/String;>;
Signature: #44 // (Ljava/util/List<Ljava/lang/String;>;)V
public java.util.List<java.lang.String> getCcNames();
descriptor: ()Ljava/util/List;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #4 // Field ccNames:Ljava/util/List;
4: areturn
LineNumberTable:
line 51: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
Signature: #40 // ()Ljava/util/List<Ljava/lang/String;>;
public void setCcNames(java.util.List<java.lang.String>);
descriptor: (Ljava/util/List;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #4 // Field ccNames:Ljava/util/List;
5: return
LineNumberTable:
line 55: 0
line 56: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/wow/mailutils/MailContent;
0 6 1 ccNames Ljava/util/List;
LocalVariableTypeTable:
Start Length Slot Name Signature
0 6 1 ccNames Ljava/util/List<Ljava/lang/String;>;
Signature: #44 // (Ljava/util/List<Ljava/lang/String;>;)V
public java.lang.String getMailFrom();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #5 // Field mailFrom:Ljava/lang/String;
4: areturn
LineNumberTable:
line 59: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
public void setMailFrom(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #5 // Field mailFrom:Ljava/lang/String;
5: return
LineNumberTable:
line 63: 0
line 64: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/wow/mailutils/MailContent;
0 6 1 mailFrom Ljava/lang/String;
public java.lang.String getMailBody();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #6 // Field mailBody:Ljava/lang/String;
4: areturn
LineNumberTable:
line 67: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/wow/mailutils/MailContent;
public void setMailBody(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: aload_1
2: putfield #6 // Field mailBody:Ljava/lang/String;
5: return
LineNumberTable:
line 71: 0
line 72: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/wow/mailutils/MailContent;
0 6 1 mailBody Ljava/lang/String;
public java.lang.String getToNamesString();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=2, locals=4, args_size=1
0: new #7 // class java/lang/StringBuilder
3: dup
4: invokespecial #8 // Method java/lang/StringBuilder."<init>":()V
7: astore_1
8: aload_0
9: getfield #3 // Field toNames:Ljava/util/List;
12: invokeinterface #9, 1 // InterfaceMethod java/util/List.iterator:()Ljava/util/Iterator;
17: astore_2
18: aload_2
19: invokeinterface #10, 1 // InterfaceMethod java/util/Iterator.hasNext:()Z
24: ifeq 53
27: aload_2
28: invokeinterface #11, 1 // InterfaceMethod java/util/Iterator.next:()Ljava/lang/Object;
33: checkcast #12 // class java/lang/String
36: astore_3
37: aload_1
38: aload_3
39: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
42: pop
43: aload_1
44: ldc #14 // String ,
46: invokevirtual #13 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
49: pop
50: goto 18
53: aload_1
54: invokevirtual #15 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
57: areturn
LineNumberTable:
line 76: 0
line 78: 8
line 80: 37
line 81: 43
line 82: 50
line 84: 53
LocalVariableTable:
Start Length Slot Name Signature
37 13 3 toName Ljava/lang/String;
0 58 0 this Lcom/wow/mailutils/MailContent;
8 50 1 toNameString Ljava/lang/StringBuilder;
StackMapTable: number_of_entries = 2
frame_type = 253 /* append */
offset_delta = 18
locals = [ class java/lang/StringBuilder, class java/util/Iterator ]
frame_type = 250 /* chop */
offset_delta = 34
}
SourceFile: "MailContent.java"
四、Fields 字段
字段主要是指类的字段定义,通常会在类的clinit和init方法里初始化
字段主要包含以下类型:
比如常用的LOG,字节码中描述了字段的名字、描述符(引用了常量池),以及访问标志
最后:jclasslib的一个小技巧,code里面点击可以跳转查看说明