首页 / JAVA / 我将如何解析Java类文件常量池?
我将如何解析Java类文件常量池?
内容导读
互联网集市收集整理的这篇技术教程文章主要介绍了我将如何解析Java类文件常量池?,小编现在分享给大家,供广大互联网技能从业者学习和参考。文章包含4549字,纯文字阅读大概需要7分钟。
内容图文
![我将如何解析Java类文件常量池?](/upload/InfoBanner/zyjiaocheng/704/98850f010d374fe881edaf3577354f6b.jpg)
根据https://en.wikipedia.org/wiki/Java_class_file#General_layout – 类文件的Java常量池在文件中开始10个字节.
到目前为止,我已经能够在此之前解析所有内容(魔术来检查它是否是类文件,主要/次要版本,常量池大小)但我仍然不明白如何解析常量池.比如,是否有用于指定方法引用和其他东西的操作码?
有没有什么办法可以在以十六进制表示文本之前引用每个十六进制值,以找出以下值是什么?
我应该通过NOP(0x00)分割每组条目然后解析不是文本值的每个字节吗?
例如,我如何准确计算出每个值代表的含义?
解决方法:
您需要的类文件的唯一相关文档是The Java? Virtual Machine Specification,尤其是Chapter 4. The class File Format,如果要解析超过常量池,则为Chapter 6. The Java Virtual Machine Instruction Set.
常量池由可变长度项组成,其第一个字节确定其类型,而后者又决定了大小.大多数项目由一个或两个指向其他项目的索引组成.一个不需要任何第三方库的简单解析代码可能如下所示:
public static final int HEAD=0xcafebabe;
// Constant pool types
public 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;
static void parseRtClass(Class<?> clazz) throws IOException, URISyntaxException {
URL url = clazz.getResource(clazz.getSimpleName()+".class");
if(url==null) throw new IOException("can't access bytecode of "+clazz);
parse(ByteBuffer.wrap(Files.readAllBytes(Paths.get(url.toURI()))));
}
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: decodeString(ix, buf); continue;
case CONSTANT_Class: case CONSTANT_String: case CONSTANT_MethodType:
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"
};
private static void decodeString(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()调用弄糊涂,我用它们作为获取无符号short的方便方法,而不是getShort()& 0xffff.
上面的代码只是打印对其他池项的引用索引.为了解码项目,您可以首先将所有项目的数据存储到随机访问数据结构中,即阵列或列表,因为项目可以指代具有更高索引号的项目.并注意从索引1开始……
内容总结
以上是互联网集市为您收集整理的我将如何解析Java类文件常量池?全部内容,希望文章能够帮你解决我将如何解析Java类文件常量池?所遇到的程序开发问题。 如果觉得互联网集市技术教程内容还不错,欢迎将互联网集市网站推荐给程序员好友。
内容备注
版权声明:本文内容由互联网用户自发贡献,该文观点与技术仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 gblab@vip.qq.com 举报,一经查实,本站将立刻删除。
内容手机端
扫描二维码推送至手机访问。