Class文件详解 (1)

转载 2007年09月24日 17:41:00
我们都知道,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,后面的信息下次再继续 :)

 

JVM系列文章(三):Class文件内容解析

作为一个程序员,仅仅知道怎么用是远远不够的。起码,你需要知道为什么可以这么用,即我们所谓底层的东西。 那到底什么是底层呢?我觉得这不能一概而论。以我现在的知识水平而言:对于Web开发者,TCP/...
  • u012422829
  • u012422829
  • 2015年06月25日 10:32
  • 4647

Class文件详解 (1)

我们都知道,Java编译器负责将.java文件编译成.class文件,class文件存储的是java字节码,与.java文件无关(只要你愿意写一个编译器,也可以将别的语言写的源代码编译成.class文...
  • asklxf
  • asklxf
  • 2004年10月25日 18:24
  • 6195

Java Class文件格式解析及实例

JAVA无关性概述 Java语言从刚诞生开始曾提出一个非常著名的宣言:“一次编写,到处运行(Write Once, Run Anywhere)”。Sun公司和其他虚拟机公司发布了许多可以运行在不同操...
  • kittyboy0001
  • kittyboy0001
  • 2014年02月14日 14:18
  • 2829

深入理解Java Class文件格式(九)

经过前八篇关于class文件的博客, 关于class文件格式的内容也基本上讲完了。 本文是关于class文件格式的最后一篇。 在这篇博客中, 将会讲解关于方法的几个属性。 理解这篇博客的内容, 对于理...
  • brave2211
  • brave2211
  • 2014年03月29日 01:40
  • 6516

java底层知识(1)--Class文件详解

本文转载自:http://blog.csdn.net/anhuidelinger/article/details/8947791 尊重原创前言如同讲汇编必先讲计算机组成原理,在开始字节码之前,我们先...
  • Mrzhoug
  • Mrzhoug
  • 2016年05月05日 22:11
  • 807

java编译后的文件出现xx$1.class的原因

java编译后的文件名字带有$接数字的就是匿名内部类的编译结果,接名字的就是内部类的编译结果 例如:TestFrame$1.class是匿名内部类的编译结果,TestFrame$MyJob.clas...
  • u013703363
  • u013703363
  • 2017年03月29日 09:10
  • 2532

产生多于的class$1.class的原因

在java中,如果在一个类中定义了内部类,刚会生成:    super&this.class的文件,如果给某个控件添加了Listener事件,则会生成    super&i.class的文件,其中i为...
  • dy_paradise
  • dy_paradise
  • 2010年10月02日 16:10
  • 7265

class文件详解

1、基本概念能够被JVM识别,加载并执行的文件格式2、生成class文件1、通过IDE自动帮我们build 2、手动通过javac去生成class文件(javac xxx.java) 可以直接通过...
  • xq_sq
  • xq_sq
  • 2017年07月07日 00:46
  • 117

Class文件详解

我们都知道,Java编译器负责将.java文件编译成.class文件,class文件存储的是java字节码,与.java文件无关(只要你愿意写一个编译器,也可以将别的语言写的源代码编译成.class文...
  • alex197963
  • alex197963
  • 2007年04月22日 19:35
  • 763

java编译时有时候会出现***$1.class这样的文件

$后面跟数字是匿名类编译出来的 $后面跟文字是内部类编译出来的
  • stubbornness1219
  • stubbornness1219
  • 2016年11月03日 10:10
  • 566
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:Class文件详解 (1)
举报原因:
原因补充:

(最多只允许输入30个字)