(2) 深入理解Java Class文件格式(一)
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/21486985
Class文件在Java体系结构中的位置和作用
在上一篇博客中, 大致讲解了Java虚拟机的体系结构和执行原理。 本篇博客主要讲解能够被JVM识别, 加载并执行的class文件的格式。
对于理解JVM和深入理解Java语言, 学习并了解class文件的格式都是必须要掌握的功课。 原因很简单, JVM不会理解我们写的Java源文件, 我们必须把Java源文件编译成class文件, 才能被JVM识别, 对于JVM而言, class文件相当于一个接口, 理解了这个接口, 能帮助我们更好的理解JVM的行为;另一方面, class文件以另一种方式重新描述了我们在源文件中要表达的意思, 理解class文件如何重新描述我们编写的源文件, 对于深入理解Java语言和语法都是很有帮助的。 另外, 不管是什么语言, 只要能编译成class文件, 都能被JVM识别并执行, 所以class文件不仅是跨平台的基础, 也是JVM跨语言的基础, 理解了class文件格式, 对于我们学习基于JVM的其他语言会有很大帮助。
总之, 在整个Java技术体系结构中, 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 | attribute_count | 1 |
| attribute_info | attributes | attributes_count |
下面对class文件中的每一项进行详细的解释。
class文件中的魔数和版本号
(1) magic
在class文件开头的四个字节, 存放着class文件的魔数, 这个魔数是class文件的标志,他是一个固定的值: 0XCAFEBABE 。 也就是说他是判断一个文件是不是class格式的文件的标准, 如果开头四个字节不是0XCAFEBABE, 那么就说明它不是class文件, 不能被JVM识别。
(2)minor_version 和 major_version
紧接着魔数的四个字节是class文件的此版本号和主版本号。 随着Java的发展, class文件的格式也会做相应的变动。 版本号标志着class文件在什么时候, 加入或改变了哪些特性。 举例来说, 不同版本的javac编译器编译的class文件, 版本号可能不同, 而不同版本的JVM能识别的class文件的版本号也可能不同, 一般情况下, 高版本的JVM能识别低版本的javac编译器编译的class文件, 而低版本的JVM不能识别高版本的javac编译器编译的class文件。 如果使用低版本的JVM执行高版本的class文件, JVM会抛出java.lang.UnsupportedClassVersionError 。具体的版本号变迁这里不再讨论, 需要的读者自行查阅资料。
class文件中的常量池概述
在class文件中, 位于版本号后面的就是常量池相关的数据项。 常量池是class文件中的一项非常重要的数据。 常量池中存放了文字字符串, 常量值, 当前类的类名, 字段名, 方法名, 各个字段和方法的描述符, 对当前类的字段和方法的引用信息, 当前类中对其他类的引用信息等等。 常量池中几乎包含类中的所有信息的描述, class文件中的很多其他部分都是对常量池中的数据项的引用,比如后面要讲到的this_class, super_class, field_info, attribute_info等, 另外字节码指令中也存在对常量池的引用, 这个对常量池的引用当做字节码指令的一个操作数。 此外, 常量池中各个项也会相互引用。
class文件中的项constant_pool_count的值为1, 说明每个类都只有一个常量池。 常量池中的数据也是一项一项的, 没有间隙的依次排放。常量池中各个数据项通过索引来访问, 有点类似与数组, 只不过常量池中的第一项的索引为1, 而不为0, 如果class文件中的其他地方引用了索引为0的常量池项, 就说明它不引用任何常量池项。class文件中的每一种数据项都有自己的类型, 相同的道理,常量池中的每一种数据项也有自己的类型。 常量池中的数据项的类型如下表:
| 常量池中数据项类型 | 类型标志 | 类型描述 |
| CONSTANT_Utf8 | 1 | UTF-8编码的Unicode字符串 |
| CONSTANT_Integer | 3 | int类型字面值 |
| CONSTANT_Float | 4 | float类型字面值 |
| CONSTANT_Long | 5 | long类型字面值 |
| CONSTANT_Double | 6 | double类型字面值 |
| CONSTANT_Class | 7 | 对一个类或接口的符号引用 |
| CONSTANT_String | 8 | String类型字面值 |
| CONSTANT_Fieldref | 9 | 对一个字段的符号引用 |
| CONSTANT_Methodref | 10 | 对一个类中声明的方法的符号引用 |
| CONSTANT_InterfaceMethodref | 11 | 对一个接口中声明的方法的符号引用 |
| CONSTANT_NameAndType | 12 | 对一个字段或方法的部分符号引用 |
每个数据项叫做一个XXX_info项, 比如, 一个常量池中一个CONSTANT_Utf8类型的项, 就是一个CONSTANT_Utf8_info 。除此之外, 每个info项中都有一个标志值(tag), 这个标志值表明了这个常量池中的info项的类型是什么, 从上面的表格中可以看出, 一个CONSTANT_Utf8_info中的tag值为1, 而一个CONSTANT_Fieldref_info中的tag值为9 。
Java程序是动态链接的, 在动态链接的实现中, 常量池扮演者举足轻重的角色。 除了存放一些字面量之外, 常量池中还存放着以下几种符号引用:
(1) 类和接口的全限定名
(2) 字段的名称和描述符
(3) 方法的名称和描述符
在详细讲解常量池中的各个数据项之前, 我们有必要先了解一下class文件中的特殊字符串, 因为在常量池中, 特殊字符串大量的出现,这些特殊字符串就是上面说的全限定名和描述符。 要理解常量池中的各个数据项, 必须先了解这些特殊字符串。
(2) 深入理解Java Class文件格式(一)的更多相关文章
- (8) 深入理解Java Class文件格式(七)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22091529 本专栏列前面的一系列博客, 对Class文件中的一部分数据项进行了介绍. 本 ...
- (6) 深入理解Java Class文件格式(五)
前情回顾 本专栏的前几篇博文, 对class文件中的常量池进行了详细的解释. 前文讲解了常量池中的7种数据项, 它们分别是: CONSTANT_Utf8_info CONSTANT_NameAndTy ...
- (5) 深入理解Java Class文件格式(四)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21658415 前情回顾 在上一篇博客深入理解Java Class文件格式(三) 中, ...
- (4) 深入理解Java Class文件格式(三)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21557357 首先, 让我们回顾一下关于class文件格式的之前两篇博客的主要内容. 在 ...
- (3) 深入理解Java Class文件格式(二)
好文转载:http://blog.csdn.net/zhangjg_blog/article/details/21487287 在上一篇文章 深入理解Java Class文件格式(一) 中, 介绍了c ...
- (10) 深入了解Java Class文件格式(九)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22432599 经过前八篇关于class文件的博客, 关于class文件格式的内容也基本上讲 ...
- (9) 深入了解Java Class文件格式(八)
转载:http://blog.csdn.net/zhangjg_blog/article/details/22205831 在本专栏的第一篇文章 深入理解Java虚拟机到底是什么 中, 我们主要讲解了 ...
- (7) 深入了解Java Class文件格式(六)
转载:http://blog.csdn.net/zhangjg_blog/article/details/21888943 经过前几篇文章, 终于将常量池介绍完了, 之所以花这么大的功夫介绍常量池, ...
- java笔记--理解java类加载器以及ClassLoader类
类加载器概述: java类的加载是由虚拟机来完成的,虚拟机把描述类的Class文件加载到内存,并对数据进行校验,解析和初始化,最终形成能被java虚拟机直接使用的java类型,这就是虚拟机的类加载机制 ...
随机推荐
- 杭电ACM 1998奇数阶魔方
#include<stdio.h>#include <string.h>int main(){ int n,m; int a[40][40]={0}; scanf(" ...
- IOS第一天多线程-03线程间通信
**** #import "HMViewController.h" @interface HMViewController () @property (weak, nonatomi ...
- js中的回调函数的理解和使用方法
js中的回调函数的理解和使用方法 一. 回调函数的作用 js代码会至上而下一条线执行下去,但是有时候我们需要等到一个操作结束之后再进行下一个操作,这时候就需要用到回调函数. 二. 回调函数的解释 因为 ...
- Enum的使用
在项目开发中经常会使用到枚举,下面将举个例子,展示枚举的使用,不说废话,直接上代码. package com.tom.enumTest; public enum StatusType { A(&quo ...
- 直观友好的单个memcache监控工具:phpmemcache.php
上传phpmemcache.php到指定文件 修改文件中的: define('ADMIN_USERNAME','user'); // Admin Usernamedefine('ADMIN_P ...
- switch多分支语句
1.switch多分支语句的语法 switch(表达式){ case 常量值:要执行的语句; break; case 常量值:要执行的语句; break; case 常量值:要执行的语句; break ...
- JavaMail邮件开发
一.只带有纯文本的邮件 代码事例如下: package com.lyh.sendemail; import java.util.Properties; import javax.mail.Messag ...
- LNMP-Linux下Nginx+MySQL+PHP+phpMyAdmin+eAcelerator一键安装包
LNMP一键安装包是一个用Linux Shell编写的可以为CentOS/RadHat.Debian/Ubuntu VPS(VDS)或独立主机安装LNMP(Nginx.MySQL.PHP.phpMyA ...
- JMeter学习-020-JMeter 监听器之【聚合报告】错误率、吞吐量、传输速率实例计算
上文 对聚合报告的结果字段进行了概要的讲述释义,同时对吞吐量.传输速率.分位数等进行了详细的阐述,此文针对上文中描述的吞吐量及传输速率的计算进行详细的实例计算演示. 多不闲述,直入主题! 实际操作步骤 ...
- C# base64编码的文本与图片互转
/// <summary> /// base64编码的文本转为图片 /// </summary> /// <param name="txtFilePath&qu ...