手写Java类解析器-02.读取常量池

2020-05-07 14:54:09 浏览数 (1)

前面说到读取魔数和版本号,今天讨论下读取常量池,我们可以借助javap -verbose的命令查看对应的class文件的内容。

代码语言:javascript复制
javap -verbose AppMain.class >>AppMain.txt

输出的内容:

代码语言:javascript复制
Classfile /Users/fuwei/work/rzclassreader/target/classes/org/rz/AppMain.class
  Last modified 2020-3-20; size 2972 bytes
  MD5 checksum fbb55a90b8c5daddb71f86a69f9baa6d
  Compiled from "AppMain.java"
public class org.rz.AppMain
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
    #1 = Methodref          #37.#97       // java/lang/Object."<init>":()V
    #2 = Long               34122202019029l
    #4 = Fieldref           #11.#98       // org/rz/AppMain.indentityCardNo:J
    ...
  #146 = Utf8               Ljava/io/PrintStream;
  #147 = Utf8               java/io/PrintStream
  #148 = Utf8               println

由于篇幅的原因不展示全部,从上面的信息可以看出,我们的常量池有148个常量,每一个常量的类型不同,分别有Methodref,LongUtf-8等等。

根据JVM的规范,常量池的基本结构如下:

代码语言:javascript复制
cp_info {
     u1 tag;
     u1 info[]; 
}

u1代表一个标记为常量的基本类型的标记,对应的数据类型如下:

代码语言:javascript复制
public class ConstantPoolType {
	public static final int CONSTANT_Utf8 = 1;
	public static final int CONSTANT_Integer = 3;
	public static final int CONSTANT_Float = 4;
	public static final int CONSTANT_Long = 5;
	public static final int CONSTANT_Double = 6;
	public static final int CONSTANT_Class = 7;
	public static final int CONSTANT_String = 8;
	public static final int CONSTANT_Fieldref = 9;
	public static final int CONSTANT_Methodref = 10;
	public static final int CONSTANT_InterfaceMethodref = 11;
	public static final int CONSTANT_NameAndType = 12;
	public static final int CONSTANT_MethodHandle = 15;
	public static final int CONSTANT_MethodType = 16;
	public static final int CONSTANT_InvokeDynamic = 18;
 
}

基于上面的认识,可以简单的设计成一个switch-case的模式,对应代码:

代码语言:javascript复制
private CPInfo[] cpInfos;
private final int count;

public ConstantPool(ClassReadCursor cursor) throws IOException {
  count = cursor.readUnsignedShort();
  cpInfos = new CPInfo[count];
  init(cursor);
  
}
public void init(ClassReadCursor cursor) throws IOException {
  for (int i = 1; i < count ; i  ) {
    int tag = cursor.readUnsignedByte();
    switch (tag) {
      case CONSTANT_Utf8: {
        cpInfos[i] = new CONSTANT_Utf8_info(cursor);
        break;
      }
      case CONSTANT_Integer: {
        cpInfos[i] = new CONSTANT_Integer_info(cursor);
        break;
      }
      case CONSTANT_Float: {
        cpInfos[i] = new CONSTANT_Float_info(cursor);
        break;
      }
      case CONSTANT_Long: {
        cpInfos[i] = new CONSTANT_Long_info(cursor);
        i  ;
        break;
      }
      case CONSTANT_Double: {
        cpInfos[i] = new CONSTANT_Double_info(cursor);
        i  ;
        break;
      }
      case CONSTANT_String: {
        cpInfos[i] = new CONSTANT_String_info(cursor);
        break;
      }
      case CONSTANT_Fieldref: {
        cpInfos[i] = new CONSTANT_Fieldref_info(cursor);
        break;
      }
      
      case CONSTANT_Methodref: {
        cpInfos[i] = new CONSTANT_Methodref_info(cursor);
        break;
      }
      case CONSTANT_InterfaceMethodref: {
        cpInfos[i] = new CONSTANT_InterfaceMethodref_info(cursor);
        break;
      }
      case CONSTANT_NameAndType: {
        cpInfos[i] = new CONSTANT_NameAndType_info(cursor);
        break;
      }
      case CONSTANT_Class: {
        cpInfos[i] = new CONSTANT_Class_info(cursor);
        break;
      }
      case CONSTANT_MethodHandle: {
        cpInfos[i] = new CONSTANT_MethodHandle_info(cursor);
        break;
      }
      case CONSTANT_MethodType: {
        cpInfos[i] = new CONSTANT_MethodType_info(cursor);
        break;
      }
    }
  }
}

其中LongDouble类型占用两个字节,索引需要加1。 由于篇幅的原因不能把每一个解析的方法都贴出来,通篇的代码并不利于阅读,只贴出来一个CONSTANT_Utf8的解析方法:

代码语言:javascript复制
public class CONSTANT_Utf8_info  extends CPInfo {
//	private  int length;
	private  String text;
	public CONSTANT_Utf8_info(ClassReadCursor cusor) throws IOException {
		super(ConstantPoolType.CONSTANT_Utf8);
		text=cusor.readUTF();
 
	}
	public String getText() {
		return text;
	}
}

(本文完)

0 人点赞