class文件基本内容

在上一篇中,我们了解了下java源程序通过编译器编译(包括词法分析,语法分析,语义分析等)最终生成class文件的基本过程, 本篇主要将讲解class文件的基本内容等知识。class文件是一个非常重要的东西,因为在以后的文章中,我们将以class文件为 基础,进一步了解jvm的运行。好了,先开始本篇的学习吧。 一个class文件主要包括以下几部分内容:

###结构信息

主要描述了class文件的格式版本号和各个部分的数量与大小的信息。

###元数据

对应于java源码中的“声明”和“常量”信息,主要包括:类,继承的超类,实现的接口的声明信息、 域(Field)、方法信息和常量池。

###方法信息 java源码中对应的“语句”和“表达式”信息。主要包括:字节码、异常处理器表、求值栈的类型记录、 调试符号信息。

了解了以上信息后,还是来看一段程序以及由它生成的class文件,来具体分析。

一个具体的例子

public class Test{
    private static final int ZERO = 0;
    private static int  all= 88;

    public int div(int one,int other) throws Exception{

        if(other == ZERO){
            throw new Exception("can't be zero!");
        }
        return (all-one)/other;

    }
}

在面的代码是一个简单的例子。其中包括了静态属性,常量,异常等的声明,通过

javac -g Test.java

编译,其中的-g是为了编译生成包括所有调试信息的class文件。这些调试信息包括:局部变量名和行号。编译后 就生成了Test.class文件,接着我们通过javap工具来查看它的内容–

javap -c -s -l -verbose Test

如果一切顺利,就可以看到如下一些内容,我们会分部分来具体讨论:

public class Test extends java.lang.Object
    SourceFile: "Test.java"
    minor version: 0
major version: 50

上述是文件最开始的部分。第一句说明Test这个类继承自java.lang.Object这个超类,也就是声明了继承信息。 第二句说明该class文件是由Test.java这个源文件编译来的。第三、四句是class文件格式版本号,其中minor version:0 是次版本号为0,而major为主版本号为50,对应的jdk为6。如果major为49则jdk相应版本为1.5,48相应为1.4。具体信息如下:

  • JDK 1.0 -> major version 45 and minor version 3
  • JDK 1.1 -> major version 45 and minor version 3
  • JDK 1.2 -> major version 46 and minor version 0
  • JDK 1.3 -> major version 47 and minor version 0
  • JDK 1.4 -> major version 48 and minor version 0
  • JDK 1.5 -> major version 49 and minor version 0
  • JDK 1.6 -> major version 50 and minor version 0
  • JDK 1.7 -> major version 51 and minor version 0

第二部分:

Constant pool:
const #1 = Method       #7.#29; //  java/lang/Object."<init>":()V
const #2 = class        #30;    //  java/lang/Exception
const #3 = String       #31;    //  can't be zero!
const #4 = Method       #2.#32; //  java/lang/Exception."<init>":(Ljava/lang/String;)V
const #5 = Field        #6.#33; //  Test.all:I
const #6 = class        #34;    //  Test
const #7 = class        #35;    //  java/lang/Object
const #8 = Asciz        ZERO;
const #9 = Asciz        I;
const #10 = Asciz       ConstantValue;
const #11 = int 0;
const #12 = Asciz       all;
const #13 = Asciz       <init>;
const #14 = Asciz       ()V;
const #15 = Asciz       Code;
const #16 = Asciz       LineNumberTable;
const #17 = Asciz       LocalVariableTable;
const #18 = Asciz       this;
const #19 = Asciz       LTest;;
const #20 = Asciz       div;
const #21 = Asciz       (II)I;
const #22 = Asciz       one;
const #23 = Asciz       other;
const #24 = Asciz       StackMapTable;
const #25 = Asciz       Exceptions;
const #26 = Asciz       <clinit>;
const #27 = Asciz       SourceFile;
const #28 = Asciz       Test.java;
const #29 = NameAndType #13:#14;//  "<init>":()V
const #30 = Asciz       java/lang/Exception;
const #31 = Asciz       can't be zero!;
const #32 = NameAndType #13:#36;//  "<init>":(Ljava/lang/String;)V
const #33 = NameAndType #12:#9;//  all:I
const #34 = Asciz       Test;
const #35 = Asciz       java/lang/Object;
const #36 = Asciz       (Ljava/lang/String;)V;

以上部分是常量池,存放了所有的Field名称,方法名,方法签名,类型名,代码及class文件中的常量值。

public Test();
  Signature: ()V
  LineNumberTable:
  line 1: 0
  LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      5      0    this       LTest;
  Code:
  Stack=1, Locals=1, Args_size=1
  0:   aload_0
  1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
  4:   return
  LineNumberTable:
  line 1: 0
  LocalVariableTable:
  Start  Length  Slot  Name   Signature
0      5      0    this       LTest;

上述片段是将符号输入到符号表时生成的默认构造方法。Signature:方法签名。LineNumberTable:对应的字节码 的源码行号信息。Code:字节码信息。LocalVariableTable:局部变量信息。

public int div(int, int)   throws java.lang.Exception;
  Signature: (II)I
  LineNumberTable:
  line 7: 0
  line 8: 4
  line 10: 14

  LocalVariableTable:
  Start  Length  Slot  Name   Signature
  0      22      0    this       LTest;
  0      22      1    one       I
  0      22      2    other       I


  Code:
  Stack=3, Locals=3, Args_size=3
  0:   iload_2
  1:   ifne    14
  4:   new     #2; //class java/lang/Exception
  7:   dup
  8:   ldc     #3; //String can't be zero!
  10:  invokespecial   #4; //Method java/lang/Exception."<init>":(Ljava/lang/String;)V
  13:  athrow
  14:  getstatic       #5; //Field all:I
  17:  iload_1
  18:  isub
  19:  iload_2
  20:  idiv
  21:  ireturn
  LineNumberTable:
  line 7: 0
  line 8: 4
  line 10: 14

 LocalVariableTable:
 Start  Length  Slot  Name   Signature
 0      22      0    this       LTest;
 0      22      1    one       I
 0      22      2    other       I

上述片段中,1,2两行是Test方法的元数据信息。而接下来的各部分与前面所说的默认构造方法一样,也包括字节码信息,LineNumberTable, LocalVariableTable等。这些内容具体将在jvm深入部分再分析,目前就了解这些。再看最后一些片段:

StackMapTable: number_of_entries = 1
frame_type = 14 /* same */

上面片段这部分记录有分支的情况。如if,for,while等。

Exceptions:
throws java.lang.Exception
static {};
Signature: ()V
LineNumberTable:
line 3: 0
Code:
Stack=1, Locals=0, Args_size=0
0:   bipush  88
2:   putstatic       #5; //Field all:I
5:   return
LineNumberTable:
line 3: 0

上述片段是异常处理器表。至此对于class文件的基本内容介绍的差不多了。

小结

本篇简单介绍并粗略了解了下class文件。在此基础上,下篇中将详细介绍class文件在jvm中的加载机制等内容。

##文档信息