当前位置: 首页 > news >正文

java虚拟机:class文件结构

一、前言

学习Java的朋友应该都知道Java从刚开始的时候就打着平台无关性的旗号,说“一次编写,到处运行”,其实说到无关性,Java平台还有另外一个无关性那就是语言无关性,要实现语言无关性,那么Java体系中的class的文件结构或者说是字节码就显得相当重要了,其实Java从刚开始的时候就有两套规范,一个是Java语言规范,另外一个是Java虚拟机规范,Java语言规范只是规定了Java语言相关的约束以及规则,而虚拟机规范则才是真正从跨平台的角度去设计的。

或许大部分程序员都认为Java虚拟机执行Java程序是一件理所当然和天经地义的事,但时至今日,商业机构和开源机构已经在Java语言之外发展出一大批在Java虚拟机之上运行的语言,如Clojure、Groovy、JRuby、Jython、Scale等。使用Java编译器可以把Java代码编译为存储字节码的Class文件,使用JRuby等其它语言的编译器一样可以把程序代码编译成Class文件,Java之所以能够跨平台运行,是因为Java虚拟机可以载入和执行同一种平台无关的字节码。也就是说,实现语言平台无关性的基础是虚拟机和字节码存储格式,虚拟机并不关心Class的来源是什么语言,只要它符合Class文件应有的结构就可以在Java虚拟机中运行。

二、Class文件编码与组成

1)Class文件是由byte(8bit)为基础的字节流构成的,这些字节流之间都严格按照规定的顺序排列,并且字节之间不存在任何空隙,对于超过8个字节的数据,将按照Big-Endian的顺序存储的,也就是说高位字节存储在低的地址上面,而低位字节存储到高地址上面,其实这也是class文件要跨平台的关键,因为PowerPC架构的处理采用Big-Endian的存储顺序,而x86系列的处理器则采用Little-Endian的存储顺序,因此为了Class文件在各中处理器架构下保持统一的存储顺序,虚拟机规范必须对其进行统一。

2) Class文件结构采用类似C语言的结构体来存储数据的,主要有两类数据项,无符号数和表,无符号数用来表述数字,索引引用以及字符串等,比如 u1,u2,u4,u8分别代表1个字节,2个字节,4个字节,8个字节的无符号数,而表是有多个无符号数以及其它的表组成的复合结构。可能大家看到这里 对无符号数和表到底是上面也不是很清楚,不过不要紧,等下面实例的时候,我会再以实例来解释。
明确了上面的两点以后,我们接下来后来看看Class文件中按照严格的顺序排列的字节流都具体包含些什么数据:

ClassFile {
    u4             magic;
    u2             minor_version;
    u2             major_version;
    u2             constant_pool_count;
    cp_info        constant_pool[constant_pool_count-1];
    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];
}

在看上图的时候,有一点我们需要注意,比如cp_info表示常量池,上图中用 constant_pool[constant_pool_count-1]的方式来表示常量池有constant_pool_count-1个常量,它这里是采用数组的表现形式,但是大家不要误以为所有的常量池的常量长度都是一样的,其实这个地方只是为了方便描述采用了数组的方式,但是这里并不像编程语言那里,一个int型的数组,每个int长度都一样。

三、Class文件结构各部分具体介绍

1)u4 magic 表示魔数,并且魔数占用了4个字节,魔数到底是做什么的呢?它其实就是表示一下这个文件的类型是一个Class文件,而不是一张JPG图片,或者AVI的电影。而Class文件对应的魔数是0xCAFEBABE.
2)u2 minor_version 表示Class文件的次版本号,并且此版本号是u2类型的无符号数表示。
3)u2 major_version 表示Class文件的主版本号,并且主版本号是u2类型的无符号数表示。major_version和minor_version主要用来表示当前的虚拟机是否接受当前这种版本的Class文件。不同版本的Java编译器编译的Class文件对应的版本是不一样的。高版本的虚拟机支持低版本的编译器编译的Class文件结构。比如Java SE 6.0对应的虚拟机支持Java SE 5.0的编译器编译的Class文件结构,反之则不行。
4)u2 constant_pool_count 表示常量池的数量。这里我们需要重点来说一下常量池是什么东西,请大家不要与Jvm内存模型中的运行时常量池混淆了,Class文件中常量池主要存储了字面量以及符号引用,其中字面量主要包括字符串,final常量的值或者某个属性的初始值等等,而符号引用主要存储类和接口的全限定名称,字段的名称以及描述符,方法的名称以及描述符,这里名称可能大家都容易理解,至于描述符的概念,放到下面说字段表以及方法表的时候再说。另外大家都知道Jvm的内存模型中 有堆,栈,方法区,程序计数器构成,而方法区中又存在一块区域叫运行时常量池,运行时常量池中存放的东西其实也就是编译器产生的各种字面量以及符号引用, 只不过运行时常量池具有动态性,它可以在运行的时候向其中增加其它的常量进去,最具代表性的就是String的intern方法。
5)cp_info 表示常量池,这里面就存在了上面说的各种各样的字面量和符号引用。放到常量池的中数据项一共有14个常量,每一种常量都是一个表,并且每种常量都用一个公共的部分tag来表示是哪种类型的常量。

Constant TypeValue
CONSTANT_Class7
CONSTANT_Fieldref9
CONSTANT_Methodref10
CONSTANT_InterfaceMethodref11
CONSTANT_String8
CONSTANT_Integer3
CONSTANT_Float4
CONSTANT_Long5
CONSTANT_Double6
CONSTANT_NameAndType12
CONSTANT_Utf81
CONSTANT_MethodHandle15
CONSTANT_MethodType16
CONSTANT_InvokeDynamic18


6)u2 access_flags 表示类或者接口的访问信息,具体如下图所示:

Flag NameValueInterpretation
ACC_PUBLIC0x0001Declared public; may be accessed from outside its package.
ACC_FINAL0x0010Declared final; no subclasses allowed.
ACC_SUPER0x0020Treat superclass methods specially when invoked by the invokespecial instruction.
ACC_INTERFACE0x0200Is an interface, not a class.
ACC_ABSTRACT0x0400Declared abstract; must not be instantiated.
ACC_SYNTHETIC0x1000Declared synthetic; not present in the source code.
ACC_ANNOTATION0x2000Declared as an annotation type.
ACC_ENUM0x4000Declared as an enum type.

7)u2 this_class 表示类的常量池索引,指向常量池中CONSTANT_Class的常量
8)u2 super_class 表示超类的索引,指向常量池中CONSTANT_Class的常量
9)u2 interface_counts 表示接口的数量
10)u2 interface[interface_counts]表示接口表,它里面每一项都指向常量池中CONSTANT_Class常量
11)u2 fields_count 表示类的实例变量和类变量的数量
12) field_info fields[fields_count]表示字段表的信息,其中字段表的结构如下图所示:

field_info {
    u2             access_flags;
    u2             name_index;
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

上图中access_flags表示字段的访问表示,比如字段是public、private、protect 等,name_index表示字段名称,指向常量池中类型是CONSTANT_UTF8的常量,descriptor_index表示字段的描述符,它也指向常量池中类型为 CONSTANT_UTF8的常量,attributes_count表示字段表中的属性表的数量,而属性表是则是一种用与描述字段,方法以及 类的属性的可扩展的结构,不同版本的Java虚拟机所支持的属性表的数量是不同的。
13) u2 methods_count表示方法表的数量
14)method_info 表示方法表,方法表的具体结构如下图所示:

method_info {
    u2             access_flags;
    u2             name_index;,
    u2             descriptor_index;
    u2             attributes_count;
    attribute_info attributes[attributes_count];
}

其中access_flags表示方法的访问表示,name_index表示名称的索引,descriptor_index表示方法的描述符,attributes_count以及attribute_info类似字段表中的属性表,只不过字段表和方法表中属性表中的属性是不同的,比如方法表中就有Code属性,表示方法的代码,而字段表中就没有Code属性。
15) attribute_count表示属性表的数量,说到属性表,我们需要明确以下几点:
属性表存在于Class文件结构的最后,字段表,方法表以及Code属性中,也就是说属性表中也可以存在属性表,属性表的长度是不固定的,不同的属性,属性表的长度是不同的

详细出处参考:https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-4.html。

转载于:https://www.cnblogs.com/xiaotian15/p/6957498.html

相关文章:

  • tomcat7线程池配置
  • JS中typeof和instanceof用法区别
  • JS中闭包、函数与对象的介绍和用法
  • IE报vuex requires a Promise polyfill in this browser问题解决
  • 从零开始学习Vue(一)
  • 从零开始学习Vue(三)
  • jmeter使用BeanShell断言
  • 裁掉你的前端吧,切版网帮你解决
  • 简介Doxygen
  • 2048-控制台版本
  • 第一章 深入理解Magento - Magento强大的配置系统
  • Directx9.0 学习教程3 -图形学之创建点 线 三角形 等
  • [微信小程序] 使用ES6特性Class后出现编译异常
  • maven管理项目用junit测试遇到的找不到编译类问题
  • 2017中国手机趋势报告:天猫手机客单价2104元,品质时代来临
  • [rust! #004] [译] Rust 的内置 Traits, 使用场景, 方式, 和原因
  • Cookie 在前端中的实践
  • CSS居中完全指南——构建CSS居中决策树
  • github指令
  • Java 9 被无情抛弃,Java 8 直接升级到 Java 10!!
  • LeetCode18.四数之和 JavaScript
  • node-glob通配符
  • node和express搭建代理服务器(源码)
  • Object.assign方法不能实现深复制
  • oldjun 检测网站的经验
  • Python - 闭包Closure
  • Web标准制定过程
  • 闭包--闭包之tab栏切换(四)
  • 从零开始在ubuntu上搭建node开发环境
  • 分享自己折腾多时的一套 vue 组件 --we-vue
  • 利用阿里云 OSS 搭建私有 Docker 仓库
  • 如何使用 OAuth 2.0 将 LinkedIn 集成入 iOS 应用
  • 使用common-codec进行md5加密
  • 使用docker-compose进行多节点部署
  • 再次简单明了总结flex布局,一看就懂...
  • 自制字幕遮挡器
  • 正则表达式-基础知识Review
  • ###STL(标准模板库)
  • #免费 苹果M系芯片Macbook电脑MacOS使用Bash脚本写入(读写)NTFS硬盘教程
  • (4)事件处理——(6)给.ready()回调函数传递一个参数(Passing an argument to the .ready() callback)...
  • (附源码)计算机毕业设计SSM疫情下的学生出入管理系统
  • (解决办法)ASP.NET导出Excel,打开时提示“您尝试打开文件'XXX.xls'的格式与文件扩展名指定文件不一致
  • (力扣)循环队列的实现与详解(C语言)
  • (十八)devops持续集成开发——使用docker安装部署jenkins流水线服务
  • (十六)Flask之蓝图
  • (学习日记)2024.02.29:UCOSIII第二节
  • (一)Dubbo快速入门、介绍、使用
  • (转)c++ std::pair 与 std::make
  • (转)Mysql的优化设置
  • .MSSQLSERVER 导入导出 命令集--堪称经典,值得借鉴!
  • .NET Core 项目指定SDK版本
  • .Net IE10 _doPostBack 未定义
  • .NET委托:一个关于C#的睡前故事
  • [14]内置对象
  • [20150707]外部表与rowid.txt