今天聊聊Class文件,也就是字节码文件的一些知识,保准新手小白也能看懂,只要不走神……
首先大家要搞清楚,什么是Class文件,我们看一个代码,比如这里有一个Java源文件,内容是:
public class TestDemo {
public static void main(String[] args) {
System.out.println("hello");
}
}
这没什么问题吧?此时这个文件存放在我的桌面:
此时我们打开命令行工具,输入以下指令:
此时就会在我们的桌面生成一个新的文件:
这就是Class文件!同时我们一般把它叫做字节码文件,这才是真正实现跨平台的东西,到了这里你就需要明白,Class文件和字节码文件是一回事!
那什么是字节码文件:
所谓的字节码文件就是Java源代码经过编译器(javac)编译之后生成的新的文件,也就是一个后缀为.class的文件,此文件是一种二进制的类文件,它的内容是JVM指令,此文件就是字节码文件!
ok,以上就是对字节码文件的解读!
那到了这里,肯定就会有人比较好奇,这个字节码文件里面是什么内容啊,我们可以使用文本工具将其打开看一下:
一般,我们用常规的文本编辑工具直接打开,它是无法识别的,比如这里我们就要打开它:
然后你看的就是这些,啥也不是,完全看不懂,一堆乱码,怎么办?(虽然我们看不懂,但是JVM看得懂)
一般来说我们会将其以**十六进制的形式打开**,如下:
看到的就是这样的,其实你还是会觉得看不懂,没关系,我们后面就会着重去分析这些都是什么意思,也就是搞清楚这个字节码文件到底是个啥?
我们上面对Class文件也即字节码文件有了基本的认识,那么现在我们怎么去查看这个Class文件呢?上面我们说了,Class文件如果我们用一般的文本编辑器去打开的话,是乱码,什么也看不懂,通常情况下,我们以十六进制的形式展现:
也就是上述这个样子,也即是说,对于Class文件,我们直接打开显示的是这样子的:
看不懂啊,就好比你不会英语,给你一段英语,你看不懂啊,怎么办?翻译啊,可以将其翻译成中文你不就看懂了嘛,同样的,对于原始的Class文件,我们直接打开是看不懂的,怎么办?也是翻译啊,翻译成啥?通常翻译成十六进制的形式,也即是这样:
这样看就友好多了,当然,它是无法直接翻译成中文的,只能翻译到这了,那接下来我们就需要去解读这些十六机制代码都是什么含义,也就是去解读这个Class文件内容,这是我们的重点!
那这里先给大家介绍下,如何去查看这个Class文件,我用的工具叫做“010 Editor”(只要是十六进制文本编辑器都可),觉得还是很强大,很方便的,直接打开Class文件,这里可以进行转换:
而且在这里可以进行更多格式的切换:
比如我们将其以二进制形式展现:
可以看到,二进制直接展现看着也是比较懵的,还是十六进制的形式比较友好,所以这个工具推荐给大家,已给大家准备好安装包,除此之外大家还可以使用比较常见的编辑工具比如notpad++或者是sublime等,这些工具都可以以十六进制形式展示文件内容!
OK,我们看到的这些十六进制形式的内容可以说是Class文件的原版本,还有一些工具可以直接将Class文件进行解读以后将内容展现给我们,比如有这么一款工具(学习JVM必备:https://github.com/ingokegel/jclasslib)。叫做“JClasslib”,这就是一个专门的字节码查看器,我们用它打开Class文件:
这里展示的信息就是对Class文件进行解读之后的,更加方便我们去看,去分析,这款工具有Windows客户端,同时我们可以在IDEA中安装这款工具插件:
安装完这个插件之后,我们将代码进行编译之后,就可以点击View:
打开该工具就会在右边显示该Class文件内容解读:
ok,目前就给大家介绍这些方式,后面我们会用到这些去给大家分析Class文件的内容!
这里再给大家强调一下,可以这么说,原汁原味的Class文件也即是字节码文件是这样子的:
我们要分析的也是这个!OK!
接下来我们就来分析一下这个全是数字和字母的十六进制文件,这个就是Class文件了,也叫作字节码文件,我们看看这些东西该怎么解读!
首先清楚,这个字节码文件中大致包含如下几部分:
接着我们以常量池
为例来分析一个案例,让你理解这个字节码文件的分析是怎样的~
首先要知道,常量池也是存储数据的一个结构,它的结构如下:
{
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count - 1]
}
这个u2
就是Class文件中的一个数据类型,代表2字节大小
,所以常量池就包含了两部分:
1-4
,因为0索引被保留了而对于不同的字面量和符号引用,都还有各自的一个类型,比如同为字面量的整数6
和字符串6
,但是前者类型是int
后者类型是String
,所以不同的数据有不同的类型,别看常量池主要保存的就是字面量和符号引用,但是拆开仔细一看,这两者包含的数据一共有17种类型(截止jdk13),如下:
我们以CONSTANT_Integer_info
为例,它就代表我们常见的int类型
,每一个常量项同时也是有两部分组成,通用表示如下:
cp_info{
u1 tag; //表示类型
u1 info[]; //表示内容的字节数组
}
比如这个常量项“CONSTANT_Integer_info”,我们常见的int
类型就属于这个常量项,看它的组成就是:
CONSTANT_Integer_info{
u1 tag;
u4 bytes[];
}
这是怎么回事呢?比如我们这里写的Java代码(源java文件):
public class TestDemo {
public final int a = 6;
public static void main(String[] args) {
System.out.println("hello");
}
}
这里我们定义了一个final整型常量a,值为“6”,那这里的这个“6”就是一个字面量,是要放在常量池中的,对应的常量池结构就是CONSTANT_Integer_info,而CONSTANT_Integer_info包含两个部分,首先是占1字节的tag就是一个u1大小的类型,这个数值固定是3,然后就是占4个字节的具体存储字面量数值的字节数组info了!
我们目前查看Class文件是以16进制查看的,那么这里的字面量“6”是十进制,需要将其转换成十六进制放进常量池,十六进制为“0x06”:
那这个十进制的字面量“6”在常量池中的布局结构就如下所示:
这个时候我们再查看上述举例的源Java文件生成的Class文件,也就是十六机制的文件:
可以发现,这个字面量6正如咱们分析的一样出现在了字节码Class文件当中!这就将我们写的java代码中的变量与这个Class文件中的内容对应了起来!
当然,上述只是举了一个例子,实际上Class文件的内容很多,分析起来也比加多复杂,以上只是让大家简单了解一下!
如果想系统全面的学习,可以关注下咱们的Java就业手册
,持续更新中……
Copyright© 2013-2020
All Rights Reserved 京ICP备2023019179号-8