栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

我将如何解析Java类文件常量池?

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

我将如何解析Java类文件常量池?

与类文件唯一相关的文档是 The Java®
Virtual Machine
Specification
,
especially Chapter 4. The class File
Format and,
if you are going to parse more than the constant pool, Chapter 6. The Java
Virtual Machine Instruction
Set.

常量池由长度可变的项组成,这些项的第一个字节
确定其类型,而类型又决定了大小。大多数项目由
指向其他项目的一两个索引组成。
不需要任何第三方库的简单解析代码可能如下所示:

public static final int HEAD=0xcafebabe;// Constant pool typespublic static final byte CONSTANT_Utf8    = 1;public static final byte CONSTANT_Integer = 3;public static final byte CONSTANT_Float   = 4;public static final byte CONSTANT_Long    = 5;public static final byte CONSTANT_Double  = 6;public static final byte CONSTANT_Class   = 7;public static final byte CONSTANT_String  = 8;public static final byte CONSTANT_FieldRef= 9;public static final byte CONSTANT_MethodRef          =10;public static final byte CONSTANT_InterfaceMethodRef =11;public static final byte CONSTANT_NameAndType        =12;public static final byte CONSTANT_MethodHandle       =15;public static final byte CONSTANT_MethodType         =16;public static final byte CONSTANT_InvokeDynamic      =18;public static final byte CONSTANT_Module  =19;public static final byte CONSTANT_Package =20;static void parseRtClass(Class<?> clazz) throws IOException, URISyntaxException {    URL url = clazz.getResource(clazz.getSimpleName()+".class");    if(url==null) throw new IOException("can't access bytepre of "+clazz);    Path p = Paths.get(url.toURI());    if(!Files.exists(p))        p = p.resolve("/modules").resolve(p.getRoot().relativize(p));    parse(ByteBuffer.wrap(Files.readAllBytes(p)));}static void parseClassFile(Path path) throws IOException {    ByteBuffer bb;    try(FileChannel ch=FileChannel.open(path, StandardOpenOption.READ)) {        bb=ch.map(FileChannel.MapMode.READ_ONLY, 0, ch.size());    }    parse(bb);}static void parse(ByteBuffer buf) {    if(buf.order(ByteOrder.BIG_ENDIAN).getInt()!=HEAD) {        System.out.println("not a valid class file");        return;    }    int minor=buf.getChar(), ver=buf.getChar();    System.out.println("version "+ver+'.'+minor);    for(int ix=1, num=buf.getChar(); ix<num; ix++) {        String s; int index1=-1, index2=-1;        byte tag = buf.get();        switch(tag) { default:     System.out.println("unknown pool item type "+buf.get(buf.position()-1));     return; case CONSTANT_Utf8: depreString(ix, buf); continue; case CONSTANT_Class: case CONSTANT_String: case CONSTANT_MethodType: case CONSTANT_Module: case CONSTANT_Package:     s="%d:t%s ref=%d%n"; index1=buf.getChar();     break; case CONSTANT_FieldRef: case CONSTANT_MethodRef: case CONSTANT_InterfaceMethodRef: case CONSTANT_NameAndType:     s="%d:t%s ref1=%d, ref2=%d%n";     index1=buf.getChar(); index2=buf.getChar();     break; case CONSTANT_Integer: s="%d:t%s value="+buf.getInt()+"%n"; break; case CONSTANT_Float: s="%d:t%s value="+buf.getFloat()+"%n"; break; case CONSTANT_Double: s="%d:t%s value="+buf.getDouble()+"%n"; ix++; break; case CONSTANT_Long: s="%d:t%s value="+buf.getLong()+"%n"; ix++; break; case CONSTANT_MethodHandle:     s="%d:t%s kind=%d, ref=%d%n"; index1=buf.get(); index2=buf.getChar();     break;  case CONSTANT_InvokeDynamic:     s="%d:t%s bootstrap_method_attr_index=%d, ref=%d%n";     index1=buf.getChar(); index2=buf.getChar();     break;        }        System.out.printf(s, ix, FMT[tag], index1, index2);    }}private static String[] FMT= {    null, "Utf8", null, "Integer", "Float", "Long", "Double", "Class",    "String", "Field", "Method", "Interface Method", "Name and Type",    null, null, "MethodHandle", "MethodType", null, "InvokeDynamic",    "Module", "Package"};private static void depreString(int poolIndex, ByteBuffer buf) {    int size=buf.getChar(), oldLimit=buf.limit();    buf.limit(buf.position()+size);    StringBuilder sb=new StringBuilder(size+(size>>1)+16)        .append(poolIndex).append(":tUtf8 ");    while(buf.hasRemaining()) {        byte b=buf.get();        if(b>0) sb.append((char)b);        else        { int b2 = buf.get(); if((b&0xf0)!=0xe0)     sb.append((char)((b&0x1F)<<6 | b2&0x3F)); else {     int b3 = buf.get();     sb.append((char)((b&0x0F)<<12 | (b2&0x3F)<<6 | b3&0x3F)); }        }    }    buf.limit(oldLimit);    System.out.println(sb);}

不要被这些

getChar()
呼叫弄糊涂了,我将它们用作
获取未签名的缩写的便捷方法,而不是
getShort()&0xffff

上面的代码仅打印其他池项目的引用索引。
为了对项目进行解码,您可以首先将所有项目的数据存储到
随机访问数据结构中,即数组或

List
由于项目可能引用
具有较高索引号的项目。并从索引开始
1



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/495041.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号