我们都知道 Java编译器负责将 java文件编译成 class文件 class文件存储的是java字节码 与 java文件无关(只要你愿意写一个编译器 也可以将别的语言写的源代码编译成 class文件) 本文准备详细解剖class文件的内部结构 并且把class文件结构读取并显示出来 Class文件的格式由JVM规范规定 一共有以下部分 magic number 必须是 xCAFEBABE 用于快速识别是否是一个class文件 version 包括major和minor 如果版本号超过了JVM的识别范围 JVM将拒绝执行 constant pool 常量池 存放所有用到的常量 access flag 定义类的访问权限 this class和super class 指示如何找到this class和super class interfaces 存放所有interfaces fields 存放所有fields methods 存放所有methods attributes 存放所有attributes 先写一个Test java package example test; public final class TestClass public int id = ; public void test() 然后编译 放在C:\\example\\test\\Test class 我们用Java来读取和分析class ClassAnalyzer的功能便是读取Test class 分析结构 然后显示出来 package classfile format; import java io *; public class ClassAnalyzer public static void main(String[] args) DataInputStream input = null; try input = new DataInputStream(new BufferedInputStream(new FileInputStream( C:\\\\example\\\\test\\\\TestClass class ))); analyze(input); catch(Exception e) System out println( Analyze failed! ); finally try input close(); catch(Exception e) public static void analyze(DataInputStream input) throws IOException // read magic number: int magic = input readInt(); if(magic== xCAFEBABE) System out println( magic number = xCAFEBABE ); else throw new RuntimeException( Invalid magic number! ); // read minor version and major version: short minor_ver = input readShort(); short major_ver = input readShort(); System out println( Version = + major_ver + + minor_ver); // read constant pool: short const_pool_count = input readShort(); System out println( constant pool size = + const_pool_count); // read each constant: for(int i= ; i analyzeConstant(input, i); public static void analyzeConstant(DataInputStream input, int index) throws IOException byte flag = input.readByte(); // for read: byte n8; short n16; int n32; long n64; float f; double d; byte[] buffer; System.out.println("\\nconst index = " + index + ", flag = " + (int)flag); switch(flag) case 1: // utf-8 string System.out.println(" const type = Utf8"); n16 = input.readShort(); System.out.println(" length = " + n16); buffer = new byte[n16]; input.readFully(buffer); System.out.println(" value = " + new String(buffer)); break; case 3: // integer System.out.println(" const type = Integer"); n32 = input.readInt(); System.out.println(" value = " + n32); break; case 4: // float System.out.println(" const type = Float"); f = input.readFloat(); System.out.println(" value = " + f); break; case 5: // long System.out.println(" const type = Long"); n64 = input.readLong(); System.out.println(" value = " + n64); break; case 6: // double System.out.println(" const type = Double"); d = input.readDouble(); System.out.println(" value = " + d); break; case 7: // class or interface reference System.out.println(" const type = Class"); n16 = input.readShort(); System.out.println(" index = " + n16 + " (where to find the class name)"); break; case 8: // string System.out.println(" const type = String"); n16 = input.readShort(); System.out.println(" index = " + n16); break; case 9: // field reference System.out.println(" const type = Fieldref"); n16 = input.readShort(); System.out.println("class index = " + n16 + " (where to find the class)"); n16 = input.readShort(); System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)"); break; case 10: // method reference System.out.println(" const type = Methodref"); n16 = input.readShort(); System.out.println("class index = " + n16 + " (where to find the class)"); n16 = input.readShort(); System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)"); break; case 11: // interface method reference System.out.println(" const type = InterfaceMethodref"); n16 = input.readShort(); System.out.println("class index = " + n16 + " (where to find the interface)"); n16 = input.readShort(); System.out.println("nameAndType = " + n16 + " (where to find the NameAndType)"); break; case 12: // name and type reference System.out.println(" const type = NameAndType"); n16 = input.readShort(); System.out.println(" name index = " + n16 + " (where to find the name)"); n16 = input.readShort(); System.out.println(" descripter = " + n16 + " (where to find the descriptor)"); break; default: throw new RuntimeException("Invalid constant pool flag: " + flag); 输出结果为: magic number = 0xCAFEBABE Version = 48.0 constant pool size = 22 const index = 1, flag = 1 const type = Utf8 length = 22 value = example/test/TestClass const index = 2, flag = 7 const type = Class index = 1 (where to find the class name) const index = 3, flag = 1 const type = Utf8 length = 16 value = java/lang/Object const index = 4, flag = 7 const type = Class index = 3 (where to find the class name) const index = 5, flag = 1 const type = Utf8 length = 2 value = id const index = 6, flag = 1 const type = Utf8 length = 1 value = I const index = 7, flag = 1 const type = Utf8 length = 6 value = const index = 8, flag = 1 const type = Utf8 length = 3 value = ()V const index = 9, flag = 1 const type = Utf8 length = 4 value = Code const index = 10, flag = 12 const type = NameAndType name index = 7 (where to find the name) descripter = 8 (where to find the descriptor) const index = 11, flag = 10 const type = Methodref class index = 4 (where to find the class) nameAndType = 10 (where to find the NameAndType) const index = 12, flag = 3 const type = Integer value = 1234567 const index = 13, flag = 12 const type = NameAndType name index = 5 (where to find the name) descripter = 6 (where to find the descriptor) const index = 14, flag = 9 const type = Fieldref class index = 2 (where to find the class) nameAndType = 13 (where to find the NameAndType) const index = 15, flag = 1 const type = Utf8 length = 15 value = LineNumberTable const index = 16, flag = 1 const type = Utf8 length = 18 value = LocalVariableTable cha138/Article/program/Java/JSP/201311/19269