大橙子网站建设,新征程启航
为企业提供网站建设、域名注册、服务器等服务
这篇文章主要介绍“JVM入门之什么是Class文件”,在日常操作中,相信很多人在JVM入门之什么是Class文件问题上存在疑惑,小编查阅了各式资料,整理出简单好用的操作方法,希望对大家解答”JVM入门之什么是Class文件”的疑惑有所帮助!接下来,请跟着小编一起来学习吧!
目前创新互联已为近1000家的企业提供了网站建设、域名、网站空间、网站托管维护、企业网站设计、蕉岭网站维护等服务,公司将坚持客户导向、应用为本的策略,正道将秉承"和谐、参与、激情"的文化,与客户和合作伙伴齐心协力一起成长,共同发展。
Java作为一门编程语言能够获得如此广泛的认可,除了它有结构严谨,面向对象的编程语言之外,它还具备一个非常突出的特性:一次编写
,到处运行
,即编写的程序可以摆脱硬件平台束缚,它提供了一种相对安全的内存管理和访问机制,避免了绝大部分内存泄漏和指针越界问题。
谈到jvm,就离不开与jdk和jre的对比,那么它们之间到底有什么区别和联系呢?
我们先看这样一幅架构图,
从集合关系上看,jdk>jre>jvm
,除了范围上的区别,我们应该了解的是它们所包含的功能上的差别及各自发挥的作用。
jdk
jdk的全称是Java Development kit
(java开发工具包),我们可以把程序设计语言
、java虚拟机
、java类库
这三部分统称为jdk,jdk是用于支持java程序开发的最小环境
。Developer可以很容易的使用里面的方法以减少代码量,里面同时包含jre和一些开发的小工具(如编译工具javac),同时包含了jre。
jre
jre的全称是Java Running Environment
(java运行时环境 ),可以把java类库API中的javaSE的API子集
和java虚拟机
这两部分统称为JRE,JRE是支持java程序运行的标准环境
。
jvm
jvm的全称java virtual machine
(java 虚拟机),它只认识XXX.class文件
,虚拟机可以识别这种文件的字节码指令并调用操作系统上的API,正是这个原因,java才可以跨平台使用
。
不管怎么说,jvm终究是一个软件
,那么它是怎样屏蔽底层的操作系统
、硬件
、CPU指令层
的细节呢?我们以Java程序为例来分析它的执行流程。
实现语言无关性的基础是虚拟机和字节码的存储格式,Java虚拟机不与包括Java语言在内的任何程序语言绑定,它只与Class文件这种特定的二进制文件格式所关联。
Class文件
是Java语言保持良好兼容性的关键,那么Class文件的结构是什么呢,存储那些内容呢?
事实上,Class文件是一组以8字节为基础单位的二进制流
,各个数据项目严格的按照顺序紧凑地排列在文件之中,中间没有添加任何分割符,这使得整个Class文件存储的内容几乎全部是程序运行的必要数据,没有空隙存在。
《Java虚拟机规范》规定了Class文件格式采用一种类似C语言结构体的伪结构来存储数据,这种伪结构只包含两种数据类型,即无符号数
和表
。
无符号数
无符号数属于基本
数据类型
,可以用来描述数字
、索引引用
、数量值
或按照UTF-8编码构成的字符串值
表
表是由多个无符号数或者其他表作为数据项构成的
复合数据类型
,为了便于区分,所有表的命名的都以_info
结尾。
class文件通过固定的数据结构排列顺序并且每种数据结构指定了占用的字节长度来紧凑的在组成了完整的可读文件,jvm只需要从文件开始的地方一步一步的读取能够完全的解析出这个类文件的内容。
来感受一下字节码文件长啥样!
在class文件中,前4个字节被称为魔数
,它能够唯一确定class文件能否被虚拟机接受。其实,魔数还广泛应用在GIF、JPEG等文件头中。
紧接着魔数的4个字节存储的是Class文件的版本号
,第5和第6个字节是次版本号
,第7和第8个字节是主版本号
。Java的版本号是从45开始的,JDK1.1之后的每个JDK大版本发布的主版本号加1(JDK1.0~1.1使用了45.0~45.3的版本号),《Java虚拟机规范》在Class文件校验部分明确要求了即使文件格式并未发生变化,虚拟机也必须拒绝执行超过其版本号的Class文件,所以高版本的JDK能向下兼容以前版本的Class文件,但是不能运行以后版本的Class文件。
在魔数、版本号之后,下一个位置存储的就是常量池
,常量池可以认为是Class文件里的资源仓库
,它是Class文件结构中与其它项目关联最多的数据。常量池的前两个字节占有的位置称为常量池计数器
(constant_pool_cont),它记录着常量池的组成元素常量池项
(cp_info)的个数。
常量池计数器是从1开始的,而不是从0开始的,即如果常量池计数器的值constant_pool_count=22
,则后面的cp_info的个数就为21,这是因为在指定class文件规范的时候,将第0项常量空出来是为了满足某些指向常量池的索引值的数据在特定的情况下表达”不引用任何一个常量池项
“,这种情况下可以将索引值设置为0来表示。
常量池中主要存放两大类常量:字面量
和符号引用
,字面量可以理解为Java语言层面上的的常量
概念,如文本字符串
、被声明为final
的常量值等。而符号引用则包括类和结构的全限定名称
、字段的名称和描述符
、方法的名称和描述符
等。
Class文件存储了方法
、字段
等各种类信息,但是它仅仅是存储了而已,它是不能反映出方法、字段等信息在内存中的布局。这是因为Java语言并不像C++语言有链接的概念,但是Java语言在虚拟机加载时会进行动态的连接
,虚拟机将会从常量池中获得对应的符号引用
,再在类创建时或运行时进行解析
、翻译
到具体的内存地址之中。
在常量池结束之后,紧接着的2个字节代表访问标志
(access_flags),这个标志用于识别一些类或者接口层次的访问信息
。比如标识一个Class是类还是接口;是否定义为public类型;是否定义为abstract类型;是否被声明为final。
标志值与标志名称的对应关系如下:
标志值 | 标志名称 |
---|---|
0x0001 | ACC_PUBLIC |
0x0010 | ACC_FINAL |
0x0020 | ACC_SUPER |
0x0100 | ACC_INTERFACE |
0x0200 | ACC_ABSTRACT |
0x1000 | ACC_SYNTHETIC |
0x2000 | ACC_ANNOTATION |
0x4000 | ACC_ENUM |
标志名称就是限定访问信息的,如ACC_PUBLIC表示为是否为public类型,ACC_FINAL表示为是否被声明为final,其它的标志类似。
访问标志结束后,紧接就是索引
,包括类索引
、父类索引
与接口索引集合
,Class文件可以由这三项数据来确定该类型的继承关系。我们先了解下这三类索引的各有什么作用
类索引
类索引用于确定这个类的全限定名
,通过类的全限定名找到这个类,所以类索引的作用就是为找出class文件所描述的这个类叫什么名字。
父类索引
父类索引用于确定这个类的父类的全限定名
,有Java语言不支持多重继承,所以除了Object外,其它类的父类索引只有一个。
接口索引的集合
它是用来描述这个类实现哪些接口
,由于接口是多实现的,所以这些实现的接口将会按顺序排列在索引集合中。接口索引的集合在入口处会有一个计数器
,它用来表示集合中索引的数量
,如果该类没有实现接口,则该计数器为0。
Note:类索引、父类索引和接口索引集合指向常量池中的符号引用。
字段表集合用于描述接口
或者类中声明的变量
,它有若干个字段表组成,字段表集合的就类似一个数组的结构,jvm在编译类的时候,会将类中的定义的字段的个数统计到字段计数器中,然后将每一个字段信息以结构的形式组成起来放在字段计数器之后。其结
特别需要注意的是,这里的字段包括类变量
以及实例变量
,但是不包括方法内部的声明的局部变量。
我们在思考这样一个问题,字段表存储的是那些信息,这些信息是什么呢,事实上,字段表存储的就是字段信息,我们整理如下
修饰符(public、protected、private)
实例变量还是类变量(被static修饰)
可变性(final)
并发可见性(volatile)
是否可被序列化(transient)
字段数据类型(基本类型、对象、数组)
字段名称
既然字段有那么多信息,他的存储的形式是怎样的呢?事实上,字段的存储和我们写字段的形式是一样的,不懂?那我们就回顾下!
在字节码,JVM定义了filed_info结构体来描述字段,它的形式也很简单,就是一个结构体,
Field_info{ access_flags; name_index; descriptor_index; attribute_count; attributes;}
access_flags
是访问标志,与前面讲解的访问标志功能是类似的,紧接着access_flags标志的是name_index
和descriptor_index
,它们是对常量池的引用,分别代表着字段的简单名称以及字段和方法的描述符。简单名称就是指没有类型和参数修饰的方法或者字段名称;字段和方法描述符指的是基本类型的头一个大写字母,如基本数据类型是byte,则方法描述修饰符是B。attribute_count
表示的属性计数器,attributes
包含三部分内容(属性名称索引、属性的长度和常量值索引)
方法表集合结构同字段表集合的结构是一样的,我们这里主要讲解它们之间的区别,剩下都可以按照属性表集合来学习。
区别一
对于方法来说,volatile关键字和transient关键字是不修饰方法的,所以访问标志中不会有相应的标志;但是synchronized、native、stricftp和abstract关键字是可以修饰方法的,所以在会有相应的访问标志。
区别二
与字段相比,方法内是有代码的,那么方法内的代码存储到哪里去了呢?事实上,对于方法里的Java代码,经Javac编译器编译成字节码的指令后,存放在方法属性表集合中会有一个名为Code的属性里面。
Class文件的主要结构都说完了,我们从宏观的角度看看Class文件到底是什么样,话不多说,来看图
到此,关于“JVM入门之什么是Class文件”的学习就结束了,希望能够解决大家的疑惑。理论与实践的搭配能更好的帮助大家学习,快去试试吧!若想继续学习更多相关知识,请继续关注创新互联网站,小编会继续努力为大家带来更多实用的文章!