zoukankan      html  css  js  c++  java
  • 【JVM虚拟机】(6)---深入理解Class中访问标志、类索引、父类索引、接口索引

    JVM(6)访问标志,类索引

    上一篇博客讲【JVM虚拟机】(5)---深入理解JVM-Class中常量池

    我们知道一个class文件正常可以分为7个部分:

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

    那么这篇博客主要讲有关 访问标志类索引、父类索引、接口索引 相关的理解和代码示例。

    先通俗的说下这两个的作用:

    访问标志: 告知该类是一个什么类型的类,是普通类?还是接口?还是枚举?或者其它类,是用什么修饰符修饰该类的。

    类索引、父类索引、接口索引: 告知该类全限名的常量池地址,有继承的话父类全限名的常量池地址,实现接口的话接口全限名的常量池地址(接口可以多个)。

    一、概述

    先对上篇博客做个补充:上篇博客虽然说了常量池但对class整体文件结构并没有说清楚,其实一个class文件即

    .class 文件本质上就是一张,由下表所示的数据项构成。

    上图也就是一开始所讲的7个部分组成。


    二、访问标志

    有关访问标志找了很多资料,也看了《深入了解java虚拟机》书中第六章给的有关访问标志的信息,网上几乎讲访问标志都是下面这张图,然后写个pulic class 类 一测试,果然是0021 代表 ACC_PUBLIC+ACC_SUPER 这样一看是没毛病。但是都没有再写一个接口来验证的,如果自己写个接口就会发现下面我圈红的地方说,JDK1.2后该处必须为真 是不对的。先看图。

    1、访问标志转为16进制解释

    思考:就好比为什么ACC_PUBLIC是00 01?如何产生的呢。

    访问标志实际上就是一系列组合,因为有16位所以共有16个标志可以使用,但是目前就定义了8个,剩下的估计是给jdk9和10......预留的吧。这8个如图所示。

    讲完理论,接下来我们进行代码测试,为了校验更佳准确我写个普通类和接口分别测试:

    2、public class修饰类

    public class XiaoXiao {
      
    }
    

    在同一目录生成成class文件

    javac XiaoXiao.java
    

    在看反编译class文件

    javap -v XiaoXiao.class
    

    我们发现这里flags为: ACC_PUBLIC, ACC_SUPER,那这么推算那么十六进制应该是0021。

    那我们再来查看XiaoXiao.class的十六进制数据

    完美吻合。

    3、接口校验

    public interface DaDa {
    
    }
    

    同样先生成class文件在反编译class文件

    看图我们可以发现flags值为:ACC_PUBLIC, ACC_INTERFACE, ACC_ABSTRACT ,这个也很好理解接口本身就是抽象类。那么加起来就是0601。但这里和上图有点不符的地方就是图中说ACC_SUPER只要是JDK1.2必须为真,而这里明显不为真,所以有关这点并不准确。

    那我们再将class文件转位16进制验证。

    这么一来验证也是通过的。

    有关ACC_SUPER不准确的问题,应该是ACC_SUPER不会是在JDK1.2以后必须为真,应该如下描述:


    三、类索引、父类索引、接口索引

    1、概念

    在 .class 文件中由这三项数据来确定这个的继承关系。

    1、类索引:u2 数据类型,用于确定这个类的全限定名。

    2、父类索引:u2 数据类型,用于确定这个类的父类的全限定名。

    3、接口索引:u2 数据类型的集合,用于描述类实现了哪些接口,这些被实现的接口将按照 implements 语句后的顺序从左至右排列在接口索引集合中。

    接口索引集合分为两部分,第一部分表示接口计数器(interfaces_count),是一个 u2 类型的数据,第二部分是接口索引表表示接口信息,紧跟在接口计数器之后。

    若一个类实现的接口为 0,则接口计数器的值为 0,接口索引表不占用任何字节。

    同样这里测试写两个测试类来测试。

    1、普通类测试

    public class XiaoXiao {
      
    }
    

    同样生成class文件,然后查看16进制数据

    我们看到该类的类索引在常量池0002位置 ,父类索引在常量池0003位置,接口为0000代表该类没有实现任何接口。

    然后我们在反编译XiaoXiao.class文件,方便我们查找常量池。

    真的是一目了然,常量池0002就是当前类,0003父类为默认继承了老祖宗Object。

    完美!

    2、实现接口测试

    为了更加深刻理解,这里再写一个类实现两个接口的类,在来查看。

    //接口
    public interface DaDa { 
    }
    //接口
    public interface LaLa {
    }
    //类实现上面两个接口
    public class XiaoXiao implements  DaDa ,LaLa{
    }
    

    说明:这里不能通过 javac XiaoXiao.java生成XiaoXiao.class文件了,因为会报错。我分析原因是因为你手动编译是无法找到DaDa ,LaLa编译信息。

    所以我们可以把整个项目启动后,到target目录下去找该class文件就可以。

    在打开16进制文件。

    我们看到该类的类索引在常量池0002位置 ,父类索引在常量池0003位。接口为0002代表该类实现了两个接口,一个接口在常量池位置004,一个在常量池位置0005。

    在看反编译后的class文件。

    验证成功!

    参考

    1、深入了解java虚拟机第2版第六章

    2、深入理解JVM-Class文件结构和类加载



    只要自己变优秀了,其他的事情才会跟着好起来(少将4)
    
  • 相关阅读:
    测试策略(1)
    css在网页中的一些重要运用
    拖拽禁止点击事件
    js入门的心结
    响应式布局
    web中的兼容性
    css中的bfc和ifc
    css格式化的基本运用
    css基础知识
    html中输入控件的元素
  • 原文地址:https://www.cnblogs.com/qdhxhz/p/10676337.html
Copyright © 2011-2022 走看看