文档章节

Class文件解读(一)

打破突破
 打破突破
发布于 2017/04/09 21:40
字数 1288
阅读 98
收藏 0

        java虚拟机规范中的java虚拟机的跨语言性及跨平台性,多半归功于定义中的Class文件,Class文件解耦了虚拟机平台的具体实现与具体的编程语言,也业务开发角度理解,可以将它抽象成接口对接文档(当然只是为了方便理解),既然是已经拟定的文档,那么必然存在一定的规则,在了解具体Class文件规范之前需要对Class文件有一个整体的认识。

        首先Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件之中,中间没有任何分隔符,这使得整个Class文件中存储的内容几乎全部是程序运行的必要数据,没有空隙存在。当需要需要占用8位字节以上空间的数据项时,则会按照高位在前的方式分割成若干个8位字节进行存储。

        根据java虚拟机规范的规定,Class文件格式采用类似于c语言中结构体的伪结构(仅仅是数据组合的一种既定方式)来存储数据,在该伪结构中只有两种数据类型:无符号数和表。

        无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节、和8个字节的无符号数,常用于表述数字(比如常量池的count、方法表count、属性表count等)、索引引用、数值量或按照UTF-8编码构成的字符串值。

        表在结构上是由无符号数和其他表构成的用语表述具有层次关系的复合结构,整个class文件也可以看成是一张特殊的表。

在介绍具体的Class文件结构之前,需要提醒的是class文件中对于字节码的顺序、长度都有严格的定义,具体的虚拟机实现必须遵循这样的规范(不然一次编译到处运行只能是梦想),当然Class文件规范中也允许虚拟机实现在遵循java标准虚拟机规范的前提下自由定义其他属性以提高虚拟机在某方面的性能。

Class文件结构:

            

       无论是无符号数还是表,当需要描述同一类型但数量不定的多个数据时,经常会使用一个前置的容量计数器加若干个连续的数据项的形式(这应该比较好理解,很多协议中都用了类似的思想,在数据报文头中先告诉接受端报文内容的整体信息,根据这些信息去解析报文数据,如netty中的编码器和解码器、http协议等),这时称这一系列连续的某一类型的数据为某一类型的集合。

详解Class文件结构:

为方便进一步理解,将使用下面的例子进行讲解:

package org.lucas.clazz;

/**
 * Created by BG260733 on 2017-04-09.
 */
public class TestClass {

    private int n;

    private static final int m = 5;

    public int inc() {
        return m + n;
    }

}

说明:以下class文件均由winHex十六进制打开。

magic:

       每个class文件的头4个字节称为魔数(Magic Number),它的唯一作用时确定这个文件是否为一个能被虚拟机接受的class文件(不代表能成功解析)。很多文件存储标准中都是在文件内容中嵌入魔术来进行身份识别,之所以不使用文件名(包括后缀)来作为文件的识别方式,主要是出于安全方面的考虑,文件名可能会被外部频繁改动。Class文件的魔术值为:OxCAFEBABY,是不是自带浪漫气息。

minor_version

        仅接着魔数后面的第5个和第6个两个字节,表示能够解析执行该class文件的虚拟机次版本号。

major_version

        第7个和第8个两个字节,表示能够解析执行该class文件的虚拟机主版本号。

            

下表列出了从JDK1.1到JDK1.7,主流JDK版本编译器输出的默认和可支持的Class文件版本号。

           

        -target标志表示允许编译器生成特定版本的Java类文件格式。

        -source标志表示允许编译器将新的语言构造(如Lambda表达式、try-with-resources以及switch中使用字符串等等)看做错误。一些新语言特性(比如Lambda表达式)需要使用特定的字节码功能(比如invokedynamic),因此,-source指定的版本比-target指定的版本还新往往是不可能的。

 

博主本打算将Class文件所有内容由一篇文章讲述清楚、但实际编写过程中发现待表述的信息量还是太大,为了方便读者阅读,特将此篇分为五到六篇文章,未完待续~

 

下篇:https://my.oschina.net/u/3345762/blog/880152

 

© 著作权归作者所有

共有 人打赏支持
打破突破

打破突破

粉丝 24
博文 26
码字总数 28638
作品 0
杭州
高级程序员
私信 提问
从动态代理,看Class文件结构定义

前言 这篇内容是上一篇动态代理是如何"坑掉了"我4500块钱的补充,进一步分析篇。 建议二者结合食用,醇香绵软,入口即化。 好了,不扯淡了,开始... 正文 2、Class 文件的格式 这里为啥是2开...

MDove
2018/08/13
0
0
SAS创建宏变量的七种方法

学会创建宏变量,特别是全局宏变量是应用宏的一个基础,下面我们介绍一下,创建宏变量的七种方法,并通过例子来演示。 1.通过宏函数创建宏变量。 %let dsid=%sysfunc(open(sashelp.class));...

开拓者-2017
2016/03/01
161
0
第三章 spring-bean之AbstractBeanFactory(5)

前言 AbstractBeanFactor实现了ConfigurableBeanFactory接口。一棵树有不仅有主干,树干,还有花花叶叶。其他接口与实现是BeanFactory的主干与树干的话,那ConfigurableBeanFactory负责管理B...

鸟菜啊
2018/08/04
0
0
android应用程序的混淆打包

1 . 在工程文件project.properties中加入下proguard.config=proguard.cfg , 如下所示: target=android-8 proguard.config=proguard.cfg Eclipse会通过此配置在工程目录生成proguard.cfg文件......

AlexZhuang
2012/04/11
0
0
Runtime之消息发送和消息转发

简介: 如果消息含有参数,则为: 1、消息发送机制 检查selector 是否需要忽略 检查target是否为nil,如果为nil,直接cleanup,然后return(这就是为什么可以向nil发送消息的原因) 然后在t...

Tonyliu_
2018/04/19
0
0

没有更多内容

加载失败,请刷新页面

加载更多

乱入Linux界的我是如何学习的

欢迎来到建哥学Linux,咳!咳!咳!开个玩笑哈,我是一个IT男,IT界的入门选手,正在学习Linux。 在之前,一直想进军IT界,学习IT技术,但是苦于没有人指导,也不知道学什么,最开始我自己在...

linuxprobe16
33分钟前
1
0
OSChina 周日乱弹 —— 没时间 没头发 但有钱

Osc乱弹歌单(2019)请戳(这里) 【今日歌曲】 @开源中国总经办主任 :分享齐一的单曲《这个年纪》 《这个年纪》- 齐一 手机党少年们想听歌,请使劲儿戳(这里) @肿肿卷 :我真的可以睡一天...

小小编辑
今天
45
4
Django进阶 1.1 ORM基础—ORM 1.2.1 增删改查之查询 1.2.2 删改增 (1) 1.2.3 删改增 (2)

ORM基础 ORM是Django操作数据库的API,Django的作者将sql语句封装在里面供我们使用。 我们前面还提到过Django提供一个模拟数据库的工具,sqlite,供我们学习测试使用。 如果我们想使用mysql...

隐匿的蚂蚁
今天
3
0
Windows 上安装 Scala

在安装 Scala 之前需要先安装 Java 环境,具体安装的详细方法就不在这里描述了。 您可以自行搜索我们网站中的内容获得其他网站的帮助来获得如何安装 Java 环境的方法。 接下来,我们可以从 ...

honeymose
今天
3
0
数据库篇多表操作

第1章 多表操作 实际开发中,一个项目通常需要很多张表才能完成。例如:一个商城项目就需要分类表(category)、商品表(products)、订单表(orders)等多张表。且这些表的数据之间存在一定的关系...

stars永恒
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部