class file format:
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
package com.caicongyang.study.classloder;
import java.io.BufferedInputStream;
import java.io.DataInputStream;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
/**
* 解析class文件
* https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7
*
* @author caicongyang
* @version id: ClassAnalyzer, v 0.1 18/1/6 下午4:03 caicongyang1 Exp $$
*/
public class ClassAnalyzer {
public static final String FILENAME = "/Users/caicongyang1/tmp/Person.class";
public static final Boolean DEBUG = false;
/**
* 字段访问修饰符map
*/
public static Map<Integer, String> fieldAccessFlagMap = new HashMap();
/**
* 方法访问修饰符map
*/
public static Map<Integer, String> methodAccessFlagsMap = new HashMap();
/**
* 类访问修饰符map
*/
public static Map<Integer, String> accessFlagMap = new HashMap();
/**
* 常量map
*/
public static Map<Integer, Object> constantMap = new HashMap();
/**
* 常量key map
*/
public static Map<Integer, Integer> constantKeyMap = new HashMap();
@org.testng.annotations.Test
public void analyze() {
//初始化各类访问修饰符map
initAcessFlag();
initFieldAccessFlag();
initMethodAccessFlagsMap();
//开始分析class文件
DataInputStream input = null;
try {
input = new DataInputStream(new BufferedInputStream(new FileInputStream(FILENAME)));
//解析数据
analyze(input);
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
input.close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
public void analyze(DataInputStream input) throws Exception {
// 读取幻数
int magic = u4(input);
// 读取副、主版本号
int minor_ver = u2(input);
int major_ver = u2(input);
//分析常量池
analyConstant(input);
// 读取Class的声明中使用的修饰符掩码并解析
short access_flags = u2(input);
//读取类或者接口的全限定名称
short this_class_index = u2(input);
short super_class_index = u2(input);
System.out.println("当前类:"+constantMap.get((int)this_class_index));
System.out.println("超类:"+constantMap.get((int)super_class_index));
// read interfaces count:
short interfaces_count = u2(input);
System.out.println("接口数:" + interfaces_count);
// read each interface:
if (interfaces_count > 0) {
System.out.println("接口列表:");
for (int i = 0; i < interfaces_count; i++) {
short interface_index = u2(input);
}
}
//fields 数量
Short fieldsCount = u2(input);
System.out.println("字段数:" + fieldsCount);
if (fieldsCount > 0) {
System.out.println("字段列表:");
for (int i = 0; i < fieldsCount; i++) {
analyzeField(input, i);
}
}
//method数量
Short methodsCount = u2(input);
System.out.println("方法数:" + methodsCount);
if (methodsCount > 0) {
System.out.println("方法列表:");
for (int i = 0; i < methodsCount; i++) {
analyzeMethod(input, i);
}
}
/**
* 类属性数量
*/
Short attributeCount = u2(input);
if (attributeCount > 0) {
}
}
/**
* 分析常量
*/
public void analyConstant(DataInputStream input) throws Exception {
// 读取常量池表中表项的个数
short const_pool_count = u2(input);
// 读取每个常量 The constant_pool table is indexed from 1 to constant_pool_count - 1.
for (int i = 1; i < const_pool_count; ++i) {
analyzeEachConstant(input, i); //分析每个常数
}
for (Integer key : constantKeyMap.keySet()) {
constantMap.put(key, constantMap.get(constantKeyMap.get(key)));
}
for (Integer key : constantMap.keySet()) {
Object value = constantMap.get(key);
if (value instanceof String) {
String oldValue = (String) value;
if (oldValue.startsWith("L")) {
constantMap.put(key, oldValue.substring(1).replace("/", "."));
}
}
}
}
/**
* 读取常量池
*
* cp_info {
* u1 tag;
* u1 info[];
* }
*/
public void analyzeEachConstant(DataInputStream input, int index) throws IOException {
byte tag = u1(input); //读取数据类型标签
switch (tag) {
case 1: // utf-8
Short lenth = u2(input); //length
byte[] buffer = new byte[lenth];
input.readFully(buffer);
constantMap.put(index, new String(buffer));
break;
case 3: // integer
Integer intergetVlue = u4(input);
constantMap.put(index, intergetVlue);
break;
case 4: // float
Integer floatValue = u4(input);
constantMap.put(index, floatValue);
break;
case 5: // long
Integer high_bytes = u4(input);
Integer low_bytes = u4(input);
constantMap.put(index, ((long) high_bytes << 32) + low_bytes);
break;
case 6: // double
Integer DoubleHighBytesValue = u4(input);
Integer DoubleLowBytesValue = u4(input);
constantMap.put(index, ((long) DoubleHighBytesValue << 32) + DoubleLowBytesValue);
break;
case 7: // class
Short name_index = u2(input);
constantKeyMap.put(index, (int) name_index);
break;
case 8: // string
Short string_index = u2(input);
constantKeyMap.put(index, (int) string_index);
break;
case 9: // CONSTANT_Fieldref
Short class_index = u2(input);
Short name_and_type_index = u2(input);
constantKeyMap.put(index, (int) name_and_type_index);
break;
case 10: // method reference
class_index = u2(input);
name_and_type_index = u2(input);
constantKeyMap.put(index, (int) name_and_type_index);
break;
case 11: // interface method reference
class_index = u2(input);
name_and_type_index = u2(input);
constantKeyMap.put(index, (int) name_and_type_index);
break;
case 12: // name and type reference
name_index = u2(input);
Short descriptor_index = u2(input);
constantKeyMap.put(index, (int) name_index);
break;
case 15: // CONSTANT_MethodHandle
byte reference_kind = u1(input);
Short reference_index = u2(input);
constantKeyMap.put(index, (int) reference_index);
break;
case 16: // CONSTANT_MethodType
descriptor_index = u2(input);
constantKeyMap.put(index, (int) descriptor_index);
break;
case 18: // CONSTANT_InvokeDynamic
Short bootstrap_method_attr_index = u2(input);
name_and_type_index = u2(input);
constantKeyMap.put(index, (int) name_and_type_index);
break;
default:
throw new RuntimeException("Invalid constant pool flag: " + tag);
}
}
/**
* 获取属性
*/
public void analyzeField(DataInputStream input, int index) throws IOException {
short accessFlag = u2(input);
String accessFlagValue = fieldAccessFlagMap.get((int) accessFlag);
Short nameIndex = u2(input); //去读名字在常量池的索引
Short descriptorIndex = u2(input); //读取描述符在常量池的索引
Short attributesCount = u2(input);// 读取属性个数
if (attributesCount > 0) { //读取field attributes 属性
Short attributeNameIndex = u2(input);
int attributeLength = u4(input);
byte[] buffer = new byte[attributeLength];
input.readFully(buffer);
System.out.println(new String(buffer));
}
System.out.println(accessFlagValue + " 描述:" + constantMap.get((int) descriptorIndex) + " 名字:"
+ constantMap.get((int) nameIndex));
}
/**
* 获取方法
*/
public void analyzeMethod(DataInputStream input, int index) throws Exception {
Short accessFlag = u2(input); // accessFlag
String accessFlagValue = methodAccessFlagsMap.get((int) accessFlag);
Short nameIndex = u2(input);
Short descriptorIndex = u2(input);
Short attributesCount = u2(input);
if (attributesCount > 0) {
Short attributeNameIndex = u2(input);
int attributeLength = u4(input);
byte[] buffer = new byte[attributeLength];
input.readFully(buffer);
// System.out.println(new String(buffer));
}
System.out.println(accessFlagValue + " 描述:" + constantMap.get((int) descriptorIndex) + " 名字:"
+ constantMap.get((int) nameIndex));
}
/**
* 初始化所有的字段访问修饰符
*/
public void initFieldAccessFlag() {
fieldAccessFlagMap.put(0x0001, "public");
fieldAccessFlagMap.put(0x0002, "private");
fieldAccessFlagMap.put(0x0004, "protected");
fieldAccessFlagMap.put(0x0008, "static");
fieldAccessFlagMap.put(0x0010, "final");
fieldAccessFlagMap.put(0x0040, "volatile");
fieldAccessFlagMap.put(0x0080, "transient");
fieldAccessFlagMap.put(0x1000, "synthetic");
fieldAccessFlagMap.put(0x4000, "enum");
}
/**
* 初始化类访问修饰符
*/
public void initAcessFlag() {
accessFlagMap.put(0x0001, "public");
accessFlagMap.put(0x0010, "final");
accessFlagMap.put(0x0020, "super");
accessFlagMap.put(0x0200, "interface");
accessFlagMap.put(0x0400, "abstract");
accessFlagMap.put(0x1000, "synthetic");
accessFlagMap.put(0x2000, "annotation");
accessFlagMap.put(0x4000, "enum");
}
/**
* 初始化method access flag map
*/
public void initMethodAccessFlagsMap() {
methodAccessFlagsMap.put(0x0001, "public");
methodAccessFlagsMap.put(0x0002, "private");
methodAccessFlagsMap.put(0x0004, "protected");
methodAccessFlagsMap.put(0x0008, "static");
methodAccessFlagsMap.put(0x0010, "final");
methodAccessFlagsMap.put(0x0020, "synchronized");
methodAccessFlagsMap.put(0x0040, "bridge");
methodAccessFlagsMap.put(0x0080, "varargs");
methodAccessFlagsMap.put(0x0100, "native");
methodAccessFlagsMap.put(0x0400, "abstract");
methodAccessFlagsMap.put(0x0800, "strict");
methodAccessFlagsMap.put(0x1000, "synthetic"); //非源码内容,有编译器生成
}
/**
* 读取1个字符
*/
public static byte u1(DataInputStream input) throws IOException {
byte value = input.readByte();
if (DEBUG) {
System.out.println(value + ":" + Integer.toHexString(value));
}
return value;
}
/**
* 读取2个字符
*/
public static Short u2(DataInputStream input) throws IOException {
short value = input.readShort();
if (DEBUG) {
System.out.println(value + ":" + Integer.toHexString(value));
}
return value;
}
/**
* 读取4个字符
*/
public static int u4(DataInputStream input) throws IOException {
int value = input.readInt();
if (DEBUG) {
System.out.println(value + ":" + Integer.toHexString(value));
}
return value;
}
/**
* 读取8个字符
*/
public static long u8(DataInputStream input) throws IOException {
long value = input.readLong();
if (DEBUG) {
System.out.println(value + ":" + Long.toHexString(value));
}
return value;
}
}
测试结果:
当前类:Person
超类:java/lang/Object
接口数:0
字段数:2
字段列表:
private 描述:java.lang.String; 名字:name
private 描述:java.lang.Integer; 名字:age
方法数:6
方法列表:
public 描述:()V 名字:<init>
public 描述:()Ljava/lang/String; 名字:getName
public 描述:(Ljava/lang/String;)V 名字:setName
public 描述:()Ljava/lang/Integer; 名字:getAge
public 描述:(Ljava/lang/Integer;)V 名字:setAge
public 描述:()V 名字:sayHello