Java字节码(.class文件)格式详解(一)

小介:去年在读《深入解析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

时间: 2025-01-02 15:23:21

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

使用技巧:对Java编程中的文件操作详解

编程|技巧|详解 一.获得控制台用户输入的信息 /** *//**获得控制台用户输入的信息 * @return * @throws IOException */ public String getInputMessage() throws IOException...{ System.out.println("请输入您的命令∶"); byte buffer[]=new byte[1024]; int count=System.in.read(buffer); char[] ch=new

Java 多线程断点下载文件_详解

基本原理:利用URLConnection获取要下载文件的长度.头部等相关信息,并设置响应的头部信息.并且通过URLConnection获取输入流,将文件分成指定的块,每一块单独开辟一个线程完成数据的读取.写入.通过输入流读取下载文件的信息,然后将读取的信息用RandomAccessFile随机写入到本地文件中.同时,每个线程写入的数据都文件指针也就是写入数据的长度,需要保存在一个临时文件中.这样当本次下载没有完成的时候,下次下载的时候就从这个文件中读取上一次下载的文件长度,然后继续接着上一次的位

Java字节码(.class文件)格式详解(三)

2.11 在ClassFile.method_info.field_info中同时存在的Attribute 2.11.1     Synthetic Attribute Synthetic Attribute用于指示当前类.接口.方法或字段由编译器生成,而不在源代码中存在(不包含类初始函数和实例初始函数).相同的功能还有一种方式就是在类.接口.方法或字段的访问权限中设置ACC_SYNTHETIC标记.   Synthetic Attribute由JDK1.1中引入,以支持内嵌类和接口(neste

PHP 序列化(serialize)格式详解

详解 由 andot 写的非常经典介绍PHP序列化的文章,原文来自: http://www.coolcode.cn/?p=170 1.前言PHP (从 PHP 3.05 开始)为保存对象提供了一组序列化和反序列化的函数:serialize.unserialize.不过在 PHP 手册中对这两个函数的说明仅限于如何使用,而对序列化结果的格式却没做任何说明.因此,这对在其他语言中实现 PHP 方式的序列化来说,就比较麻烦了.虽然以前也搜集了一些其他语言实现的 PHP 序列化的程序,不过这些实现都不完

C 和 C++ 文件操作详解

来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551662.html 来源:http://www.cnblogs.com/likebeta/archive/2012/06/16/2551780.html C++的文件操作 在C++中,有一个stream这个类,所有的I/O都以这个"流"类为基础的,包括我们要认识的文件I/O,stream这个类有两个重要的运算符: 1.插入器(<<) 向流输出数据.比如说系统有一

关于java字节码框架ASM的学习

一.什么是ASM ASM是一个java字节码操纵框架,它能被用来动态生成类或者增强既有类的功能.ASM 可以直接产生二进制 class 文件,也可以在类被加载入 Java 虚拟机之前动态改变类行为.Java class 被存储在严格格式定义的 .class文件里,这些类文件拥有足够的元数据来解析类中的所有元素:类名称.方法.属性以及 Java 字节码(指令).ASM从类文件中读入信息后,能够改变类行为,分析类信息,甚至能够根据用户要求生成新类. 使用ASM框架需要导入asm的jar包,下载链接:

掌握Java字节码(转)

Java是一门设计为运行于虚拟机之上的编程语言,因此它需要一次编译,处处运行(当然也是一次编写,处处测试).因此,安装到你系统上的JVM是原生的程序,而运行在它之上的代码是平台无关的.Java字节码就是你写的源代码的中间表现形式,也就是你的代码编译后的产物.你的class文件就是字节码. 简单点说,字节码就是JVM使用的代码集,它在运行时可能会被JIT编译器编译成本地代码. 你玩过汇编语言或者机器代码吗?字节码就是类似的东西,不过业界中许多人也很少会用及它,因为基本没这个必要.然而它对于理解程序

Java字节码浅析(三)

英文原文链接,译文链接,原文作者:James Bloom,译者:有孚 从Java7开始,switch语句增加了对String类型的支持.不过字节码中的switch指令还是只支持int类型,并没有增加对其它类型的支持.事实上switch语句对String的支持是分成两个步骤来完成的.首先,将每个case语句里的值的hashCode和操作数栈顶的值(译注:也就是switch里面的那个值,这个值会先压入栈顶)进行比较.这个可以通过lookupswitch或者是tableswitch指令来完成.结果会路

Java Web请求与响应实例详解_java

Servlet最主要作用就是处理客户端请求并作出回应,为此,针对每次请求,Web容器在调用service()之前都会创建两个对象,分别是HttpServletRequest和HttpServletResponse.其中HttpServletRequest封装HTTP请求消息,HttpServletResponse封装HTTP响应消息.需要注意的是,Web服务器运行过程中,每个Servlet都会只创建一个实例对象,不过每次请求都会调用Servlet实例的service(ServletRequest