java class文件

在正式开始之前,先说下虚拟机提供的语言无关性

Java虚拟机只会解析字节码文件,至于上面到底采用的什么高级语言,他不会去关心。下面我们来看看class字节码文件的结构。

Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在class文件之中,中间没有任何分隔符。当遇到占用8位字节以上空间的数据项时,会按照高位在前的方式分割成若干个8位字节进行存储。那么class文件的存储结构如何?你怎么区分一个数据项占用了几个字节呢?class文件采用一种类似于c语言结构体的伪结构来存储,这种伪结构只有两种数据类型:无符号数与表,表是由多个无符号数或其他表作为数据项构成的复合数据项,整个class文件本质上就是一张表,class文件格式如下:


类型


名称


数量


U4


Magic


1


U2


Minor_version


1


U2


Major_version


1


U2


Constant_pool_count


1


Cp_info


Constant_pool


Constant_pool_count-1


U2


Access_flags


1


U2


This_class


1


U2


Super_class


1


U2


Interfaces_count


1


U2


Interfaces


Interfaces_count


U2


Fields_count


1


Field_info


Fields


Fields_count


U2


Methods_count


1


Method_info


Methods


Methods_count


U2


Attributes_count


1


Attribute_info


attributes


Attributes_count

注:u1、u2、u4、u8代表1个字节、2个字节、4个字节和8个字节,以“_info”结尾表示是表。

1.魔数Magic

头4个字节,用于确定这个文件是否为一个能被虚拟机接受的class文件,该值为0xCAFEBABE,就能被虚拟机接受,否则不可以

2.次版本号Minor_version与主版本号Major_version

Java的版本号是从45开始的,JDK1.1能支持版本号为45.0~45.65535,JDK1.2能支持45.0~56.65535.下表列举了从JDK1.1到1.7之间,版本号的支持。

3.常量池

Constant_pool_count代表常量池容量计数值,如果Constant_pool_count=21,那么常量池  Constant_pool中就有20项常量,0项空出来。常量池中存放两大类常量:字面量和符号引用,字面量指文本字符串或final的常量值,符号引用指类和接口的全限定名、字段的名称和描述符、方法的名称和描述符。常量池中的每一个常量都是一个表,共有11种结构各不相同的表结构,如下:

这11种常量类型均有自己的结构,如下:

(1)CONSTANT_Class_info


类型


名称


数量


U1


Tag


1


U2


name_index


1

Tag是标志位,name_index是一个索引值,指向常量池中一个CONSTANT_utf8_info类型的常量,指向的常量代表了类或接口的全限定名。

(2)CONSTANT_Utf8_info


类型


名称


数量


U1


Tag


1


U2


Length


1


U1


Bytes


Length

Length表示这个utf-8编码的字符串长度是多少字节,后面紧跟着的长度为Length字节的连续数据是一个使用utf-8编码的字符串。U2能表达的最大值是65535,因此java程序中如果定义超过64kB的英文字符的变量或方法名,将会无法编译。

(3)CONSTANT_Integer_info


类型


名称


数量


U1


Tag


1


U4


Bytes


1

Bytes表示按照高位在前存储的int值

CONSTANT_Float_info、CONSTANT_Long_info、CONSTANT_Double_info与CONSTANT_Integer_info类似。

4.访问标志 Access_flags

5.类索引this_class、父类索引super_class与接口索引Interfaces

Class文件中由这三项数据来确定这个类的继承关系,类索引用于确定这个类的全限定名、父类索引用于确定这个类的父类的全限定名。类索引与父类索引各自指向一个类型为CONSTANT_Class_info的类描述符常量,通过CONSTANT_Class_info的name_index找到定义在CONSTANT_utf8_info类型的常量中的全限定名字符串。

6.字段表集合Fields_info

字段表集合Fields_info 用于描述接口或类中声明的变量,字段Fields包括类级变量或实例级变量,不包括在方法内部声明的变量。字段表结构如下:

字段修饰符放在access_flags项目中,与类中的access_flag项目十分类似。Name_index、descriptor_index,都是对常量池的引用,代表字段的简单名称及字段和方法的描述符。描述符的作用是用来描述字段的数据类型、方法的参数列表和返回值。如代码

Private Int m;

Public voidmin();

其中m字段与inc()方法的简单名称分别是m与inc,描述符为I、()V。

7.方法表集合Method_info

结构如下

与字段表集合类似。方法里的代码经过编译器编译成字节码指令之后,存放在方法属性表集合中一个名为code的属性里面。

8.属性表集合Attribute_info

在class文件、字段表、方法表都可以携带自己的属性表集合。Java虚拟机规范预定义了9项虚拟机实现应当能识别的属性。具体如下

对于每一个属性,它的名称需要从常量池中引用一个CONSTANT_Utf8_info类型的常量来表示,属性值的结构完全自定义,只需要说明属性值所占用的位数长度即可,符合规则的属性表结构如下:

(1)Code属性

Code属性出现在方法表的属性集合中,接口或抽象类中的方法不存在code属性。Code属性表结构如下


类型


名称


数量


说明


U2


Attribute_name_index


1


指向CONSTANT_Utf8_info型常量的索引,值为code


U4


Attribute_length


1


属性值长度


U2


Max_stack


1


操作数栈最大深度


U2


Max_locals


1


局部变量所需的存储空间


U4


Code_length


1


字节码长度


U1


Code


Code_length


存储字节码


U2


Exception_table_length


1


异常表长度


Exception_info


Exception_table


Exception_table_length


异常表,实现java异常及finally处理机制


U2


Attributes_count


1


Attribute_info


attributes


Attributes_count

(2)Exceptions属性

列举出方法中可能抛出的异常,即方法描述时在throws关键字后面列举的异常,结构如下


类型


名称


数量


说明


U2


Attribute_name_index


1


U4


Attribute_length


1


U2


Number_of_exceptions


1


异常数目


U2


Exception_index_table


Number_of_exceptions

(3)LineNumberTable属性

描述java源码行号与字节码行号之间的对应关系,结构如下


类型


名称


数量


说明


U2


Attribute_name_index


1


U4


Attribute_length


1


U2


Line_number_table_length


1


Line_number_info


Line_number_table


Line_number_table_length


包括start_pc和line_number,前者是字节码行号,后者是java源码行号

(4)LocalVariableTable属性

描述栈帧中局部变量表中的变量与java源代码中定义的变量之间的关系。

(5)SourceFile

记录生成class文件的源码文件名称。

(6)ConstantValue属性

作用是通知虚拟机自动为静态变量赋值。只有被static关键字修饰的变量才可以使用这项属性。程序中

Int x=123;与static intx=123;虚拟机对其赋值方式和时刻都不一样。

(7)InnerClasses属性

记录内部类与宿主类之间的关联。如果一个类中定义了内部类,那编译器将会为它及它包含的内部类生成InnerClasses属性。

(8)Deprecated及Synthetic属性

Deprecated标志某个类、字段、方法已经被程序标志不再使用,在代码中使用@ deprecated注释进行设置。

Synthetic代表此字段或方法不是由Java源代码直接产生的,而是由编译器自行添加的。

9.举例实战

代码实例


Package org.fenixsoft.clazz

Public class TestClass{

Private int m;

Public int inc(){

Return m+1;

}

}

使用WinHex打开class文件如下

魔数与版本号

前四个字节为魔数,紧接着的四个字节是版本号,0x00000033,转为十进制为51,说明该版本时可以被JDK1.7的虚拟机执行的class文件。

常量池

紧接着两个字节0x0016,转换成十进制为22,代表常量池中有21个常量,索引值为1~21。常量池中共11中常量类型,但每一种类型的第一个字节都是一个标志位字节。

第一个常量,标志位字节为0x07,十进制为7,表示CONSTANT_Class_info,通过前面的讲解,知道CONSTANT_Class_info类型的常量,后面是一个2字节的name_index,指向常量池中的CONSTANT_Utf8_info,2个字节为0x00002,指向常量池中第二项常量,

第二项常量的的标志位字节为0x01,表示是一个CONSTANT_Utf8_info类型的常量,后面两个字节代表长度,0x001D,换成十进制为29,即后面有29个字节的连续字符串。向后数29个,分别为

一个字节的Utf-8编码,相当于1~127的ASCII码,0x6F换成十进制为111,查ASCII码表字符为o,类似,往后推算,29个连续字符为org/fenixsoft/clazz/TestClass。

第三项常量的标志位为0x07,表示CONSTANT_Class_info,后面是一个2字节的name_index,值为0x0004,指向常量池中第四项常量。

第四项常量的标志位为01,表示是一个CONSTANT_Utf8_info类型的常量,后面两个字节代表0x0010,换成十进制为29,即后面有16个字节的连续字符串。向后数16个,分别为

为java/lang/Object。

第五项常量的标志为01,表示是一个CONSTANT_Utf8_info类型的常量,后面两个字节代表0x0001,换成十进制为1,即后面有1个字节的连续字符串。代表m

第六项常量的标志为01,表示是一个CONSTANT_Utf8_info类型的常量,后面两个字节代表0x0001,换成十进制为1,即后面有1个字节的连续字符串。代表I。

第七项常量的标志为01,表示是一个CONSTANT_Utf8_info类型的常量,后面两个字节代表0x0006,换成十进制为6,即后面有6个字节的连续字符串。代表<init>

第八项为()V

第九项为Code

第十项常量的标志位为0x0A,表示CONSTANT_Methodref_info,后面是一个2字节的index,值为0x0003,指向声明方法的类描述符CONSTANT_Class_info的索引项。接下来的2字节index为0x000B,指向名称及类型描述符CONSTANT_NameAndType_info的索引项。即为java/lang/Object.”<init>”.()V

第十一项常量的标志位为0x0C,表示CONSTANT_NameAndType,后面是一个2字节的index,值为0x0007,指向该字段或方法名称常量项的索引。接下来的2字节index为0x0008,指向该字段或方法描述符常量项的索引。即为”<init>”.()V.

一次类推,

第十二项为LineNumberTable

第十三项为LocalVariableTable

第十四项为this

第十五项为Lorg/fenixsoft/clazz/TestClass;

第十六项为inc

第十七项为()I

第十八项为org/fenixsoft/clazz/TestClass.m:I

第十九项为m:I

第二十项为SourceFile

第二十一项为TestClass.java

访问标志

常量池后的两个字节,值为0x0021,为ACC_PUBLIC与ACC_SUPER

类索引、父类索引、接口索引

值分别为0x0001、0x0003、0x0000,表示类索引为1,父类索引为3,接口索引集合大小为0.常量池中,第一项的值为org/fenixsoft/clazz/TestClass,第三项的值为java/lang/Object,即类为org/fenixsoft/clazz/TestClass,父类为java/lang/Object,没有接口

字段

接下来的两个字节0x0001,代表字段的数量为1,根据字段表的结构,后面的几项分别为

访问标志0x0002,表示ACC_PRIVATE

Name_index:0x0005,表示m

Descriptor_index:0x0006,表示I,即int

Attributes_count:0x0000,属性个数为0

即一个字段,为privateint m

方法

接下来的两个字节0x0002,代表方法的数量为2,根据方法表的结构,后面的几项分别为

第一个方法

访问标志0x0001,表示ACC_PUBLIC

Name_index:0x0007,表示<init>

Descriptor_index:0x0008,表示()V,即void()

Attributes_count:0x0001,属性个数为1

根据属性结构

Attribute_name_index:0x0009,为Code

Attribute_length:0x0000,长度为0

第二个方法是父类是父类方法,如果在子类中没有被重写,方法表集合中就不会出现父类方法的信息,因此,看不到第二个方法<clinit>

时间: 2024-10-13 18:25:49

java class文件的相关文章

java读写文件

读文件 package tool; import java.io.BufferedReader; import java.io.BufferedWriter; import java.io.File; import java.io.FileOutputStream; import java.io.FileReader; import java.io.IOException; import java.io.OutputStreamWriter; public class ReadFile { pu

Java下载文件

下面的代码简单的实现了java下载文件的步骤,看代码: protected void doPost(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { //获取文件的类名 String Path=this.getClass().getResource("/").getPath()+"JAVA笔记.txt"; //对获取的路径进

解决Eclipse建立Maven项目后无法建立src/main/java资源文件夹的办法

建立好一个Maven项目后,如果Java Resources资源文件下没有src/main/java文件夹,并且在手动创建这个文件时提示“已存在文件”. 这说明,在这个项目配置中已经有了src/main/java这个文件夹,至于为什么不显示,我暂时也还不清楚,希望谁明白了跟我下,谢了.(已解决) 第一种方法: 打开项目的classpath文件:如下 <?xml version="1.0" encoding="UTF-8"?><classpath&g

Eclipse或MyEclipse没有在java类文件上显示Spring图标的问题

Eclipse或MyEclipse没有在java类文件上显示接口图标的问题解决办法: 前: 后:

Java Class文件详解

作者:禅楼望月(http://www.cnblogs.com/yaoyinglong) Java Class文件中包含以下信息: [+]view code ClassFile { u4 magic;                                                                               //模数u2 minor_version;                                                   

java多线程文件上传服务器

描述: (1)jdk自带线程池见 JDK自带线程池配置 (2)此上传文件服务器中上传文件的后缀名通过第一段缓冲字符流传递,此缓冲字符流大小为1024,在文件接收端以1024接收.处理. 1.服务器代码如下(使用jdk自带线程池): 1 /** 2 * 服务器处理多线程问题 3 * 4 * 1.因为服务器是要很多人访问的,因此里面一定要用多线程来处理,不然只能一个人一个人的访问,那还叫Y啥服务器 5 * 6 * 2,拿上面这个文件上传的例子来说,它将每个连接它的用户封装到线程里面去,把用户要执行的

java class 文件解析

参考下面两个文章对一个class文件进行解析: http://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html#jvms-4.4.6 http://blog.163.com/hfut_quyouhu/blog/static/7847183520127214559314/ java的源代码如下: 1 package test.java.abs; 2 3 public class Abs { 4 5 /** 6 * @param args

java实现文件批量导入导出实例(兼容xls,xlsx)

1.介绍 java实现文件的导入导出数据库,目前在大部分系统中是比较常见的功能了,今天写个小demo来理解其原理,没接触过的同学也可以看看参考下. 目前我所接触过的导入导出技术主要有POI和iReport,poi主要作为一些数据批量导入数据库,iReport做报表导出.另外还有jxl类似poi的方式,不过貌似很久没跟新了,2007之后的office好像也不支持,这里就不说了. 2.POI使用详解 2.1 什么是Apache POI? Apache POI是Apache软件基金会的开放源码函式库,

Java的文件读写操作

当我们读写文本文件的时候,采用Reader是非常方便的,比如FileReader,InputStreamReader和BufferedReader.其中最重要的类是InputStreamReader, 它是字节转换为字符的桥梁.你可以在构造器重指定编码的方式,如果不指定的话将采用底层操作系统的默认编码方式,例如GBK等.使用FileReader读取文件: [java] view plain copy FileReader fr = new FileReader("ming.txt");

Java IO: 文件

原文链接  作者: Jakob Jenkov  译者: 李璟([email protected]) 在Java应用程序中,文件是一种常用的数据源或者存储数据的媒介.所以这一小节将会对Java中文件的使用做一个简短的概述.这篇文章不会对每一个技术细节都做出解释,而是会针对文件存取的方法提供给你一些必要的知识点.在之后的文章中,将会更加详细地描述这些方法或者类,包括方法示例等等. 通过Java IO读文件 如果你需要在不同端之间读取文件,你可以根据该文件是二进制文件还是文本文件来选择使用FileIn