原文链接:http://www.blogjava.net/DLevin/archive/2011/09/05/358033.html

小介:去年在读《深入解析JVM》的时候写的,记得当时还想着用自己的代码解析字节码的,最后只完成了一部分。现在都不知道还有没有保留着,貌似Apache有现成的BCEL工程可以做这件事。当时也只是为了学习。这份资料主要参考《深入解析JVM》和《Java虚拟机规范》貌似是1.2版本的,整理出来的。里面包含了一些自己的理解和用实际代码的测试。有兴趣的童鞋可以研究研究。嘿嘿。要有错误也希望能为小弟指点出来,感激不尽。:)

1.总体格式

Class File format

type

descriptor

remark

u4

magic

0xCAFEBABE

u2

minor_version

u2

major_version

u2

constant_pool_count

cp_info

constant_pool[cosntant_pool_count – 1]

index 0 is invalid

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]

2.     格式详解

2.1  magic

magic被称为“魔数”,用来标识.class文件的开头。所有合法的.class字节码都应该是该数开头,占4个字节。

2.2  major_version.minor_version

major_version.minor_version合在一起形成当前.class文件的版本号,该版本号一般由编译器产生,并且由sun定义。如59.0。它们一起占4个字节。

2.3  constant_pool

在Java字节码中,有一个常量池,用来存放不同类型的常量。由于Java设计的目的之一就是字节码需要经网络传输的,因而字节码需要比较紧凑,以减少网络传输的流量和时间。常量池的存在则可以让一些相同类型的值通过索引的方式从常量池中找到,而不是在不同地方有不同拷贝,缩减了字节码的大小。

每个常量池中的项是通过cp_info的类型来表示的,它的格式如下:

cp_info format

type

descriptor

remark

u1

tag

u1

info[]

这里tag用来表示当前常量池不同类型的项。info中存放常量池项中存放的数据。

tag中表示的数据类型:

CONSTANT_Class_info                                  (7)、

CONSTANT_Integer_info                              (3)、

CONSTANT_Long_info                                   (5)、

CONSTANT_Float_info                                  (4)、

CONSTANT_Double_info                              (6)、

CONSTANT_String_info                                 (8)、

CONSTANT_Fieldref_info                              (9)、

CONSTANT_Methodref_info                       (10)、

CONSTANT_InterfaceMethodref_info      (11)、

CONSTANT_NameAndType_info                (12)、

CONSTANT_Utf8_info                                   (1)、

注:在Java字节码中,所有boolean、byte、char、short类型都是用int类型存放,因而在常量池中没有和它们对应的项。

2.3.1    CONSTANT_Class_info

用于记录类或接口名(used to represent a class or an interface)

CONSTANT_Class_info format

type

descriptor

remark

u1

tag

CONSTANT_Class (7)

u2

name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。表示类或接口名。

注:在Java字节码中,类和接口名不同于源码中的名字,详见附件A.

2.3.2    CONSTANT_Integer_info

用于记录int类型的常量值(represent 4-byte numeric (int) constants:)

CONSTANT_Integer_info

type

descriptor

remark

u1

tag

CONSTANT_Integer (3)

u4

bytes

整型常量值

2.3.3    CONSTANT_Long_info

用于记录long类型的常量值(represent 8-byte numeric (long) constants:)

CONSTANT_Long_info

type

descriptor

remark

u1

tag

CONSTANT_Long (5)

u4

high_bytes

长整型的高四位值

u4

low_bytes

长整型的低四位值

2.3.4    CONSTANT_Float_info

用于记录float类型的常量值(represent 4-byte numeric (float) constants:)

CONSTANT_Float_info

type

descriptor

remark

u1

tag

CONSTANT_Float(4)

u4

bytes

单精度浮点型常量值

几个特殊值:0x7f800000 => Float.POSITIVE_INFINITY、0xff800000 => Float.NEGATIVE_INFINITY、

0x7f800001 to 0x7fffffff => Float.NaN、0xff800001 to 0xffffffff => Float.NaN

2.3.5    CONSTANT_Double_info

用于记录double类型的常量值(represent 8-byte numeric (double) constants:)

CONSTANT_Double_info

type

descriptor

remark

u1

tag

CONSTANT_Double(6)

u4

high_bytes

双精度浮点的高四位值

u4

low_bytes

双精度浮点的低四位值

几个特殊值:0x7ff0000000000000L => Double.POSITIVE_INFINITY、

0xfff0000000000000L => Double.NEGATIVE_INFINITY

0x7ff0000000000001L to 0x7fffffffffffffffL => Double.NaN 、

0xfff0000000000001L to 0xffffffffffffffffL => Double.NaN

2.3.6    CONSTANT_String_info

用于记录常量字符串的值(represent constant objects of the type String:)

CONSTANT_String_info

type

descriptor

remark

u1

tag

CONSTANT_String(8)

u2

string_index

constant_pool中的索引,CONSTANT_Utf8_info类型。表示String类型值。

2.3.7    CONSTANT_Fieldref_info

用于记录字段信息(包括类或接口中定义的字段以及代码中使用到的字段)。

CONSTANT_Fieldref_info

type

descriptor

remark

u1

tag

CONSTANT_Fieldref(9)

u2

class_index

constant_pool中的索引,CONSTANT_Class_info类型。记录定义该字段的类或接口。

u2

name_and_type_index

constant_pool中的索引,CONSTANT_NameAndType_info类型。指定类或接口中的字段名(name)和字段描述符(descriptor)。

 

2.3.8    CONSTANT_Methodref_info

用于记录方法信息(包括类中定义的方法以及代码中使用到的方法)。

CONSTANT_Methodref_info

type

descriptor

remark

u1

tag

CONSTANT_Methodref(10)

u2

class_index

constant_pool中的索引,CONSTANT_Class_info类型。记录定义该方法的类。

u2

name_and_type_index

constant_pool中的索引,CONSTANT_NameAndType_info类型。指定类中扽方法名(name)和方法描述符(descriptor)。

 

2.3.9    CONSTANT_InterfaceMethodref_info

用于记录接口中的方法信息(包括接口中定义的方法以及代码中使用到的方法)。

CONSTANT_InterfaceMethodref_info

type

descriptor

remark

u1

tag

CONSTANT_InterfaceMethodref(11)

u2

class_index

constant_pool中的索引,CONSTANT_Class_info类型。记录定义该方法的接口。

u2

name_and_type_index

constant_pool中的索引,CONSTANT_NameAndType_info类型。指定接口中的方法名(name)和方法描述符(descriptor)。

 

2.3.10    CONSTANT_NameAndType_info

记录方法或字段的名称(name)和描述符(descriptor)(represent a field or method, without indicating which class or interface type it belongs to:)。

CONSTANT_NameAndType_info

type

descriptor

remark

u1

tag

CONSTANT_NameAndType (12)

u2

name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段或方法的名称。

u2

descriptor_index

constant_pool中的索引,CONSTANT_utf8_info类型。指定字段或方法的描述符(见附录C

2.3.11    CONSTANT_Utf8_info

记录字符串的值(represent constant string values. String content is encoded in modified UTF-8.)

modifie

d UTF-8 refer to :

http://download.ora

cle.com/javase/1.4.2/docs/api/java/io/DataInputStream.html

CONSTANT_Utf8_info

type

descriptor

remark

u1

tag

CONSTANT_Utf8 (1)

u2

length

bytes所代表

的字符串的长度

u1

bytes[length]

字符串的byte数据,可以通过DataInputStream中的readUtf()方法(实例方法或静态方法读取该二进制的字符串的值。)

2.4  access_flags

指定类或接口的访问权限。

类或接口的访问权限

Flag Name

Value

Remarks

ACC_PUBLIC

0x0001

pubilc,包外可访问。

ACC_FINAL

0x0010

final,不能有子类。

ACC_SUPER

0x0020

用于兼容早期编译器,新编译器都设置该标记,以在使用 invokespecial指令时对子类方法做特定处理。

ACC_INTERFACE

0x0200

接口,同时需要设置:ACC_ABSTRACT。不可同时设置:ACC_FINAL、ACC_SUPER、ACC_ENUM

ACC_ABSTRACT

0x0400

抽象类,无法实例化。不可和ACC_FINAL同时设置。

ACC_SYNTHETIC

0x1000

synthetic,由编译器产生,不存在于源代码中。

ACC_ANNOTATION

0x2000

注解类型(annotation),需同时设置:ACC_INTERFACE、ACC_ABSTRACT

ACC_ENUM

0x4000

枚举类型

2.5  this_class

this_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口。

2.6  super_class

super_class是指向constant pool的索引值,该值必须是CONSTANT_Class_info类型,指定当前字节码定义的类或接口的直接父类。只有Object类才没有直接父类,此时该索引值为0。并且父类不能是final类型。接口的父类都是Object类。

2.7  interfaces

interfaces数组记录所有当前类或接口直接实现的接口。interfaces数组中的每项值都是一个指向constant pool的索引值,这些值必须是CONSTANT_Class_info类型。数组中接口的顺序和源代码中接口定义的顺序相同。

2.8  fields

fields数组记录了类或接口中的所有字段,包括实例字段和静态字段,但不包含父类或父接口中定义的字段。fields数组中每项都是field_info类型值,它描述了字段的详细信息,如名称、描述符、字段中的attribute等。

field_info

type

descriptor

remark

u2

access_flags

记录字段的访问权限。见2.8.1

u2

name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定字段的名称。

u2

descriptor_index

constant_pool中的索引,CONSTANT_Utf8_info类型,指定字段的描述符(见附录C)。

u2

attributes_count

attributes包含的项目数。

attribute_info

attributes[attributes_count]

字段中包含的Attribute集合。见2.8.2-2.8.7

注:fields中的项目和CONSTANT_Fieldref_info中的项目部分信息是相同的,他们主要的区别是CONSTANT_Fieldref_info中的项目不仅包含了类或接口中定义的字段,还包括在字节码中使用到的字段信息。不过这里很奇怪,为什么field_info结构中不把name_index和descriptor_index合并成fieldref_index,这样的class文件不是更加紧凑吗??不知道这是sun因为某些原因故意这样设计还是这是他们的失误??

2.8.1    字段访问权限

字段的访问权限

Flag Name

Value

Remarks

ACC_PUBLIC

0x0001

pubilc,包外可访问。

ACC_PRIVATE

0x0002

private,只可在类内访问。

ACC_PROTECTED

0x0004

protected,类内和子类中可访问。

ACC_STATIC

0x0008

static,静态。

ACC_FINAL

0x0010

final,常量。

ACC_VOILATIE

0x0040

volatile,直接读写内存,不可被缓存。不可和ACC_FINAL一起使用。

ACC_TRANSIENT

0x0080

transient,在序列化中被忽略的字段。

ACC_SYNTHETIC

0x1000

synthetic,由编译器产生,不存在于源代码中。

ACC_ENUM

0x4000

enum,枚举类型字段

注:接口中的字段必须同时设置:ACC_PUBLIC、ACC_STATIC、ACC_FINAL

2.8.2    ConstantValue Attribute JVM识别)

ConstantValue Attribute

type

descriptor

remark

u2

attribute_name_index

constant_pool中的索引,CONSTANT_Utf8_info类型。指定Attribute的名称(“ConstantValue”)。

u4

attribute_length

该Attribute内容的字节长度(固定值:2)

u2

constant_value_index

constant_pool中的索引,

CONSTANT_Integer_info(int,boolean,char、short、byte)、

CONSTANT_Float_info(float)、

Constant_Double_info(double)、

CONSTANT_Long_info(long)

CONSTANT_String_info(String)类型

每个常量字段(final,静态常量或实例常量)都包含有且仅有一个ConstantValue Attribute。ConstantValue Attribute结构用于存储一个字段的常量值。

对一个静态常量字段,该常量值会在类或接口被初始化之前,由JVM负责赋给他们,即它在任何静态字段之前被赋值。

对一个非静态常量字段,该值会被虚拟机忽略,它的赋值由生成的实例初始化函数(<init>)实现。如类:

class A {

public static final int fa = 10;

public final int fa2 = 30;

private static int sa = 20;

static {

sa = 30;

}

}

生成的字节码如下:

// Compiled from Test.java (version 1.6 : 50.0, super bit)

class org.levin.insidejvm.miscs.staticinit.A {

 public static final int fa = 10;

 public final int fa2 = 30;

private static int sa;

 static {};

0 bipush 20

2 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]

5 bipush 30

7 putstatic org.levin.insidejvm.miscs.staticinit.A.sa : int [16]

10 return

 public A();

0 aload_0 [this]

1 invokespecial java.lang.Object() [21]

4 aload_0 [this]

    5 bipush 30

     7 putfield org.levin.insidejvm.miscs.staticinit.A.fa2 : int [23]

10 return

2.8.3    Synthetic Attribute

参考2.11.1

2.8.4    Signature Attribute

参考2.11.2

2.8.5    Deprecated Attribute

参考2.11.3

2.8.6    RuntimeVisibleAnnotations Attribute

参考2.11.4

2.8.7    RuntimeInvisibleAnnotations Attribute

参考2.11.5

于2010-12-19

Java字节码(.class文件)格式详解(一)的更多相关文章

  1. Java之字节码(2) - .class文件格式详解

    转载来自 小介:去 年在读<深入解析JVM>的时候写的,记得当时还想着用自己的代码解析字节码的,最后只完成了一部分.现在都不知道还有没有保留着,貌似Apache有现 成的BCEL工程可以做 ...

  2. 空手套白狼,硬阅java字节码class文件

    如下,是一些java字节码也就是原始的class文件,当应用部署到线上之后,我们能够看到的也就是这样的字样了.那么怎样解呢?就让我们一起,来解读解读字节码吧! Offset A B C D E F C ...

  3. Beyound Compare中比较java字节码class文件

    背景 项目维护的时候版本混乱或者外出在现场项目排错的时候难免要比对两个jar/class/war文件的源代码. 通常情况下这个时候我们用jd-gui直接把文件拖进去比对,这种情况只适合单一文件的比对. ...

  4. Java字节码 小结

    Reference javap 基本使用方法 深入理解java字节码 从Java代码到字节码 Java字节码.class文件案例分析 字节码 核心概念 Class文件是8位字节流,按字节对齐.之所以称 ...

  5. 图文详解 Java 字节码,让你秒懂全过程

    原文地址:https://blog.csdn.net/AliceSmith1/article/details/80051153 即便对那些有经验的Java开发人员来说,阅读已编译的Java字节码也很乏 ...

  6. 我的书籍《深入解析Java编译器:源码剖析与实例详解》就要出版了

    一个十足的技术迷,2013年毕业,做过ERP.游戏.计算广告,在大公司呆过,但终究不满足仅对技术的应用,在2018年末离开了公司,全职写了一本书<深入解析Java编译器:源码剖析与实例详解> ...

  7. @使用javap反编译Java字节码文件

    在Sun公司提供的JDK中,就已经内置了Java字节码文件反编译工具javap.exe(位于JDK安装目录的bin文件夹下). 我们可以在dos窗口中使用javap来反汇编指定的Java字节码文件.在 ...

  8. WAL日志文件名称格式详解

    转自:http://blog.osdba.net/534.html WAL日志文件名称格式详解 PostgreSQL的WAL日志文件在pg_xlog目录下,一般情况下,每个文件为16M大小: osdb ...

  9. OpenJDK源码研究笔记(八)-详细解析如何读取Java字节码文件(.class)

    在上一篇OpenJDK源码研究笔记(七)–Java字节码文件(.class)的结构中,我们大致了解了Java字节码文件的结构. 本篇详细地介绍了如何读取.class文件的大部分细节. 1.构造文件  ...

随机推荐

  1. MyEclipse下查看Java API帮助文档

    每次重装JDK或者升级JDK时,都会忘了如何使MyEclipse关联帮助文档.然后,再花十几分钟重新google搜索,麻烦! 首先下载Javadoc api帮助文档,google搜一下就行了. MyE ...

  2. Random Integer Generator

    先占坑.以后再修改 昨天遇到一道题, Given int Rand(1) =  0或者 1- uniformly distributed,   write a function to implemen ...

  3. Android TabHost中实现标签的滚动以及一些TabHost开发的奇怪问题

    最近在使用TabHost的时候遇到了一些奇怪的问题,在这里总结分享备忘一下. 首先说一点TabActivity将会被FragmentActivity所替代,但是本文中却是使用的TabActivity. ...

  4. Linux/Unix 系统分析命令速查手册

    1.Hardware CPU information: cat /proc/cpuinfo 物理core个数: 统计core 逻辑CPU个数:统计processor Memory informatio ...

  5. Java汉字排序(3)按笔划排序

    对于包含汉字的字符串来说,排序的方式主要有两种:一种是拼音,一种是笔画. 本文就讲述如何实现按笔划排序的比较器(Comparator). 作者:Jeff 发表于:2007年12月21日 11:27 最 ...

  6. bash 读入文件

    Suppose we have a file contains the following information, termed input_file: A       0 B       1 C ...

  7. Java面试题-并发工具

    1. 如何实现一个流控程序,用于控制请求的调用次数?

  8. sublime text 2 配置文件

    安装好 sublime text 2后不进行任何设置,如果允许 sublime text 2 软件的话,会在以下目录自动生成一个 sublime text 2 的文件夹,这个文件夹是用来放配置文件的, ...

  9. 解决windows下vim方向键变成 ABCD 的问题

    一.问题描述: windows下面要安装git --> 安装了 msys2 -->安装并更新了 vim(7.4),然后在使用过程中发现vim不能使用  BACKSPACE 键,按方向键会打 ...

  10. 【转】@Override must override a superclass method 问题解决

    原文网址:http://www.blogjava.net/anchor110/articles/339352.html 如果在使用Eclipse开发Java项目时,在使用 @Override 出现以下 ...