第6章 类文件结构
来源:互联网 发布:海马玩mac下载不了 编辑:程序博客网 时间:2024/05/16 08:26
概述:
类文件就是二进制和源码的中介
其实java可以被编译成.class文件、JRuby,Groovy等都可以编译成.class文件,然后都java虚拟机上运行
1、Class类文件的结构
采用是8位字节为基础单位的二进制流,没有空隙,按顺序,
Class 文件格式采用一种类似于C语言结构,分为无符号树和表。
无符号数属于基本的数据类型,以u1 u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节的无符号数,无符号数可以用来描述数字、索引引用、或者按照UTF-8编码构成字符串值。
2、魔数与Class文件的版本
2.1 、头4个字节称为魔数(MagicNumber):是否能被虚拟机接受的class文件, Class魔数为 : 0xCAFEBABE
2.2、4个字节存储是Class文件版本号:第5和第6字节是次版本号(Minor Version) 第7和第8个字节是主版本号(Major Version)
java版本从45开始 JDK 1.1 支持版本号为 45.0~45.65535 JDK1.7 的主版本号为51.0
写一个java编译成class文件,用winhex打开
public class ShowTime {private int m;public int inc(){return m + 1;}}
字节码
2.3、常量池
紧接版本之后就是常量池入口
第一个为u2类型的数据,代表常量池容量计数值(constant_pool_count) 从1 开始的
0x0013 十进制为19,代表18个常量 索引从1~18
常量池放入两大类常量:字面量和符号引用
字面量:如文本字符串、被声明为final的常量值等,
符号引用: 类和接口的权限定名、字段的名称和描述符、方法的名称和描述符
常量池中的每一项常量都是一个表,共有11中结构各不相同的表结构数据,第一个是一个u1类型的标志位(tag, 取值为1至12,缺少标志为2的数据类型)代表是这个常量是那种常量类型。
类型标志描述CONSTANT_Utf8_info1UTF-8编码的字符串CONSTANT_Integer_info3整型字面量CONSTANT_Float_info4浮点型字面量CONSTANT_Long_info5长整型字面量CONSTANT_Double_info6双精度浮点型字面量CONSTANT_Class_info7类或接口的符号引用CONSTANT_String_info8字符串类型字面量CONSTANT_Fieldref_info9字段的符号引用CONSTANT_Methodref_info10类中方法的符号引用CONSTANT_InterfaceMethodref_info11接口中方法的符号引用CONSTANT_NameAndType_info12字段或方法的部分符号引用
在列为A表示 0x0A 代表十进制也就是CONSTANT_Methodref_info, 可以看到它将引用CONSTANT_Class_info,第四个常量 和 CONSTANT_NameAndType第15常量
第二个常量 0x09 ,即十进制9, 也就是CONSTANT_Fieldref_info, 可以它引用第3个CONSTANT_Class_info和第16(0x10)个CONSTANT_NameAndType
其余可以通过jdk自带工具算出:javap -verbose
D:\data\spittr>javap -verbose TestClassClassfile /D:/data/spittr/TestClass.class Last modified 2017-7-26; size 275 bytes MD5 checksum 2549ac0e12d6f173f679851de1545d98 Compiled from "TestClass.java"public class TestClass minor version: 0 major version: 52 flags: ACC_PUBLIC, ACC_SUPERConstant pool: #1 = Methodref #4.#15 // java/lang/Object."<init>":()V #2 = Fieldref #3.#16 // TestClass.m:I #3 = Class #17 // TestClass #4 = Class #18 // java/lang/Object #5 = Utf8 m #6 = Utf8 I #7 = Utf8 <init> #8 = Utf8 ()V #9 = Utf8 Code #10 = Utf8 LineNumberTable #11 = Utf8 inc #12 = Utf8 ()I #13 = Utf8 SourceFile #14 = Utf8 TestClass.java #15 = NameAndType #7:#8 // "<init>":()V #16 = NameAndType #5:#6 // m:I #17 = Utf8 TestClass #18 = Utf8 java/lang/Object{ public TestClass(); descriptor: ()V flags: ACC_PUBLIC Code: stack=1, locals=1, args_size=1 0: aload_0
可以看出,咱们推算是正确的。
2.4、访问标志
常量池结束紧接着的2个字节代表访问标志(access_flags)
标志名称标志值含义ACC_PUBLIC0x0001是否为public类型ACC_FINAL0x0010是否被声明为final,只有类可设置ACC_SUPER0x0020是否允许使用invokespecial字节码指令,JDK1.2之后编译出来的类的这个标志为trueACC_INTERFACE0x0200标志这个是一个接口ACC_ABSTRACT0x0400是否为abstract类型,对于接口或抽象类来说,此标志值为true,其他值为falseACC_SYNTHETIC0x1000标志这个类并非由用户产生的ACC_ANNOTATION0x2000标识这个一个注解ACC_ENUM0x4000标识这是一个枚举根据上面编译可以找到access_flags对应位置
access_flags中一共有32个标志为可以使用,当前只定义了其中的8个,可以进行或运算进行组合
TestClass这个类被public关键之修饰但没有被声明为final和abstract,ACC_PUBLIC、ACC_SUPER标志为true,其它为false
access_flags的值: 0x0001|0x0020 = 0x0021
2.5 类索引、父类索引与接口索引集合
类索引(this_class)和父类索引(super_class)都是一个u2类型的数据,而接口索引集合(interface)是一组u2类型的数据的集合,Class文件中由这三个数据来确定这个类继承关系,类索引用于确定这个类的全限定名,父类索引用于确定这个类的父类全限定名,由于java语言不允许多重继承,所以父类索引只有一个,除了java.lang.Object之外,所有的java类都有父类,因此除了java.lang.Object外,所有java类的父类索引都不为0.
2.6、字段表集合
字段包括了类级变量或实例级变量,但是不包括在方法内部声明的变量。
包含的信息:字段的作用域(public 、private、protected)类级别还是实例级变量(static)可变性(final)、并发可见性(volatile,是否强制从主内存读取)、可否序列化(transient)、字段数据类型(基本类型、对象、数组)、字段名称
字段表结构
类型名称数量u2access_flags1u2name_index1u2descriptor_index1u2attributes_count1attribute_infoattributesattributes_count字段访问标志
ACC_PUBLIC、ACC_PRIVATE、ACC_PROTECTED不能同时选择
ACC_FINAL 、 ACC_VOLATILE 不能同时选择
接口字段必须有ACC_PUBLIC、ACC_STATIC、ACC_FINAL
name_index:简单名称
descriptor_index:方法的描述符
简单名称:没有类型和参数修饰的方法或字段名称 ,这个类中的inc()方法和字段m 的简单名称分别为inc 和m
描述字段:用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值
标志字符含义B基本类型byteC基本类型charD基本类型doubleF基本类型floatI基本类型intJ基本类型longS基本类型shortZ基本类型booleanV特殊类型voidL对象类型 如 Ljava/lang/Objectjava.lang.String[][] 二维数组 被记录为"[[Ljava/lang/String;" int[] 被记录为“[I”
用于描述符来描述方法时,按照先参数列表,后返回值得顺序描述,参数列表按照参数严格顺序放在一组小括号之内。例如void inc() 描述符为 “()V”
方法java.lang.String.toString()的描述符为 "()Ljava/lang/String", 方法 int indexOf(char[] source,int sourceOffset, int sourceCount,char[] target, int targetOffset,int targetCount, int fromIndex) 的描述符为“([CII[CIII)I”
2.7 方法表集合
方法表的结构与字段表结构一样
方法中代码存在于code 中
2.8属性表集合
不严格按照顺序了,只要不重名就可以了
2.8.1 Code属性
attribute_name_index是一项指向CONSTANT_Utf8_info类型常量的引用,常量值固定为“Code”,它代表了该属性的名称
attribute_length指示的属性值的长度,由于属性名称索引和属性长度一共占6个字节,所有最后减去6个字节
max_stack代表了操作数栈深度的最大值。
max_locals代表了局部变量表所需的存储空间。单位是Slot 32位用一个Slot 64位用两个Slot
code_length 和code用来存储java源程序编译后生成的字节码指令
code_length 虽然是u4类型的长度值 理论上达到2的32次方-1 ,实际上限制一个方法不允许超过65535条,也就是方法太长,java虚拟机拒绝编译
异常表
2.8.2 Exceptions属性
Exceptions属性的作用是列出方法可能抛出的检查异常(Checked Exceptions)也就是方法描述时在throws关键字后面列举的异常。
2.8.3、LineNumberTable属性
描述java源码行号与字节码行号(字节码的偏移量)之间的对应的关系,它并不是运行时必须的属性,但是默认会生成Class文件之中,可以在javac带参数-g:none或-g:lines选项来取消或要求生成这项信息,如果不生成,抛出异常不会指定行号,也就不可以设置断点进行调试
2.8.4 、LocalVariableTable属性
描述栈帧中局部变量表中的变量与java源码中定义变量之间的关系
默认也不会生成Class文件之中,可以通过-g:none或-g:vars 设置 ,调试的时候的参数变量没有值
2.8.5/ SourceFile属性
用于记录生成这个Class文件的源码文件名称,这个属性可选的 通过 -g:none 或-g:source关闭或要求生成这项信息。内部类例外
2.8.6、ConstantValue属性
用于通知虚拟机自动为静态变量赋值。
2.8.7 innerClasses属性
记录内部类与宿主类之前的关联
inner_class_access_flags是内部类的访问标志
总算勉强写完了。。。。。。
- 第6章 类文件结构
- 第6章 类文件结构
- 《深入理解Java虚拟机》第6章 类文件结构
- 第1章 文件结构
- 第1章 文件结构
- 第6章 类文件结构--《深入理解 Java 虚拟机》笔记
- 第 1 章文件结构索引
- 第2章 文件结构与配置
- 第6章 循环结构
- 6类文件结构
- C++编程规范---第1章 文件结构
- C++编程规范---第1章 文件结构
- 高质量C++编程之第1章 文件结构
- 第 6 章:管理数据库存储结构
- 第6章 循环结构程序设计
- 第6章 结构(笔记)
- 第6章 存储器层次结构
- 第六章 类文件结构
- python之路——装饰器
- 1006. Sign In and Sign Out (25)
- 碎片替换
- 求一个数的所有素因子
- android播放本地音乐程序
- 第6章 类文件结构
- 不平衡数据分类算法
- Markdown 初接触
- E
- Eclipse的编码设置成UTF-8格式
- 【c#】异常处理:try catch throw
- 1007. Maximum Subsequence Sum
- github解决端口22不能连接错误
- POJ 1131 Octal Fractions【高精度用java】