1 准备工作

获取class文件byte[]

 public static byte[] getFileBytes(File file) {
try (FileInputStream fileInputStream = new FileInputStream(file)) {
int available = fileInputStream.available();
byte[] data=new byte[available];
fileInputStream.read(data,0,available-1);
return data;
} catch (Exception e) {
e.printStackTrace();
}
return null;
}

这里使用jdk的ByteBuffer包装bytes

ByteBuffer data = ByteBuffer.wrap(getFileBytes(file));

因为ByteBuffer没有无符号的读取方法,所以自己实现一下,也可以直接用netty的Bytebuf,里面方法齐全

    // 图方便直接返回int
private int readUnsignedByte(ByteBuffer data) {
return data.get() & 0xff;
} // 图方便直接返回int
private int readUnsignedShort(ByteBuffer data) {
return data.getShort() & 0xffff;
} private long readUnsignedInt(ByteBuffer data) {
return data.getInt() & 0xffffffffL;
}

定义class文件结构

参考: https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html

    private static class ClassFileStructure {
long magic;
int minorVersion;
int majorVersion;
int constantPoolCount;
ConstantPool[] constantPool;
int accessFlags;
int thisClass;
int superClass;
int interfacesCount;
int[] interfaces;
int fieldsCount;
FieldInfo[] fields;
int methodsCount;
MethodInfo[] methods;
int attributesCount;
AttributeInfo[] attributes;
}

2 开始解析

2.1 magic

    private void magic(ClassFileStructure structure, ByteBuffer data) {
structure.magic = readUnsignedInt(data);
}

2.2 minorVersion

    private void minorVersion(ClassFileStructure structure, ByteBuffer data) {
structure.minorVersion = readUnsignedShort(data);
}

2.3 majorVersion

    private void majorVersion(ClassFileStructure structure, ByteBuffer data) {
structure.majorVersion = readUnsignedShort(data);
}

2.4 constantPoolCount

   private void constantPoolCount(ClassFileStructure structure, ByteBuffer data) {
structure.constantPoolCount = readUnsignedShort(data);
}

2.5 ConstantPool[]

ConstantPool不同tag解析方式不同,定义抽象类ConstantPool,子类按规则解析

    private abstract static class ConstantPool {
int tag; public ConstantPool(int tag) {
this.tag = tag;
} abstract void parse(ByteBuffer data);
}

子类实现ConstantPool

ConstantUtf8:

 private class ConstantUtf8 extends ConstantPool {
int length;
byte[] bytes; public ConstantUtf8(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.length = readUnsignedShort(data);
bytes = new byte[this.length];
for (int i = 0; i < this.length; i++) {
bytes[i] = (byte) readUnsignedByte(data);
}
}
}

ConstantMethodHandle:

 private class ConstantMethodHandle extends ConstantPool {
short referenceKind;
int referenceIndex; public ConstantMethodHandle(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.referenceKind = (short) readUnsignedByte(data);
this.referenceIndex = readUnsignedShort(data);
}
}

ConstantMethodType:

 private class ConstantMethodType extends ConstantPool {
int descriptorIndex; public ConstantMethodType(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.descriptorIndex = readUnsignedShort(data);
}
}

ConstantClass:

private class ConstantClass extends ConstantPool {
int nameIndex; public ConstantClass(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
}
}

ConstantClass:

   private class ConstantClass extends ConstantPool {
int nameIndex; public ConstantClass(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
}
}

ConstantFieldref:


private class ConstantFieldref extends ConstantPool {
int classIndex;
int nameAndTypeIndex; public ConstantFieldref(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}

ConstantMethodref:

private class ConstantMethodref extends ConstantPool {
int classIndex;
int nameAndTypeIndex; public ConstantMethodref(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}

ConstantInterfaceMethodref:

 private class ConstantInterfaceMethodref extends ConstantPool {
int classIndex;
int nameAndTypeIndex; public ConstantInterfaceMethodref(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.classIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}

ConstantString:

 private class ConstantString extends ConstantPool {
int stringIndex; public ConstantString(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.stringIndex = readUnsignedShort(data);
}
}

ConstantInteger:

private class ConstantInteger extends ConstantPool {
long bytes; public ConstantInteger(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.bytes = readUnsignedInt(data);
}
}

ConstantFloat:

private class ConstantFloat extends ConstantPool {
long bytes; public ConstantFloat(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.bytes = readUnsignedInt(data);
}
}

ConstantLong:

private class ConstantLong extends ConstantPool {
long highBytes;
long lowBytes; public ConstantLong(int tag) {
super(tag);
} @Override
void parse(ByteBuffer data) {
this.highBytes = readUnsignedInt(data);
this.lowBytes = readUnsignedInt(data);
}
}

ConstantDouble:

   private class ConstantDouble extends ConstantPool {
long highBytes;
long lowBytes;
public ConstantDouble(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.highBytes = readUnsignedInt(data);
this.lowBytes = readUnsignedInt(data);
}
}

ConstantNameAndType:

  private class ConstantNameAndType extends ConstantPool {
int nameIndex;
int descriptorIndex;
public ConstantNameAndType(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
}
}

ConstantInvokeDynamic:

  private class ConstantInvokeDynamic extends ConstantPool {
int bootstrapMethodAttrIndex;
int nameAndTypeIndex;
public ConstantInvokeDynamic(int tag) {
super(tag);
}
@Override
void parse(ByteBuffer data) {
this.bootstrapMethodAttrIndex = readUnsignedShort(data);
this.nameAndTypeIndex = readUnsignedShort(data);
}
}

以上是所有 constantPool 子类型,现在开始解析

坑:“所有 8 字节常量都占用文件constant_pool表中的两个条目class。 如果

CONSTANT_Long_infoorCONSTANT_Double_info结构是constant_pool表中索引n处的项目,则池中的下一个可用项目位于索引n +2 处。

constant_pool 索引n +1 必须有效但被视为不可用 。 回想起来,让 8 字节常量占用两个常量池条目是一个糟糕的选择。”

 private void constantPool(ClassFileStructure structure, ByteBuffer data) {
structure.constantPool = new ConstantPool[structure.constantPoolCount - 1];
for (int i = 0; i < structure.constantPool.length; i++) {
int type = readUnsignedByte(data);
int index = i;
switch (type) {
case 1: //
structure.constantPool[i] = new ConstantUtf8(type);
break;
case 3: //
structure.constantPool[i] = new ConstantInteger(type);
break;
case 4:
structure.constantPool[i] = new ConstantFloat(type);
break;
case 5:
structure.constantPool[i] = new ConstantLong(type);
i++;// 占2位
break;
case 6:
structure.constantPool[i] = new ConstantDouble(type);
i++;// 占2位
break;
case 7: //
structure.constantPool[i] = new ConstantClass(type);
break;
case 8: //
structure.constantPool[i] = new ConstantString(type);
break;
case 9: //
structure.constantPool[i] = new ConstantFieldref(type);
break;
case 10: //
structure.constantPool[i] = new ConstantMethodref(type);
break;
case 11: //
structure.constantPool[i] = new ConstantInterfaceMethodref(type);
break;
case 12: //
structure.constantPool[i] = new ConstantNameAndType(type);
break;
case 15: //
structure.constantPool[i] = new ConstantMethodHandle(type);
break;
case 16: //
structure.constantPool[i] = new ConstantMethodType(type);
break;
case 18: //
structure.constantPool[i] = new ConstantInvokeDynamic(type);
break;
default:
throw new ParserException("class file parser exception");
}
structure.constantPool[index].parse(data);
}
}

2.6 accessFlags

    private void accessFlags(ClassFileStructure structure, ByteBuffer data) {
structure.accessFlags = readUnsignedShort(data);
}

2.7 thisClass

    private void thisClass(ClassFileStructure structure, ByteBuffer data) {
structure.thisClass = readUnsignedShort(data);
}

2.8 superClass

    private void superClass(ClassFileStructure structure, ByteBuffer data) {
structure.superClass = readUnsignedShort(data);
}

2.9 interfacesCount

    private void interfacesCount(ClassFileStructure structure, ByteBuffer data) {
structure.interfacesCount = readUnsignedShort(data);
}

2.10 int[] interfaces

    private void interfaces(ClassFileStructure structure, ByteBuffer data) {
structure.interfaces = new int[structure.interfacesCount];
for (int i = 0; i < structure.interfacesCount; i++) {
structure.interfaces[i] = readUnsignedShort(data);
}
}

2.11 fieldsCount

    private ClassFile fieldsCount(ClassFileStructure structure, ByteBuffer data) {
structure.fieldsCount = readUnsignedShort(data);
return this;
}

2.12 FieldInfo[] fields

FieldInfo:

 private class FieldInfo {
int accessFlags;
int nameIndex;
int descriptorIndex;
int attributesCount;
AttributeInfo[] attributes; public FieldInfo parse(ByteBuffer data) {
this.accessFlags = readUnsignedShort(data);
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
this.attributesCount = readUnsignedShort(data);
this.attributes = new AttributeInfo[attributesCount];
for (int i = 0; i < this.attributesCount; i++) {
this.attributes[i] = new AttributeInfo().parse(data);
}
return this;
}
}

AttributeInfo:

  private class AttributeInfo {

        int attributeNameIndex;
long attributeLength;
short[] info; public AttributeInfo parse(ByteBuffer data) {
this.attributeNameIndex = readUnsignedShort(data);
this.attributeLength = readUnsignedInt(data);
this.info = new short[(int) attributeLength];
for (int i = 0; i < this.attributeLength; i++) {
this.info[i] = (short) readUnsignedByte(data);
}
return this;
}
}
    private void fields(ClassFileStructure structure, ByteBuffer data) {
structure.fields = new FieldInfo[structure.fieldsCount];
for (int i = 0; i < structure.fieldsCount; i++) {
structure.fields[i] = new FieldInfo().parse(data);
}
}

2.13 methodsCount

    private ClassFile methodsCount(ClassFileStructure structure, ByteBuffer data) {
structure.methodsCount = readUnsignedShort(data);
return this;
}

2.14 MethodInfo[]

MethodInfo:

 private class MethodInfo {
int accessFlags;
int nameIndex;
int descriptorIndex;
int attributesCount;
AttributeInfo[] attributes; public MethodInfo parse(ByteBuffer data) {
this.accessFlags = readUnsignedShort(data);
this.nameIndex = readUnsignedShort(data);
this.descriptorIndex = readUnsignedShort(data);
this.attributesCount = readUnsignedShort(data);
this.attributes = new AttributeInfo[attributesCount];
for (int i = 0; i < this.attributesCount; i++) {
this.attributes[i] = new AttributeInfo().parse(data);
}
return this;
}
}
    private void methods(ClassFileStructure structure, ByteBuffer data) {
structure.methods = new MethodInfo[structure.methodsCount];
for (int i = 0; i < structure.methodsCount; i++) {
structure.methods[i] = new MethodInfo().parse(data);
}
}

2.15 attributesCount

    private void attributesCount(ClassFileStructure structure, ByteBuffer data) {
structure.attributesCount = readUnsignedShort(data);
}

2.16 AttributeInfo[]

    private void attributes(ClassFileStructure structure, ByteBuffer data) {
structure.attributes = new AttributeInfo[structure.attributesCount];
for (int i = 0; i < structure.attributesCount; i++) {
structure.attributes[i] = new AttributeInfo().parse(data);
}
}

Class文件解析的更多相关文章

  1. CocosStudio文件解析工具CsdAnalysis

    起因 因为工作需要,所以需要使用CocosStudio来制作界面动画什么的.做完了发现需要找里边对象的时候会有很长一串代码,感觉不是很爽.之前写OC代码的时候可以吧程序中的对象指针跟编辑器中的对象相对 ...

  2. 通过正则表达式实现简单xml文件解析

    这是我通过正则表达式实现的xml文件解析工具,有些XHTML文件中包含特殊符号,暂时还无法正常使用. 设计思路:常见的xml文件都是单根树结构,工具的目的是通过递归的方式将整个文档树装载进一个Node ...

  3. 八、Android学习第七天——XML文件解析方法(转)

    (转自:http://wenku.baidu.com/view/af39b3164431b90d6c85c72f.html) 八.Android学习第七天——XML文件解析方法 XML文件:exten ...

  4. phpcms V9 首页模板文件解析

    在了解了<phpcms V9 URL访问解析>之后,我们已经知道首页最终执行的是content模块下index控制器的init方法. 下面, 我们逐步分析过程如下: 第一.首页默认执行的是 ...

  5. (转)AVI文件格式解析+AVI文件解析工具

    AVI文件解析工具下载地址:http://download.csdn.net/detail/zjq634359531/7556659 AVI(Audio Video Interleaved的缩写)是一 ...

  6. itextSharp 附pdf文件解析

    一.PdfObject: pdf对象 ,有9种,对象是按照对象内涵来分的,如果按照对象的使用规则来说,对象又分为间接对象和直接对象.间接对象是PDF中最常用的对象,如前面对象集合里面的,所有对象都是间 ...

  7. 《热血传奇2》wix、wil文件解析Java实现

    在百度上搜索java+wil只有iteye上一篇有丁点儿内容,不过他说的是错的!或者说是不完整的,我个人认为我对于热血传奇客户端解析还是有一定研究的,请移步: <JMir——Java版热血传奇2 ...

  8. paper 37 : WINCE的BIB文件解析

    WINCE的BIB文件解析 BIB的全称为Binary Image Builder,在Wince编译过程中的最后MakeImage阶段会用到BIB文件,BIB文件的作用是指示构建系统如何构建二进制映像 ...

  9. 如何让你的Apache支持include文件解析和支持shtml的相关配置

    源地址:http://www.itokit.com/2011/0430/65992.html Apache支持include文件解析shtml首先要应该修改Apache配置文件httpd.conf . ...

  10. android基础知识13:AndroidManifest.xml文件解析

    注:本文转载于:http://blog.csdn.net/xianming01/article/details/7526987 AndroidManifest.xml文件解析. 1.重要性 Andro ...

随机推荐

  1. 输入法词库解析(六)QQ 拼音分类词库.qpyd

    详细代码:https://github.com/cxcn/dtool 前言 .qpyd 是 QQ 拼音输入法 6.0 以下版本所用的词库格式,可以在 http://cdict.qq.pinyin.cn ...

  2. vscode-jupyter快捷键

    运行本单元 ctrl + enter 运行本单元,新建一个单元 shift + enter 运行本单元,在其下方新建一个单元 alt + enter 在上方插入一个新单元 a 在下方插入新单元 b 复 ...

  3. VLAN的配置

    1 vlan的概念和作用 虚拟局域网(VLAN)是一组逻辑上的设备和用户,这些设备和用户并不受物理位置的限制,可以根据功能.部门等因素将它们组织起来.相互之间的通信就好像它们在同一个网段中一样. 虚拟 ...

  4. Nginx反代服务器进阶学习最佳配置实践指南

    转载自:https://www.bilibili.com/read/cv16150010?spm_id_from=333.999.0.0 0x00 编译实践 描述:在企业线上生产环境中推荐进行Ngin ...

  5. 使用Prometheus和Grafana监控emqx集群

    以 Prometheus为例: emqx_prometheus 支持将数据推送至 Pushgateway 中,然后再由 Promethues Server 拉取进行存储. 注意:emqx_promet ...

  6. 安装Alertmanager,nginx配置二级路径代理访问

    安装配置 Alertmanager wget https://github.com/prometheus/alertmanager/releases/download/v0.20.0/alertman ...

  7. 学习记录-Python的局部变量和全局变量

    目录 1 定义 2 作用域的重要性 2.1 全局作用域中的代码不能使用任何局部变量 2.2 局部作用域中的代码可以访问全局变量 2.3 不同局部作用域中的变量不能相互调用 2.4 在不同的作用域中,可 ...

  8. 关于vmware虚拟机的ova/ovf转换成aws上的AMI镜像

    很多时候,我们会有这样的需求,需要将DC中vmware虚拟化的服务器,迁移到aws上,我们就得先将vmware虚拟机导出,然后转换 关于vmvare虚拟的导出备份,一般有ova(Open Virtua ...

  9. 洛谷P4011 【网络流24题】 孤岛营救问题 (BFS+状压)

    一道妙题啊......(不知道为什么这道题的标签是网络流,不需要用网络流啊) 如果没有门和钥匙,连边(边权为1)求最短路就行了. 但是有这两个因素的限制,我们采用分层建图的思想,一共2p层,每层对应持 ...

  10. Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test (default-test) on project StuMavenDemo1: There are test failures.

    Maven使用Test的时候出现 Failed to execute goal org.apache.maven.plugins:maven-surefire-plugin:2.12.4:test ( ...