前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >手写Java类解析器-02.读取常量池

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

作者头像
付威
发布2020-05-07 14:54:09
4270
发布2020-05-07 14:54:09
举报

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

javap -verbose AppMain.class >>AppMain.txt

输出的内容:

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的规范,常量池的基本结构如下:

cp_info {
     u1 tag;
     u1 info[]; 
}

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

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的模式,对应代码:

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的解析方法:

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;
	}
}

(本文完)

本文参与 腾讯云自媒体分享计划,分享自作者个人站点/博客。
原始发表:2020-04-14 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档