【JVM虚拟机】(5)---深刻理解JVM-Class中常量池

<center>深刻理解Class---常量池</center>

<font color=#FFD700> 1、概念</font>

一、jvm生命周期

启动:当启动一个java程序时,一个jvm实例就诞生了,任何一个拥有main方法的class均可以做为jvm实例运行的起点。java

运行:main()函数做为程序初始线程起点,其它线程由该线程启动,包括守护线程(daemon)和non-daemon(普通线程)。守护线程是JVM本身使用的线程好比GC线程就是个守护线程,只要这个jvm实例还有普通线程执行,就不会中止,可是能够用exit()强制终止程序。安全

消亡:全部非守护线程退出时,JVM实例结束生命,若安全管理器容许,程序也可使用java.lang.Runtime类或者System.exit(0)来退出。实际上exit也是用到Runtime类来退出,Runtime是个神奇的类,它还能够用于启动和关闭非java进程。网络

二、JVM与Class文件

咱们一直说java虚拟机实现的与语言是无关的,java虚拟机不和包含java在内的任何语言绑定,它只和与class文件这种特殊的二进制文件格式所关联,class文件中包含了java虚拟机指令集符号表以及若干其余辅助信息。基于安全方面的考虑, Java 虑拟机规范要求在 Class 文件中使用许多强制性的语法和结构化约束,但任一门功能性语言均可以表示为一个能被 Java 虚拟机所接受的有效的 Class 文件。做为一个通用的、机器无关的执行平台,任何其余语言的实现者均可以将 Java 虚拟机做为语言的产品交付媒介。例如,使用 Java 编译器能够把 Java 代码编译为存储字节码的 Class 文件,使用 JRuby 等其余语言的编译器一样能够把程序代码编译成 Class 文件,虚拟机并不关心Class 的来源是何种语言,如图。dom

三、什么是Class文件

Java字节码类文件(.class)是Java编译器编译Java源文件(.java)产生的“目标文件”。它是一种8位字节的二进制流文件, 各个数据项按顺序紧密的从前向后排列, 相邻的项之间没有间隙, 这样可使得class文件很是紧凑, 体积轻巧, 能够被JVM快速的加载至内存, 而且占据较少的内存空间(方便于网络的传输)。jvm

class文件是一组以8位字节为基础单位的二进制流。

class文件中的信息是一项一项排列的, 每项数据都有它的固定长度, 有的占一个字节, 有的占两个字节, 还有的占四个字节或8个字节, 数据项的不一样长度分别用u1, u2, u4, u8表示, 分别表示一种数据项在class文件中占据一个字节, 两个字节, 4个字节和8个字节。编辑器

四、什么是魔数

当咱们把class文件转成16进制,咱们能够看到文件的头四个字节是cafe babe,这个就称为魔数。,它惟一做用就告诉虚拟机当前的文件就是class文件。 使用魔数而不是用扩展名来进行识别主要是基于安全考虑,由于扩展名咱们能够随意经过重命名等方式改动。而经过魔数就算你把结尾改为.clss。但它一样还能在JVM运行,由于它的头部仍是cafe babe没变。 不少文件存储标准中都用魔数进行身份标识,如图片gif,jpeg都在文件头部中存储着魔数。函数

五、jvm常量池

我先讲下概念,接下来我会将class文件转为16进制流后,在举例说明。工具

常量池中每一项常量都是一个表,jdk1.8有14种结构不一样的表结构,这14个表有个共同特色,就是表开始的第一位都是一个u1类型的标志位,JVM根据这个标志位[tag]来肯定某个常量池项表示什么类型的字面量,好比tag为1就是指CONSTANT_utf8_info编码

再看常量池类型表spa

这14种常量项结构还有一个特色是,其中13表占用得字节固定,只有CONSTANT_Utf8_info占用字节不固定,其大小由length决定。为何呢?由于从常量池存放的内容可知,其存放的是字面量和符号引用,最终这些内容都会是一个字符串, 这些字符串的大小是在编写程序时才肯定,好比你定义一个类,类名能够取长取短,因此在没编译前,没法肯定大小不固定,编译后,经过utf-8编码,就能够知道其长度。

在看每一项常量表对应的说明:

<br>

<font color=#FFD700> 2、16进制class文件解析</font>

先看java代码

package com.jincou.demo.domain;
public class XiaoXiao {
    private String father;
    public String fatherName() {
        return "小小她爹";
    }
}

经过命令自动生成class文件(会在同一目录生成)

javac XiaoXiao.java

在将class文件拖入文本编辑器里,显示天然就是16进制流了,以下:

<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190402230800719-150205933.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="500">

上面的表其实能够划分为如下七个部分,.class 字节码文件包括:

  • 魔数与class文件版本
  • 常量池
  • 访问标志
  • 类索引、父类索引、接口索引
  • 字段表集合
  • 方法表集合
  • 属性表集合

这篇博客只讲到常量池,其它的下篇讲,接下来咱们一行一行解释,首先是:

cafe babe:上面说过了这个是魔数,告诉JVM虚拟机我就是class文件。

0000 0034:次版本号组成u2+主版本号u2。共占4个字节。0034转10进制为52,表明当前JDK版本为1.8。

0013 :说明有19-1即18个常量。

上面这些位置是固定的。接下来就是说明每个常量:

0a:这就是tag表明一个标志,0a表明10,去找常量池列表。

得知它是一个接口中方法的符号引用,而后去找CONSTANT_Methodref_info对应常量列表描述:

从常量列表咱们能够知道该类型一共占了5u,即0a00 0400 0f,那么下一个tag就是08表明字符串类型常量,以此类推就能够知道一共18个常量的信息。 <br>

<font color=#FFD700> 3、class反编译</font>

经过上面看16进制的却太麻烦了,如今咱们能够经过JDK自带反编译工具查看会更加清晰。

javap -verbose 文件名

经过反编译看去就很直观,好比第一个字符常量很明显告诉你是CONSTANT_Methodref_info,并且对于的就是4和15和上面完美对应。

最后思考,到底哪些会放到常量池?

1.常量池能够理解为class文件中的资源仓库,有不少种类型,主要存放两大常量
①.字面量 
字面量就是通俗理解的java常量,如文本字符串,8大基本数据类型,final修饰的常量值等
②.符号引用
符号引用属于编译原理的概念,主要包含如下三种
1)类和接口的全限定名
2)字段的名称和描述符
3)方法的名称和描述符

<br>

<font color=#FFD700> 参考</font>

一、深刻了解java虚拟机第2版第六章

二、深刻理解JVM-Class文件结构和类加载

三、深刻理解JVM之Java字节码(.class)文件详解

<br>

<br>

只要本身变优秀了,其余的事情才会跟着好起来(少将3)
相关文章
相关标签/搜索