Java学习:详解字节码class文件

背景:通过上一篇查看字节码文件知道如何查看java字节码文件后,可以继续仔细研究下字节码文件的内容,看看里面究竟承载了哪些内容

借用jclasslib插件的一张截图,可以看到字节码文件主要分为6个部分:


  • General Information

Major version: 52 代表 jdk 1.8

Minor version:代表jdk的次版本号

Constant pool count/Interfaces count/Methods count/Fields count/Attributes count :分别代表常量池数量、继承接口数、方法数量、类字段数量、类属性数量

Access flags:标识该类或接口的访问属性,各种访问属性如下图

  • Constant Pool
    常量池,里面定义了类、方法、接口中涉及到的常量,包括类、方法、字段的名称、类型等等

  • Interfaces
    类(接口)继承的接口

  • Fields
    从常量池中解析出来的类接口字段,常量池中类型为Fieldref的即类的字段

字段举例:

字段的各个属性如下:

Name: 字段名称,cp_info_#18对应常量池中的#18,如下图

Descriptor:字段类型,cp_info_#19如下图:

Access flags:字段的访问类型

对应字节码内容


#2 = Fieldref  #16.#61

其中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"

推荐阅读更多精彩内容

  • 参考《Java虚拟机规范JavaSE7版》的描述来看,每一个字节码文件其实都对应着全局唯一的一个类或者接口的定义信...
    爱码士平头哥阅读 205评论 0 1
  • 最近刚看完 深入理解 Java 虚拟机 一书中的第 6 章 (类文件结构),便迫不及待地自己写一个小的 Demo,...
    alighters阅读 769评论 0 5
  • 1.流程 创建 HelloWorld.java代码如下package jvm; /** * @author ...
    RunAlgorithm阅读 665评论 4 4
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    会飞的鱼69阅读 24,319评论 18 391
  • 文/伟伟 东走西闯,风来雨去,艰苦的做着贩人的勾当。虽然我只有23岁,但在这一行已经干了23个月。一直带着我的龙叔...
    大男人不霸道阅读 111评论 1 2