水稻:看你研究盯着这个文档一天了,什么玩意让人心驰神往

菜瓜:前几天意外得到一本武功秘籍《jvms8》,看起来就情不自禁

水稻:这不是Java虚拟机的说明文档吗<PS:投来惊吓的目光>

菜瓜:是的,在研究第四章-The class File Format. 讲的是class文件结构。以前模糊的知道我们写的java代码是以二进制字节码加载到虚拟机然后执行的,但是没有见识过

水稻:有什么收获,分享一下啊

菜瓜:只是在研究,可以一起探讨。我是这么干的,先准备工具

  • jvms8官方文档下载 - (因为我是用jdk8编译的,所以下载的是8版本的。可以选择自己的版本 https://docs.oracle.com/javase/specs/index.html)
  • idea插件jclasslib Bytecode viewer - (代替javap命令直接在idea中查看字节码编译内容)
  • sublime - 查看16进制字节码,方便阅读 (也可以下载idea插件BinEd)

菜瓜:写一段最简单的demo

  • java源文件

    • package club.interview.jvm;
      
      /**
      * @author QuCheng on 2020/7/10.
      */
      public class ClassOriginal {
      }
  • 二进制 - 编译成class文件
    • 11001010 11111110 10111010 10111110 00000000 00000000 00000000 00110100 00000000 00010000 00001010 00000000 00000011 00000000 00001101 00000111 00000000 00001110 00000111 00000000 00001111 00000001 00000000 00000110 00111100 01101001 01101110 01101001 01110100 00111110 00000001 00000000 00000011 00101000 00101001 01010110 00000001 00000000 00000100 01000011 01101111 01100100 01100101 00000001 00000000 00001111 01001100 01101001 01101110 01100101 01001110 01110101 01101101 01100010 01100101 01110010 01010100 01100001 01100010 01101100 01100101 00000001 00000000 00010010 01001100 01101111 01100011 01100001 01101100 01010110 01100001 01110010 01101001 01100001 01100010 01101100 01100101 01010100 01100001 01100010 01101100 01100101 00000001 00000000 00000100 01110100 01101000 01101001 01110011 00000001 00000000 00100010 01001100 01100011 01101100 01110101 01100010 00101111 01101001 01101110 01110100 01100101 01110010 01110110 01101001 01100101 01110111 00101111 01101010 01110110 01101101 00101111 01000011 01101100 01100001 01110011 01110011 01001111 01110010 01101001 01100111 01101001 01101110 01100001 01101100 00111011 00000001 00000000 00001010 01010011 01101111 01110101 01110010 01100011 01100101 01000110 01101001 01101100 01100101 00000001 00000000 00010010 01000011 01101100 01100001 01110011 01110011 01001111 01110010 01101001 01100111 01101001 01101110 01100001 01101100 00101110 01101010 01100001 01110110 01100001 00001100 00000000 00000100 00000000 00000101 00000001 00000000 00100000 01100011 01101100 01110101 01100010 00101111 01101001 01101110 01110100 01100101 01110010 01110110 01101001 01100101 01110111 00101111 01101010 01110110 01101101 00101111 01000011 01101100 01100001 01110011 01110011 01001111 01110010 01101001 01100111 01101001 01101110 01100001 01101100 00000001 00000000 00010000 01101010 01100001 01110110 01100001 00101111 01101100 01100001 01101110 01100111 00101111 01001111 01100010 01101010 01100101 01100011 01110100 00000000 00100001 00000000 00000010 00000000 00000011 00000000 00000000 00000000 00000000 00000000 00000001 00000000 00000001 00000000 00000100 00000000 00000101 00000000 00000001 00000000 00000110 00000000 00000000 00000000 00101111 00000000 00000001 00000000 00000001 00000000 00000000 00000000 00000101 00101010 10110111 00000000 00000001 10110001 00000000 00000000 00000000 00000010 00000000 00000111 00000000 00000000 00000000 00000110 00000000 00000001 00000000 00000000 00000000 00000110 00000000 00001000 00000000 00000000 00000000 00001100 00000000 00000001 00000000 00000000 00000000 00000101 00000000 00001001 00000000 00001010 00000000 00000000 00000000 00000001 00000000 00001011 00000000 00000000 00000000 00000010 00000000 00001100
  • 16进制 
    • cafe babe 0000 0034 0010 0a00 0300 0d07
      000e 0700 0f01 0006 3c69 6e69 743e 0100
      0328 2956 0100 0443 6f64 6501 000f 4c69
      6e65 4e75 6d62 6572 5461 626c 6501 0012
      4c6f 6361 6c56 6172 6961 626c 6554 6162
      6c65 0100 0474 6869 7301 0022 4c63 6c75
      622f 696e 7465 7276 6965 772f 6a76 6d2f
      436c 6173 734f 7269 6769 6e61 6c3b 0100
      0a53 6f75 7263 6546 696c 6501 0012 436c
      6173 734f 7269 6769 6e61 6c2e 6a61 7661
      0c00 0400 0501 0020 636c 7562 2f69 6e74
      6572 7669 6577 2f6a 766d 2f43 6c61 7373
      4f72 6967 696e 616c 0100 106a 6176 612f
      6c61 6e67 2f4f 626a 6563 7400 2100 0200
      0300 0000 0000 0100 0100 0400 0500 0100
      0600 0000 2f00 0100 0100 0000 052a b700
      01b1 0000 0002 0007 0000 0006 0001 0000
      0006 0008 0000 000c 0001 0000 0005 0009
      000a 0000 0001 000b 0000 0002 000c
  • 引用jvms8中的说明 - 虚拟机按照这个结构体对二进制文件进行解析
    • A class file consists of a single ClassFile structure: //单个class文件结构组成
      ClassFile {
      u4 magic; // 前4字节magic
      u2 minor_version; // jdk小版本
      u2 major_version; // 主要版本
      u2 constant_pool_count; // 常量池大小
      cp_info constant_pool[constant_pool_count-1]; // 常量池信息
      u2 access_flags; // 类访问修饰符
      u2 this_class; // 当前class指向常量池
      u2 super_class; // 父类class指向常量池
      u2 interfaces_count; // 接口总数
      u2 interfaces[interfaces_count]; // 接口索引 - 若无接口,则无需统计
      u2 fields_count; // 字段统计
      field_info fields[fields_count]; // 字段信息 - 若无成员字段,则无需统计
      u2 methods_count; // 方法统计
      method_info methods[methods_count]; // 方法信息 - 默认会有无参构造
      u2 attributes_count; // 属性
      attribute_info attributes[attributes_count]; // 表示文件信息,譬如路径和文件名
      }
    • u4、u2 -- u表示无符号位,4和2表示字节数

水稻:cafe babe 眼熟 ,0034转换为10进制是52,代表1.8版本。后面的倒是没见过

菜瓜:那我们看一拿着前面一段来对照看看

  • cafe babe 0000 0034 0010 0a00 0300 0d07
    
    按照结构体来划分
    u4 4个字节 <cafe babe> 头文件校验
    u2 2个字节 <> minor_version小版本=0
    u2 2个字节 <> major_version大版本 52(16进制) = 1.8
    u2 2个字节 <> 常量池大小 16(16进制)

水稻:懂,后面的 0a00 0300 0d07 是什么呢? 按照结构体的排序是cp_info 常量池数组根据下标编排的内容对吧

菜瓜:没错,这里的cp_info 结构体有一个参照表如下

  • Constant_Type Value
    CONSTANT_Class 7
    CONSTANT_Fieldref 9
    CONSTANT_Methodref 10
    CONSTANT_InterfaceMethodref 11
    CONSTANT_String 8
    CONSTANT_Integer 3
    CONSTANT_Float 4
    CONSTANT_Long 5
    CONSTANT_Double 6
    CONSTANT_NameAndType 12
    CONSTANT_Utf8 1
    CONSTANT_MethodHandle 15
    CONSTANT_MethodType 16
    CONSTANT_InvokeDynamic 18 info 也是一个对象,不同对象属性还不一样
    // tag=10 方法引用
    CONSTANT_Methodref_info {
    u1 tag;
    u2 class_index; // class下标
    u2 name_and_type_index; //
    }
    // tag = 7
    CONSTANT_Class_info {
    u1 tag;
    u2 name_index; // class索引
    } // tag = 1
    CONSTANT_Utf8_info {
    u1 tag;
    u2 length;
    u1 bytes[length];
    } CONSTANT_NameAndType_info {
    u1 tag;
    u2 name_index;
    u2 descriptor_index;
    }
  • 再来看上面没解析的  0a00 0300 0d07以及后续
    • 0a00 0300 0d07
      
      u1 1字节 0a 表示10 对应10号结构体
      CONSTANT_Methodref_info {
      u1 tag;
      u2 class_index; // class下标
      u2 name_and_type_index; // 结构体下标
      } u1 0a tag 结构体cp_info标识
      u2 00 03 class_index 类文件下标,此处指向常量池03位
      u2 00 0d name_type_index 指向常量池13位
  • 再列举几个,你应该就能看明白了
    • 衔接第一排0d07
      000e 0700 0f01 0006 3c69 6e69 743e 0100
      0d已经被使用,从07开始
      对照cp_info 07号结构体
      // tag = 7
      CONSTANT_Class_info {
      u1 tag;
      u2 name_index; // class索引
      }
      <07 000e>
      u1 07
      u2 000e 指向常量池第14位
      <0700 0f>
      u1 07
      u2 000f 常量池第15位 下一位01 对应结构体
      // tag = 1
      CONSTANT_Utf8_info {
      u1 tag;
      u2 length;
      u1 bytes[length];
      }
      <01 0006 3c69 6e69 743e>
      u1 tag
      u2 0006 后续字节长度
      u1 长度为6的字节数组 (3c69 6e69 743e) 对照ASCII表翻译成字符("<init>")

水稻:妙啊!你怎么证明是这样的

菜瓜:不慌,用到第二个idea插件工具jclasslib ... 怎么使用我就不演示了。(也可以使用javap命令)编译结果如下

  • 类整体结构信息

  • 常量池信息

  • 后面的我就不贴了

水稻:原来是这样解析的!!

菜瓜:当然这个其实没什么技术含量,只是一个比较死板的解析过程而已,不过这个设计真让人拍案叫绝,只要最后java文件能被编译成这种class文件格式,jvm就都能解析。后面有个区域需要熟悉一下:methods

水稻:哦?有什么讲究

菜瓜:我们方法的执行逻辑都在这里,有个i++和++i的常见面试题可以从这里一探究竟。因为我写的这个demo比较简单,此处的mthods区域只有一个方法就是默认的构造方法

  • 要想看懂这个,还得拿jvms8的指令集对照表查看- 第6章6.5
    • aload_0 将this从局部变量表加载到操作数栈栈顶  (aload_0指令 - 16进制码是2a)
    • invokespecial 调用方法 - 这里是调用的object的构造方法 (invokespecial指令 - 16进制码是b7)
    • return - 返回结构 (return - 16进制是 b1)
  • 后面标注了指令对应的16进制码,可以呼应上面我们的16进制对照表
    • 2a b7 b1  

水稻:有收获,虽然对写代码没啥太大用,但是这个流程搞清楚了就比较通透

菜瓜:后面我还想继续深入一下,有收获再分享啊

水稻:可以可以

总结:

【JVM】或许,这就是二进制Class吧的更多相关文章

  1. Java中new一个对象是一个怎样的过程?JVM中发生了什么?

    Java中new一个对象的步骤: 1. 当虚拟机遇到一条new指令时候,首先去检查这个指令的参数是否能 在常量池中能否定位到一个类的符号引用 (即类的带路径全名),并且检查这个符号引用代表的类是否已被 ...

  2. JVM类加载

    JVM的类加载机制就是:JVM把描述类的class文件加载到内存,并对数据进行校验.转换解析和初始化,最终形成可以被JVM直接使用的Java类型 ClassLoader JVM中的ClassLoade ...

  3. Java虚拟机详解01----初识JVM

    主要内容如下: JVM的概念 JVM发展历史 JVM种类 Java语言规范 JVM规范 一.JVM的概念: JVM: Java Virtual Machine,意为Java虚拟机. 虚拟机: 指通过软 ...

  4. 关于JVM的类型和模式

    原文出处: 摆渡者 引言 曾几何时,我也敲打过无数次这样的命令: 然而之前的我都只关心过版本号,也就是第一行的内容.今天,我们就来看看第3行输出的内容:JVM的类型和工作模式. 其实说Server和C ...

  5. 1.初步认识JVM -- JVM序列

    1.JVM概念 JVM是java Virtual Machine的简称.也称为Java虚拟机. 虚拟机:通过软件模拟具有完整硬件功能的运行在一个完全隔离环境的完整计算机系统.VMWare.Visual ...

  6. JVM知识(上)

    目录 什么是JVM? JVM的生命周期 JVM的体系结构 JVM的数据类型 java虚拟机被称为"虚拟",因为它是一个抽象的计算机定义的规范.要运行一个Java程序,需要一个抽象的 ...

  7. 深入JVM内核---原理,诊断与优化

    JVM的概念 JAM是Java Virtual Machine的简称.意为Java虚拟机 虚拟机 指通过软件模拟的具有完整硬件系统功能的,运行在一种完整隔离环境中的完整计算机系统 有哪些虚拟机 - V ...

  8. JVM | JVM的核心技术

    说到JVM,很多工作多年的老铁,可能就有点发憷了,因为搬砖多年,一直使用java这个工具,对于JVM没有了解过,有句话面试造航母,上班拧螺丝,要啥自行车啊,知道如何搬砖就可以了,为啥要懂这么多,如果你 ...

  9. JVM内核-原理、诊断与优化学习笔记(一):初识JVM

    文章目录 JVM的概念 JVM是Java Virtual Machine的简称.意为Java虚拟机 虚拟机 有哪些虚拟机 VMWare或者Visual Box都是使用软件模拟物理CPU的指令集 JVM ...

随机推荐

  1. LinkedList竟然比ArrayList慢了1000多倍?(动图+性能评测)

    数组和链表是程序中常用的两种数据结构,也是面试中常考的面试题之一.然而对于很多人来说,只是模糊的记得二者的区别,可能还记得不一定对,并且每次到了面试的时候,都得把这些的概念拿出来背一遍才行,未免有些麻 ...

  2. vc6.0转vs2012的一些错误与解决方法

    1>------ 已启动生成: 项目: NMW210, 配置: Debug Win32 ------ abs_position = fabs((float)posiTemp1 - (float) ...

  3. jmeter跨线程组传值和jmeter跨线程组调用

    Jmeter的线程组之间是独立的,用Jmeter做接口测试或者是性能测试时,经常会涉及到多个线程组.那么如何将A线程组返回的变量信息提取后,传递给B,C线程组使用呢?这里以已登录接口返回的access ...

  4. #Linux 下 Xampp的安装与Hello World

    一.下载安装 去官网下载 移动下载完毕的xampp-linux-x64-7.4.6-0-installer.run 到/usr/local/jayce-softwares/xampp目录下(jayce ...

  5. 07.DRF-序列化

    Serializer序列化器 序列化器的作用: 进行数据的校验 对数据对象进行转换 一.定义Serializer 1.1 定义方法 Django REST framework中的Serializer使 ...

  6. Linux性能优化思路

    性能测试的核心,就是找出性能瓶颈并进行性能优化,解决"慢"的问题,最终满足客户业务需求. [性能需求来源及性能问题现象] 性能需求的来源,主要分为以下几类: 项目组提出性能需求: ...

  7. 微信小程序-页面跳转与参数传递

    QQ讨论群:785071190 微信小程序页面跳转方式有很多种,可以像HTML中a标签一样添加标签进行跳转,也可以通过js中方法进行跳转. navigator标签跳转 <view class=& ...

  8. nginx在windows系统中启动、重启、停止,常用命令

    cmd终端在进入到nginx的安装目录下使用对应命令 查看nginx的版本号:nginx -v 启动nginx:start nginx 快速停止或关闭nginx:nginx -s stop 正常停止或 ...

  9. JavaWeb网上图书商城完整项目--day02-19.修改密码功能流程分析

    我们来看看修改密码的业务流程操作:

  10. Jmeter系列(29)- 详解 JDBC Connection Configuration

    如果你想从头学习Jmeter,可以看看这个系列的文章哦 https://www.cnblogs.com/poloyy/category/1746599.html 前言 发起 jdbc 请求前,需要有 ...