看懂class文件 转
前言
现在周六公司进行一系列的java培训,刚上来就给我看class文件,比较头疼,不过感觉还是学到了一些东西,毕竟像老大说的,想要变得牛逼,是需要多学习多看的。好了,闲话不多说,我整理了一下思路,记录一下自己的学习过程,以后如果有时间的话,我会每个周日整理自己的笔记。我是菜鸡,大家不喜勿喷啊。
曾经风靡前世界的Wirte once,Run Anywhere,让Java这门语言在编程语言上大放异彩,至今仍然保持着第一受欢迎的地位。虽然Sun公司已经被收购,詹姆斯~高斯林前段时间找工作还被歧视年纪大,但我们还是对这门语言充满信心。好了,吹多了。Write once,Run AnyWhere基础实现就是虚拟机(JVM)和字节码储存格式。当然了,这里我主要还是记录一下字节码格式了,JVM以后有时间再学习吧。
这里的字节码格式,就是我们今天要说的Class文件了。当然了,这种说法如果考究起来还是不那么贴切的。因为任何一个Class文件都对应着唯一一个类和接口的定义信息,但是反过来说吧,类和接口并不一定非得在文件中(因为有些类或者接口可以通过classLoader自动生成)。
魔数 版本号
Class文件是一组以8位字节为基础单位的二进制流,各个数据项目严格按照顺序紧凑地排列在Class文件中,中间没有添加任何分隔符,就像下面的这样:
vc+28c+wtcSjrLWryse21MDtveLJz8PmxMfQqcr919a7ucrH09Cw79b6tcShozwvcD4NCjxwPs7et/u6xcr9yvTT2rv5sb61xMr9vt3A4NDNo6zV4sDvy/y2qNLlwct1MaGidTKhonU0oaJ1OMC0tPqx7TG49tfWvdqhojK49tfWvdqhojS49tfWvdq6zTi49tfWvdq1xM7et/u6xcr9oaPL/L/J0tTD6Mr2uty24LarzvejrLHIyOfK/dfWoaLL99L90v3Tw6Giyv3Bv9a1u/LV31VURi04seDC67m5s8m1xNfWt/u0rta1oaM8L3A+DQo8cD66w8HLo6zP1tTav6rKvLfWzvbO0sPHtcRjbGFzc87EvP7By6Os1abDx9K70NDSu9DQwLSjrMbk1tC63LbgwcujrLa8ysdKYXZh0OnE4rv6tcS55re2o6zL+dLUztLDx8HLveLSu8/Cvs3Q0MHLo6zPyL+0tdrSu9DQo7o8L3A+DQo8cD48aW1nIGFsdD0="这里写图片描述" src="/uploadfile/Collfiles/20170612/20170612092423657.png" title="\" />
第一行第一个红框,4个字节,如果看成英语,那么就是cafebabe了,也就是我们的咖啡了,你看java的logo是不是就是个咖啡样子啊?这四个字节在被称之为魔数(Magic Number),唯一的作用不是为了好玩,是为了判断是否成为虚拟机接受的class文件。当然像这种判断方式有很多了,我们经常用的图片的格式并不是以后缀名png,jpg来判断的,而是通过图片的头文件的数据来判断的,哎,这里吐槽一下,刚开始第一家公司写项目的时候,后台就是根据后缀名去剪切图像,经常出现图片不能保存的错误,搞得我么 一度很尴尬啊。
第二个红框,也就是第5个和第6个字节代表的是次版本号(是JDK的版本号,不是你写程序的版本号),看上去都是0啊。
第三个红框,也是00 34 第7和第8个字节,16进制的转成十进制的就是52了,这地方得说一下,它代表的是主板本号(Major Version)。Java的版本号是从45开始的,JDK1.1之后每一个大版本发布主版本号向上+1,高版本的JDK能向下兼容以前的老版本的class文件,但是不能运行以后的class文件,即使文件格式未发生任何变化,虚拟机也必须拒绝执行超过其版本号的class文件。
举个例子啊,我的目前运行的是jdk1.8,版本就是52了,虽然我可以执行jdk1.7生成的class文件,但是jdk1.7的环境运行不了我1.8生成的class文件。下图是我在书上找的,可能比较老,还没有到1.8的内容,打个tag吧,JDK 1.8.0_40的major version是52。

现在还介绍最后一个框00 21的意思了。这个是常量池的入口了。常量池可以理解为Class文件之中的资源仓库,它是Class文件结构中与其它项目关联最多的数据类型,也是占用Class文件空间最大的数据项目之一。
常量池
每一个Class文件的常量池都不是固定的,所以有一个u2类型(也就是2个字节的)数据,来记录常量池的个数,但是这个个数与Java语言习惯不一样,它是从1开始计数的,也就是说00 21本来是有33个常量池,但是事实只有32个。关于这个问题的设计,可以追究到Class文件格式规范制定之时,设计者将第0项常量空出来是有特殊考虑的,这样做的目的是在于满足后面的某些指向常量池的索引值的数据在特定情况下表达“不引用任何一个常量池项目”的含义,这样情况及可以把索引值置为0 来表示。
当然了,常量池并不是我们想的那样,值放我们的public static final int _COUNT = 1这种常量值了,它主要存放两大类常量:字面量(Literal)和符号引用(Symbolic References).这里的字面量就像我们Java语言层面的常量概念,就是文本常量,final型的常量值等等。而符号引用是属于编译原理方面的概念,包含了下面的常量:
1.类和接口的全限定名(Fully Qualified Name)
2.字段的名称和描述符(Descriptor)
3.方法的名称和描述符
当然了,这些都是什么意思,可能需要等我学习深入之后才能懂的吧。
到这里了,是不是应该来看这些常量池都是些什么东西吧。不急,想了解这个常量池的内容,还需要知道这张表的含义,Class文件就是通过查询这两张表,还获取常量池的内容。首先需要知道常量池中14项常量项的结构表:


大家看到这边表可能不知道什么意思,那好,我们就用程序来说明一下,写个hello world程序:
| 
 1 
2 
3 
4 
5 
6 
7 
8 
9 
10 
 | 
public class T {    //字符常量    public static final int COUNT_NUMBER = 1 ;    //main函数    public static void main(String[] args) {        System.out.println("hello world");    }} | 
编译的T文件用UltraEdit打开,如下图:

紧靠在00 21后面的 就是我们的第一个常量池了,请看第一个红框,为什么是一个字节呢,因为常量池中最多14中不同的数据结构,一个字节(255)足够了,节约资源嘛。那么第一个红框中是0A,换成十进制就是10了,好了这次要查表了,什么表,就是上图那个表了啊,

对,我们看到了是MethodRef_info,它的这种数据结构有三个属性组成:tag,index,index。tag值为10,标记是MethodRef属性的,还有两个index,index分别表示方法描述符的索引项和类型描述符的索引项,这里就不深究了,因为今天的内容只是为了读懂这个class文件,但是需要注意的是两个index都是u2类型的,那么就表明它们的值分别为00 06 和00 13,换成十进制就是6和19。
这个分析完了,这也就是我们第一个常量池中常量方法的分析了。 来看第二个:

对,是09,我们查表:

跟常量method属性一致,连个值分别为20,21,这里就不分析了,下一个:

对,一下子到这里来,因为上面的都差不多,先查tag值,然后查询数据结构,看自己的Index所占的字节,然后获取数据,然后下一个。 这个是01,那就是字符串了:

这次是length,看到结果是个00 0C,那么就是12了,那么就意味着后面的12个字节就是这个字符串的内容了,好了,看一下吧:
| 
 1 
2 
3 
 | 
43 4F 55 4E 54 5F 4E 55 4D 42 45 52转义为COUNT_NUMBER | 
那么也就是我们自定义的常量字符了。 好了,到了这里我就不分析了,因为下去都一样了,其实Javap给我们提供了这种功能:
| 
 1 
 | 
javap -verbose ClassName | 
看图:

从这个图里,我们可以得到我们关于class的基本信息了,有次版本主版本,还有今天得常量池,看我们分析的也基本上和它一样了。
好了,今天就记录在这里吧,刚刚开始,感觉有些难,不知不觉写了这么多,其实理解起来不算很难吧。
也参考过老大的PPT,还有一些书籍,算了不写上去了,累啊。。。
看懂class文件 转的更多相关文章
- 一个故事看懂Linux文件权限管理
		
前情回顾: 我通过open这个系统调用虫洞来到了内核空间,又在老爷爷的指点下来到了sys_open的地盘,即将开始打开文件的工作. 详情参见:内核地址空间大冒险:系统调用 open系统调用链 我是一个 ...
 - 看懂Class文件的装载流程
		
Class文件的加载过程 ClassLoader的工作模式 类的热加载 1 Class文件的装载流程 只有被java虚拟机装载的Class类型才能在程序中使用(注意装载和加载的区别) 1.1 类装载的 ...
 - 一图看懂hadoop分布式文件存储系统HDFS工作原理
		
一图看懂hadoop分布式文件存储系统HDFS工作原理
 - 看懂Oracle执行计划
		
最近一直在跟Oracle打交道,从最初的一脸懵逼到现在的略有所知,也来总结一下自己最近所学,不定时更新ing- 一:什么是Oracle执行计划? 执行计划是一条查询语句在Oracle中的执行过程或访问 ...
 - 看懂SqlServer查询计划【转】
		
原文链接:http://www.cnblogs.com/fish-li/archive/2011/06/06/2073626.html 开始 SQL Server 查找记录的方法 SQL Server ...
 - 文科生也能看懂的iptables教程(转载)
		
据说还是个MM, 写得很通俗易懂, 还很诙谐, 原文:http://dallascao.com/cn/iptables-tutorial-for-newbies/ 对于斗胆开始玩vps的文科生来讲,i ...
 - PHP笔记——java程序员看懂PHP程序
		
PHP笔记——java程序员看懂PHP程序 php是一种服务器端脚本语言,类型松散的语言. <?php ?> xml风格 <script language=”ph ...
 - 【转载】看懂SqlServer查询计划
		
看懂SqlServer查询计划 阅读目录 开始 SQL Server 查找记录的方法 SQL Server Join 方式 更具体执行过程 索引统计信息:查询计划的选择依据 优化视图查询 推荐阅读-M ...
 - 看懂SqlServer查询计划
		
看懂SqlServer查询计划 阅读目录 开始 SQL Server 查找记录的方法 SQL Server Join 方式 更具体执行过程 索引统计信息:查询计划的选择依据 优化视图查询 推荐阅读-M ...
 
随机推荐
- Python ————反射机制
			
python中的反射功能是由以下四个内置函数提供:hasattr.getattr.setattr.delattr,改四个函数分别用于对对象内部执行:检查是否含有某成员.获取成员.设置成员.删除成员. ...
 - C# WPF DevExpress 图表控件之柱状图
			
说明:DevExpress版本是17.1.VS是2015. XAML: <!--#region 图表控件--> <dxc:ChartControl x:Name="char ...
 - java 获得系统当前时间
			
import org.junit.Test; import java.text.SimpleDateFormat; import java.util.Calendar; import java.uti ...
 - web:频繁刷新浏览器的页面【小工具】
			
[目的] 频繁刷新某一浏览器页面,小测试一下加载性能,或者打开的文件是否及时关闭,会不会导致服务器奔溃 [小工具] 新建txt,输入以下内容,并保存为html的格式,然后在浏览器中打开,则会定时刷新指 ...
 - 12纯 CSS 创作一种文字断开的交互特效
			
原文地址:https://segmentfault.com/a/1190000014719591 总结:三部分组成,原文透明,左右都与原文重叠(绝对定位),但左右各取相应一部分. HTML代码: &l ...
 - 《算法》第一章部分程序 part 2
			
▶ 书中第一章部分程序,加上自己补充的代码,包括简单的计时器,链表背包迭代器,表达式计算相关 ● 简单的计时器,分别记录墙上时间和 CPU 时间. package package01; import ...
 - 使用windows性能计数器监控cpu使用率
			
https://blog.csdn.net/yabingshi_tech/article/details/26672355 2. http://blog.51cto.com/qixue/1702557 ...
 - 9. 一个list拆分成多个list返回
			
/** * @Title: splitList * @Description: 1个list分割成多个list * @param targe 原list * @para ...
 - 3. easyui 修改功能实例
			
function modifyPerson() { var rows = $('#personInfoGrid').datagrid('getSelections'); if (rows.length ...
 - python3下安装Selenium插件和驱动
			
import sysimport osimport shutilimport time os.system('pip install selenium') file_name="IEDriv ...