我们都知道,java因为一次编译处处运行,等特性,使其目前发展的特别大,java能做到这一点,主要归功于JVM。程序员写完的程序通过编译成class字节文件,JVM负责将class文件解释给机器执行。 我们来自己写一个程序,和JVM一样,简单的完成对于class的解析。

开始之前我们先对Class有一个简单的了解

  • Class文件是一组以8位字节为基础单位的二进制流,当遇到需要8位字节以上空间的数据项时,则会按照高位在前的方式分隔成若干个8位字节进行存储。
  • Class文件由无符号数和表构成。
  • 无符号数:以u1、u2、u4、u8分别代表1个字节、2个字节、4个字节和8个字节的无符号数,可以用来描述数字、索引引用、数量值、按照UTF-8编码构成的字符串值。
  • 表:由多个无符号数或其他表作为数据项构成的复杂数据类型,所有表都习惯性地以“_info”结尾。

Class文件格式如下

类型描述备注
u4magic魔数
u2minor_version小版本号
u2major_version主版本号
u2constant_pool_count常量池大小,从1开始
cp_infoconstant_pool[constant_pool_count - 1]常量池信息
u2access_flags访问标志
u2this_class类索引
u2super_class父类索引
u2interfaces_count接口个数
u2interfaces[interfaces_count]接口类索引信息
u2fields_count字段数
field_infofields[fields_count]字段表信息
u2methods_count方法数
method_infomethods[methods_count]方法表信息
u2attributes_count属性个数
attribute_infoattributes[attributes_count]属性表信息

准备一个普通的类,编译成IBopClient.class,并是sublime 打开

cafe babe 0000 0033 0016 0700 1307 0014
0100 0765 7865 6375 7465 0100 5c28 4c63
6f6d 2f62 6169 7761 6e67 2f62 6f70 2f72
6571 7565 7374 2f49 426f 7052 6571 7565
7374 3b4c 6a61 7661 2f6c 616e 672f 5374
7269 6e67 3b4c 6a61 7661 2f6c 616e 672f
436c 6173 733b 294c 6a61 7661 2f6c 616e
672f 4f62 6a65 6374 3b01 000a 4578 6365
7074 696f 6e73 0700 1501 0009 5369 676e
6174 7572 6501 0068 3c54 3a4c 6a61 7661
2f6c 616e 672f 4f62 6a65 6374 3b3e 284c
636f 6d2f 6261 6977 616e 672f 626f 702f
7265 7175 6573 742f 4942 6f70 5265 7175
6573 743b 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 4c6a 6176 612f 6c61 6e67
2f43 6c61 7373 3c54 543b 3e3b 2954 543b
0100 4a28 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 4c6a 6176 612f 6c61
6e67 2f53 7472 696e 673b 294c 6a61 7661
2f6c 616e 672f 5374 7269 6e67 3b01 000b
6578 6563 7574 6541 7379 6e01 006f 284c
636f 6d2f 6261 6977 616e 672f 626f 702f
7265 7175 6573 742f 4942 6f70 5265 7175
6573 743b 4c6a 6176 612f 6c61 6e67 2f53
7472 696e 673b 4c6a 6176 612f 6c61 6e67
2f43 6c61 7373 3b4c 6a61 7661 2f6c 616e
672f 496e 7465 6765 723b 294c 6a61 7661
2f6c 616e 672f 4f62 6a65 6374 3b01 007b
3c54 3a4c 6a61 7661 2f6c 616e 672f 4f62
6a65 6374 3b3e 284c 636f 6d2f 6261 6977
616e 672f 626f 702f 7265 7175 6573 742f
4942 6f70 5265 7175 6573 743b 4c6a 6176
612f 6c61 6e67 2f53 7472 696e 673b 4c6a
6176 612f 6c61 6e67 2f43 6c61 7373 3c54
543b 3e3b 4c6a 6176 612f 6c61 6e67 2f49
6e74 6567 6572 3b29 5454 3b01 0008 7365
7450 726f 7879 0100 1628 4c6a 6176 612f
6c61 6e67 2f53 7472 696e 673b 4929 5601
0010 7365 7441 7574 686f 7269 7a61 7469
6f6e 0100 2728 4c6a 6176 612f 6c61 6e67
2f53 7472 696e 673b 4c6a 6176 612f 6c61
6e67 2f53 7472 696e 673b 2956 0100 0a53
6f75 7263 6546 696c 6501 000f 4942 6f70
436c 6965 6e74 2e6a 6176 6101 0021 636f
6d2f 6261 6977 616e 672f 626f 702f 636c
6965 6e74 2f49 426f 7043 6c69 656e 7401
0010 6a61 7661 2f6c 616e 672f 4f62 6a65
6374 0100 2363 6f6d 2f62 6169 7761 6e67
2f62 6f70 2f63 6c69 656e 742f 426f 7045
7863 6570 7469 6f6e 0601 0001 0002 0000
0000 0005 0401 0003 0004 0002 0005 0000
0004 0001 0006 0007 0000 0002 0008 0401
0003 0009 0001 0005 0000 0004 0001 0006
0401 000a 000b 0002 0005 0000 0004 0001
0006 0007 0000 0002 000c 0401 000d 000e
0000 0401 000f 0010 0000 0001 0011 0000
0002 0012 

魔数 cafe babe

minor_version 0000

major_version 0033 ,十进制是51

常量池-0016

版本号后面是常量池,常量池中常量的数量是不固定的,所以常量池的入口处有一个u2类型的数据,表示常量池中常量的数值大小。 0x0016f十进制是22,表示常量池常量数为22(注意常量池计数是从1而不是0开始),使用“javap -v BMWCar”命令可以查看Class文件的信息如下

Classfile /Users/mac/Documents/other/bw/bopsdk-openapi-1.0.2-Release/com/baiwang/bop/client/IBopClient.class
  Last modified 2019-6-24; size 916 bytes
  MD5 checksum caabed00c0d617ed9139705bb56f1f4b
  Compiled from "IBopClient.java"
public interface com.baiwang.bop.client.IBopClient
  minor version: 0
  major version: 51
  flags: ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
Constant pool:
   #1 = Class              #19            // com/baiwang/bop/client/IBopClient
   #2 = Class              #20            // java/lang/Object
   #3 = Utf8               execute
   #4 = Utf8               (Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
   #5 = Utf8               Exceptions
   #6 = Class              #21            // com/baiwang/bop/client/BopException
   #7 = Utf8               Signature
   #8 = Utf8               <T:Ljava/lang/Object;>(Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class<TT;>;)TT;
   #9 = Utf8               (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
  #10 = Utf8               executeAsyn
  #11 = Utf8               (Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Integer;)Ljava/lang/Object;
  #12 = Utf8               <T:Ljava/lang/Object;>(Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class<TT;>;Ljava/lang/Integer;)TT;
  #13 = Utf8               setProxy
  #14 = Utf8               (Ljava/lang/String;I)V
  #15 = Utf8               setAuthorization
  #16 = Utf8               (Ljava/lang/String;Ljava/lang/String;)V
  #17 = Utf8               SourceFile
  #18 = Utf8               IBopClient.java
  #19 = Utf8               com/baiwang/bop/client/IBopClient
  #20 = Utf8               java/lang/Object
  #21 = Utf8               com/baiwang/bop/client/BopException
{
  public abstract <T extends java.lang.Object> T execute(com.baiwang.bop.request.IBopRequest, java.lang.String, java.lang.Class<T>) throws com.baiwang.bop.client.BopException;
    descriptor: (Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    Exceptions:
      throws com.baiwang.bop.client.BopException
    Signature: #8                           // <T:Ljava/lang/Object;>(Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class<TT;>;)TT;

  public abstract java.lang.String execute(java.lang.String, java.lang.String, java.lang.String) throws com.baiwang.bop.client.BopException;
    descriptor: (Ljava/lang/String;Ljava/lang/String;Ljava/lang/String;)Ljava/lang/String;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    Exceptions:
      throws com.baiwang.bop.client.BopException

  public abstract <T extends java.lang.Object> T executeAsyn(com.baiwang.bop.request.IBopRequest, java.lang.String, java.lang.Class<T>, java.lang.Integer) throws com.baiwang.bop.client.BopException;
    descriptor: (Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class;Ljava/lang/Integer;)Ljava/lang/Object;
    flags: ACC_PUBLIC, ACC_ABSTRACT
    Exceptions:
      throws com.baiwang.bop.client.BopException
    Signature: #12                          // <T:Ljava/lang/Object;>(Lcom/baiwang/bop/request/IBopRequest;Ljava/lang/String;Ljava/lang/Class<TT;>;Ljava/lang/Integer;)TT;

  public abstract void setProxy(java.lang.String, int);
    descriptor: (Ljava/lang/String;I)V
    flags: ACC_PUBLIC, ACC_ABSTRACT

  public abstract void setAuthorization(java.lang.String, java.lang.String);
    descriptor: (Ljava/lang/String;Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_ABSTRACT
}
SourceFile: "IBopClient.java"

后面部分没有验证,只列索引

访问标志

类索引、父类索引

接口索引

字段表

方法表

属性表