上一篇博客讲【JVM虚拟机】(5)---深刻理解JVM-Class中常量池javascript
咱们知道一个class文件正常能够分为7个部分:html
访问标志
类索引、父类索引、接口索引
那么这篇博客主要讲有关 访问标志 和 类索引、父类索引、接口索引 相关的理解和代码示例。java
先通俗的说下这两个的做用:测试
访问标志
: 告知该类是一个什么类型的类,是普通类?仍是接口?仍是枚举?或者其它类,是用什么修饰符修饰该类的。spa
类索引、父类索引、接口索引
: 告知该类全限名的常量池地址,有继承的话父类全限名的常量池地址,实现接口的话接口全限名的常量池地址(接口能够多个)。code
先对上篇博客作个补充:上篇博客虽说了常量池但对class总体文件结构并无说清楚,其实一个class文件即htm
.class
文件本质上就是一张表
,由下表所示的数据项构成。blog
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135031721-1835822396.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="612">继承
上图也就是一开始所讲的7个部分组成。索引
<br>
有关访问标志
找了不少资料,也看了《深刻了解java虚拟机》书中第六章给的有关访问标志的信息,网上几乎讲访问标志都是下面这张图,而后写个pulic class 类 一测试,果真是0021 表明 ACC_PUBLIC+ACC_SUPER
这样一看是没毛病。可是都没有再写一个接口来验证的,若是本身写个接口就会发现下面我圈红的地方说,JDK1.2后该处必须为真 是不对的
。先看图。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135129522-1831389208.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="700" height="412">
思考
:就比如为何ACC_PUBLIC是00 01?如何产生的呢。
访问标志
实际上就是一系列组合,由于有16位因此共有16个标志可使用,可是目前就定义了8个,剩下的估计是给jdk9和10......预留的吧。这8个如图所示。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135139548-792467058.png" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="426">
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135148442-1272202826.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="420">
讲完理论,接下来咱们进行代码测试,为了校验更佳准确我写个普通类和接口分别测试:
public class XiaoXiao { }
在同一目录生成成class文件
javac XiaoXiao.java
在看反编译class文件
javap -v XiaoXiao.class
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135200951-1944917775.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="274">
咱们发现这里flags为: ACC_PUBLIC, ACC_SUPER
,那这么推算那么十六进制应该是0021。
那咱们再来查看XiaoXiao.class的十六进制数据
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135210605-118543476.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="370">
完美吻合。
public interface DaDa { }
一样先生成class文件在反编译class文件
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135219909-386750991.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="247">
看图咱们能够发现flags值为:ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT
,这个也很好理解接口自己就是抽象类。那么加起来就是0601
。但这里和上图有点不符的地方就是图中说ACC_SUPER只要是JDK1.2必须为真,而这里明显不为真,因此有关这点并不许确。
那咱们再将class文件转位16进制验证。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135232383-1170041644.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="218">
这么一来验证也是经过的。
有关ACC_SUPER不许确的问题,应该是ACC_SUPER不会
是在JDK1.2之后必须为真,应该以下描述:
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135241834-913919387.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="410">
<br>
在 .class 文件中由这三项数据来肯定这个类
的继承关系。
一、类索引
:u2 数据类型,用于肯定这个类
的全限定名。
二、父类索引
:u2 数据类型,用于肯定这个类的父类
的全限定名。
三、接口索引
:u2 数据类型的集合,用于描述类实现了哪些接口
,这些被实现的接口将按照 implements 语句后的顺序从左至右排列在接口索引集合中。
接口索引集合分为两部分,第一部分表示接口计数器
(interfaces_count),是一个 u2 类型的数据,第二部分是接口索引表
表示接口信息,紧跟在接口计数器以后。
若一个类实现的接口为 0,则接口计数器的值为 0,接口索引表不占用任何字节。
一样这里测试写两个测试类来测试。
public class XiaoXiao { }
一样生成class文件,而后查看16进制数据
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135252392-556980563.jpg" style="border: 1px dashed rgb(204, 200, 200);" width="600" height="425">
咱们看到该类的类索引在常量池0002位置 ,父类索引在常量池0003位置,接口为0000表明该类没有实现任何接口。
而后咱们在反编译XiaoXiao.class文件,方便咱们查找常量池。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135305029-1927119339.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="273">
真的是一目了然,常量池0002就是当前类,0003父类为默认继承了老祖宗Object。
完美!
为了更加深入理解,这里再写一个类实现两个接口的类,在来查看。
//接口 public interface DaDa { } //接口 public interface LaLa { } //类实现上面两个接口 public class XiaoXiao implements DaDa ,LaLa{ }
说明
:这里不能经过 javac XiaoXiao.java
生成XiaoXiao.class文件了,由于会报错。我分析缘由是由于你手动编译是没法找到DaDa ,LaLa编译信息。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135321017-796665369.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="385">
因此咱们能够把整个项目启动后,到target目录下去找该class文件就能够。
在打开16进制文件。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135331220-1772694961.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="260">
咱们看到该类的类索引在常量池0002位置 ,父类索引在常量池0003位。接口为0002表明该类实现了两个接口,一个接口在常量池位置004,一个在常量池位置0005。
在看反编译后的class文件。
<img src="https://img2018.cnblogs.com/blog/1090617/201904/1090617-20190409135343028-161944163.jpg" style="border: 2px dashed rgb(204, 200, 200);" width="600" height="286">
验证成功!
##<font color=#FFD700>参考 </font>
一、深刻了解java虚拟机第2版第六章
<br> <br> ``` 只要本身变优秀了,其余的事情才会跟着好起来(少将4) ```