服务热线:13616026886

技术文档 欢迎使用技术文档,我们为你提供从新手到专业开发者的所有资源,你也可以通过它日益精进

位置:首页 > 技术文档 > JAVA > 新手入门 > 基础入门 > 查看文档

class文件详解 (1)


  我们都知道,java编译器负责将.java文件编译成.class文件,class文件存储的是java字节码,与.java文件无关(只要你愿意写一个编译器,也可以将别的语言写的源代码编译成.class文件),本文准备详细解剖class文件的内部结构,并且把class文件结构读取并显示出来。

class文件的格式由jvm规范规定,一共有以下部分:
1. magic number,必须是0xcafebabe,用于快速识别是否是一个class文件。
2. version,包括major和minor,如果版本号超过了jvm的识别范围,jvm将拒绝执行。
3. constant pool,常量池,存放所有用到的常量。
4. access flag,定义类的访问权限。
5. this class和super class,指示如何找到this class和super class。
6. interfaces,存放所有interfaces。
7. fields,存放所有fields。
8. methods,存放所有methods。
9. attributes,存放所有attributes。

先写一个test.java:

package example.test;

public final class testclass {
    public int id = 1234567;
    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==0xcafebabe)
            system.out.println("magic number = 0xcafebabe");
        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=1; i<const_pool_count; 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 = <init>

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

const index = 17, flag = 1
 const type = utf8
     length = 4
      value = this

const index = 18, flag = 1
 const type = utf8
     length = 24
      value = lexample/test/testclass;

const index = 19, flag = 1
 const type = utf8
     length = 4
      value = test

const index = 20, flag = 1
 const type = utf8
     length = 10
      value = sourcefile

const index = 21, flag = 1
 const type = utf8
     length = 14
      value = testclass.java

我们暂时只读取到constant pool,后面的信息下次再继续 :)

参考:《inside the java virture mechine》

扫描关注微信公众号