zijiema-zhiling.html 83.5 KB
Newer Older
沉默王二's avatar
沉默王二 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40
<!DOCTYPE html>
<html lang="zh-CN" data-theme="light">
  <head>
    <meta charset="utf-8" />
    <meta name="viewport" content="width=device-width,initial-scale=1" />
    <meta name="generator" content="VuePress 2.0.0-beta.46" />
    <meta name="theme" content="VuePress Theme Hope" />
    <meta property="og:url" content="https://tobebetterjavaer.com/jvm/zijiema-zhiling.html"><meta property="og:site_name" content="Java 程序员进阶之路"><meta property="og:title" content="JVM字节码指令详解"><meta property="og:type" content="article"><meta property="og:updated_time" content="2022-05-13T23:14:28.000Z"><meta property="og:locale" content="zh-CN"><meta property="article:tag" content="Java"><meta property="article:modified_time" content="2022-05-13T23:14:28.000Z"><script>
        var _hmt = _hmt || [];
        (function() {
          var hm = document.createElement("script");
          hm.src = "https://hm.baidu.com/hm.js?5230ac143650bf5eb3c14f3fb9b1d3ec";
          var s = document.getElementsByTagName("script")[0]; 
          s.parentNode.insertBefore(hm, s);
        })();
      </script><link rel="stylesheet" href="//at.alicdn.com/t/font_3180624_7cy10l7jqqh.css"><link rel="icon" href="/favicon.ico"><link rel="icon" href="/assets/icon/chrome-mask-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-mask-192.png" type="image/png" sizes="192x192"><link rel="icon" href="/assets/icon/chrome-512.png" type="image/png" sizes="512x512"><link rel="icon" href="/assets/icon/chrome-192.png" type="image/png" sizes="192x192"><link rel="manifest" href="/manifest.webmanifest" crossorigin="use-credentials"><meta name="theme-color" content="#46bd87"><link rel="apple-touch-icon" href="/assets/icon/apple-icon-152.png"><meta name="apple-mobile-web-app-capable" content="yes"><meta name="apple-mobile-web-app-status-bar-style" content="black"><meta name="msapplication-TileImage" content="/assets/icon/ms-icon-144.png"><meta name="msapplication-TileColor" content="#ffffff"><meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=no, viewport-fit=cover"><title>JVM字节码指令详解 | Java 程序员进阶之路</title><meta name="description" content="一份通俗易懂、风趣幽默的Java学习指南,内容涵盖Java基础、Java并发编程、Java虚拟机、Java企业级开发、Java面试等核心知识点。学Java,就认准Java程序员进阶之路">
    <style>
      :root {
        --bg-color: #fff;
      }

      html[data-theme="dark"] {
        --bg-color: #1d2025;
      }

      html,
      body {
        background-color: var(--bg-color);
      }
    </style>
    <script>
      const userMode = localStorage.getItem("vuepress-theme-hope-scheme");
      const systemDarkMode =
        window.matchMedia &&
        window.matchMedia("(prefers-color-scheme: dark)").matches;

      if (userMode === "dark" || (userMode !== "light" && systemDarkMode)) {
        document.querySelector("html").setAttribute("data-theme", "dark");
      }
    </script>
41
    <link rel="stylesheet" href="/assets/style.aa7884a9.css">
沉默王二's avatar
沉默王二 已提交
42
    <link rel="modulepreload" href="/assets/app.615e41d8.js"><link rel="modulepreload" href="/assets/zijiema-zhiling.html.60db7eb3.js"><link rel="modulepreload" href="/assets/plugin-vue_export-helper.21dcd24c.js"><link rel="modulepreload" href="/assets/zijiema-zhiling.html.34c655bc.js">
沉默王二's avatar
沉默王二 已提交
43 44
  </head>
  <body>
沉默王二's avatar
沉默王二 已提交
45
    <div id="app"><!--[--><!--[--><!--[--><span tabindex="-1"></span><a href="#main-content" class="skip-link sr-only">Skip to content</a><!--]--><div class="theme-container has-toc"><!--[--><!--[--><header class="navbar"><div class="navbar-left"><button class="toggle-sidebar-button" title="Toggle Sidebar"><span class="icon"></span></button><!----><a href="/" class="brand"><img class="logo" src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/logo-02.png" alt="Java 程序员进阶之路"><!----><span class="site-name hide-in-pad">Java 程序员进阶之路</span></a><!----></div><div class="navbar-center"><!----><nav class="nav-links"><div class="nav-item hide-in-mobile"><a href="/home.html" class="nav-link" aria-label="进阶之路"><span class="icon iconfont icon-lujing" style=""></span>进阶之路<!----></a></div><div class="nav-item hide-in-mobile"><a href="/zhishixingqiu/java-mianshi-zhinan.html" class="nav-link" aria-label="星球专栏"><span class="icon iconfont icon-Artboard" style=""></span>星球专栏<!----></a></div><div class="nav-item hide-in-mobile"><a href="/xuexiluxian/" class="nav-link" aria-label="学习路线"><span class="icon iconfont icon-luxian" style=""></span>学习路线<!----></a></div><div class="nav-item hide-in-mobile"><a href="https://space.bilibili.com/513340480" rel="noopener noreferrer" target="_blank" aria-label="B站视频" class="nav-link"><span class="icon iconfont icon-bzhan" style=""></span>B站视频<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><div class="nav-item hide-in-mobile"><div class="dropdown-wrapper"><button class="dropdown-title" type="button" aria-label="珍藏资源"><span class="title"><span class="icon iconfont icon-youzhi" style=""></span>珍藏资源</span><span class="arrow"></span><ul class="nav-dropdown"><li class="dropdown-item"><a href="/download/java.html" class="nav-link" aria-label="Java电子书下载"><span class="icon iconfont icon-java" style=""></span>Java电子书下载<!----></a></li><li class="dropdown-item"><a href="/sidebar/sanfene/nixi.html" class="nav-link" aria-label="面渣逆袭"><span class="icon iconfont icon-zhunbei" style=""></span>面渣逆袭<!----></a></li><li class="dropdown-item"><a href="/download/nicearticle.html" class="nav-link" aria-label="优质文章"><span class="icon iconfont icon-youzhi" style=""></span>优质文章<!----></a></li><li class="dropdown-item"><a href="/download/history.html" class="nav-link" aria-label="网络日志"><span class="icon iconfont icon-rizhi" style=""></span>网络日志<!----></a></li><li class="dropdown-item"><a href="https://docsify.tobebetterjavaer.com/" rel="noopener noreferrer" target="_blank" aria-label="回到过去" class="nav-link"><span class="icon iconfont icon-fanhuijiuban" style=""></span>回到过去<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></li></ul></button></div></div></nav><!----></div><div class="navbar-right"><!----><div class="nav-item"><!----></div><div class="nav-item"><a class="repo-link" href="https://github.com/itwanger/toBeBetterJavaer" target="_blank" rel="noopener noreferrer"><svg xmlns="http://www.w3.org/2000/svg" class="icon github-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="github icon" style="width:1.25rem;height:1.25rem;vertical-align:middle;"><path d="M511.957 21.333C241.024 21.333 21.333 240.981 21.333 512c0 216.832 140.544 400.725 335.574 465.664 24.49 4.395 32.256-10.07 32.256-23.083 0-11.69.256-44.245 0-85.205-136.448 29.61-164.736-64.64-164.736-64.64-22.315-56.704-54.4-71.765-54.4-71.765-44.587-30.464 3.285-29.824 3.285-29.824 49.195 3.413 75.179 50.517 75.179 50.517 43.776 75.008 114.816 53.333 142.762 40.79 4.523-31.66 17.152-53.377 31.19-65.537-108.971-12.458-223.488-54.485-223.488-242.602 0-53.547 19.114-97.323 50.517-131.67-5.035-12.33-21.93-62.293 4.779-129.834 0 0 41.258-13.184 134.912 50.346a469.803 469.803 0 0 1 122.88-16.554c41.642.213 83.626 5.632 122.88 16.554 93.653-63.488 134.784-50.346 134.784-50.346 26.752 67.541 9.898 117.504 4.864 129.834 31.402 34.347 50.474 78.123 50.474 131.67 0 188.586-114.73 230.016-224.042 242.09 17.578 15.232 33.578 44.672 33.578 90.454v135.85c0 13.142 7.936 27.606 32.854 22.87C862.25 912.597 1002.667 728.747 1002.667 512c0-271.019-219.648-490.667-490.71-490.667z"></path></svg></a></div><div class="nav-item hide-in-mobile"><button id="appearance-switch"><svg xmlns="http://www.w3.org/2000/svg" class="icon auto-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="auto icon" style="display:block;"><path d="M512 992C246.92 992 32 777.08 32 512S246.92 32 512 32s480 214.92 480 480-214.92 480-480 480zm0-840c-198.78 0-360 161.22-360 360 0 198.84 161.22 360 360 360s360-161.16 360-360c0-198.78-161.22-360-360-360zm0 660V212c165.72 0 300 134.34 300 300 0 165.72-134.28 300-300 300z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon dark-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="dark icon" style="display:none;"><path d="M524.8 938.667h-4.267a439.893 439.893 0 0 1-313.173-134.4 446.293 446.293 0 0 1-11.093-597.334A432.213 432.213 0 0 1 366.933 90.027a42.667 42.667 0 0 1 45.227 9.386 42.667 42.667 0 0 1 10.24 42.667 358.4 358.4 0 0 0 82.773 375.893 361.387 361.387 0 0 0 376.747 82.774 42.667 42.667 0 0 1 54.187 55.04 433.493 433.493 0 0 1-99.84 154.88 438.613 438.613 0 0 1-311.467 128z"></path></svg><svg xmlns="http://www.w3.org/2000/svg" class="icon light-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="light icon" style="display:none;"><path d="M952 552h-80a40 40 0 0 1 0-80h80a40 40 0 0 1 0 80zM801.88 280.08a41 41 0 0 1-57.96-57.96l57.96-58a41.04 41.04 0 0 1 58 58l-58 57.96zM512 752a240 240 0 1 1 0-480 240 240 0 0 1 0 480zm0-560a40 40 0 0 1-40-40V72a40 40 0 0 1 80 0v80a40 40 0 0 1-40 40zm-289.88 88.08-58-57.96a41.04 41.04 0 0 1 58-58l57.96 58a41 41 0 0 1-57.96 57.96zM192 512a40 40 0 0 1-40 40H72a40 40 0 0 1 0-80h80a40 40 0 0 1 40 40zm30.12 231.92a41 41 0 0 1 57.96 57.96l-57.96 58a41.04 41.04 0 0 1-58-58l58-57.96zM512 832a40 40 0 0 1 40 40v80a40 40 0 0 1-80 0v-80a40 40 0 0 1 40-40zm289.88-88.08 58 57.96a41.04 41.04 0 0 1-58 58l-57.96-58a41 41 0 0 1 57.96-57.96z"></path></svg></button></div><div id="docsearch-container"></div><!----><button class="toggle-navbar-button" aria-label="Toggle Navbar" aria-expanded="false" aria-controls="nav-screen"><span class="button-container"><span class="button-top"></span><span class="button-middle"></span><span class="button-bottom"></span></span></button></div></header><!----><!--]--><!----><div class="toggle-sidebar-wrapper"><span class="arrow left"></span></div><aside class="sidebar"><!--[--><!----><!--]--><ul class="sidebar-links"><li><!--[--><a href="/home.html" class="nav-link sidebar-link sidebar-page" aria-label="一、前言"><!---->一、前言<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">二、Java核心</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.1 Java概述</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.2 Java基础语法</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.3 面向对象编程</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.4 字符串&amp;数组</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.5 集合框架(容器)</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.6 IO</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.7 异常处理</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.8 常用工具类</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.9 Java新特性</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.10 Java重要知识点</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">2.11 并发编程</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable active"><!----><span class="title">2.12 JVM</span><span class="arrow down"></span></button><ul class="sidebar-links"><li><!--[--><a href="/jvm/what-is-jvm.html" class="nav-link sidebar-link sidebar-page" aria-label="JVM到底是什么?"><!---->JVM到底是什么?<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/how-run-java-code.html" class="nav-link sidebar-link sidebar-page" aria-label="JVM到底是如何运行Java代码的"><!---->JVM到底是如何运行Java代码的<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/class-load.html" class="nav-link sidebar-link sidebar-page" aria-label="类加载机制"><!---->类加载机制<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/class-file-jiegou.html" class="nav-link sidebar-link sidebar-page" aria-label="详解Java的类文件结构"><!---->详解Java的类文件结构<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/bytecode.html" class="nav-link sidebar-link sidebar-page" aria-label="从javap的角度轻松看懂字节码"><!---->从javap的角度轻松看懂字节码<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a aria-current="page" href="/jvm/zijiema-zhiling.html" class="router-link-active router-link-exact-active nav-link active sidebar-link sidebar-page active" aria-label="字节码指令详解"><!---->字节码指令详解<!----></a><ul class="sidebar-sub-headers"><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_01、加载与存储指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="01、加载与存储指令"><!---->01、加载与存储指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_02、算术指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="02、算术指令"><!---->02、算术指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_03、类型转换指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="03、类型转换指令"><!---->03、类型转换指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_04、对象的创建和访问指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="04、对象的创建和访问指令"><!---->04、对象的创建和访问指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_05、方法调用和返回指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="05、方法调用和返回指令"><!---->05、方法调用和返回指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_06、操作数栈管理指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="06、操作数栈管理指令"><!---->06、操作数栈管理指令<!----></a><ul class="sidebar-sub-headers"></ul></li><li class="sidebar-sub-header"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_07、控制转移指令" class="router-link-active router-link-exact-active nav-link sidebar-link heading" aria-label="07、控制转移指令"><!---->07、控制转移指令<!----></a><ul class="sidebar-sub-headers"></ul></li></ul><!--]--></li><li><!--[--><a href="/jvm/how-jvm-run-zijiema-zhiling.html" class="nav-link sidebar-link sidebar-page" aria-label="虚拟机是如何执行字节码指令的"><!---->虚拟机是如何执行字节码指令的<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/hsdb.html" class="nav-link sidebar-link sidebar-page" aria-label="HSDB(Hotspot Debugger)"><!---->HSDB(Hotspot Debugger)<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/asm.html" class="nav-link sidebar-link sidebar-page" aria-label="史上最通俗易懂的ASM教程"><!---->史上最通俗易懂的ASM教程<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/compile-jdk.html" class="nav-link sidebar-link sidebar-page" aria-label="自己编译JDK"><!---->自己编译JDK<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/neicun-jiegou.html" class="nav-link sidebar-link sidebar-page" aria-label="深入理解JVM的内存结构"><!---->深入理解JVM的内存结构<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/whereis-the-object.html" class="nav-link sidebar-link sidebar-page" aria-label="Java 创建的对象到底放在哪"><!---->Java 创建的对象到底放在哪<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/gc.html" class="nav-link sidebar-link sidebar-page" aria-label="从头到尾说一次Java垃圾回收"><!---->从头到尾说一次Java垃圾回收<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/tujie-gc.html" class="nav-link sidebar-link sidebar-page" aria-label="图解Java的垃圾回收机制"><!---->图解Java的垃圾回收机制<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/problem-tools.html" class="nav-link sidebar-link sidebar-page" aria-label="Java问题诊断和排查工具"><!---->Java问题诊断和排查工具<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/jit.html" class="nav-link sidebar-link sidebar-page" aria-label="JIT原理解析及实践"><!---->JIT原理解析及实践<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/oom.html" class="nav-link sidebar-link sidebar-page" aria-label="内存溢出排查优化实战"><!---->内存溢出排查优化实战<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/cpu-percent-100.html" class="nav-link sidebar-link sidebar-page" aria-label="CPU 100% 排查优化实践"><!---->CPU 100% 排查优化实践<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li><li><!--[--><a href="/jvm/zongjie.html" class="nav-link sidebar-link sidebar-page" aria-label="JVM 核心知识点总结"><!---->JVM 核心知识点总结<!----></a><ul class="sidebar-sub-headers"></ul><!--]--></li></ul></section><!--]--></li></ul></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">三、Java企业级开发</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">四、数据库</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">五、计算机基础</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">六、求职面试</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">七、学习资源</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">八、知识库搭建</span><span class="arrow right"></span></button><!----></section><!--]--></li><li><!--[--><section class="sidebar-group"><button class="sidebar-heading clickable"><!----><span class="title">九、联系作者</span><span class="arrow right"></span></button><!----></section><!--]--></li></ul><!--[--><!----><!--]--></aside><!--[--><main class="page" id="main-content"><!--[--><!----><nav class="breadcrumb disable"></nav><div class="page-title"><h1><!---->JVM字节码指令详解</h1><div class="page-info"><span class="author-info" aria-label="作者🖊" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon author-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="author icon"><path d="M649.6 633.6c86.4-48 147.2-144 147.2-249.6 0-160-128-288-288-288s-288 128-288 288c0 108.8 57.6 201.6 147.2 249.6-121.6 48-214.4 153.6-240 288-3.2 9.6 0 19.2 6.4 25.6 3.2 9.6 12.8 12.8 22.4 12.8h704c9.6 0 19.2-3.2 25.6-12.8 6.4-6.4 9.6-16 6.4-25.6-25.6-134.4-121.6-240-243.2-288z"></path></svg><span><a class="author-item" href="https://tobebetterjavaer.com" target="_blank" rel="noopener noreferrer">沉默王二</a></span><span property="author" content="沉默王二"></span></span><!----><span class="date-info" aria-label="写作日期📅" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon calendar-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="calendar icon"><path d="M716.4 110.137c0-18.753-14.72-33.473-33.472-33.473-18.753 0-33.473 14.72-33.473 33.473v33.473h66.993v-33.473zm-334.87 0c0-18.753-14.72-33.473-33.473-33.473s-33.52 14.72-33.52 33.473v33.473h66.993v-33.473zm468.81 33.52H716.4v100.465c0 18.753-14.72 33.473-33.472 33.473a33.145 33.145 0 01-33.473-33.473V143.657H381.53v100.465c0 18.753-14.72 33.473-33.473 33.473a33.145 33.145 0 01-33.473-33.473V143.657H180.6A134.314 134.314 0 0046.66 277.595v535.756A134.314 134.314 0 00180.6 947.289h669.74a134.36 134.36 0 00133.94-133.938V277.595a134.314 134.314 0 00-133.94-133.938zm33.473 267.877H147.126a33.145 33.145 0 01-33.473-33.473c0-18.752 14.72-33.473 33.473-33.473h736.687c18.752 0 33.472 14.72 33.472 33.473a33.145 33.145 0 01-33.472 33.473z"></path></svg><span>2022年3月27日</span><meta property="datePublished" content="2022-03-27T04:07:13.000Z"></span><span class="category-info" aria-label="分类🌈" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon category-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="category icon"><path d="M148.41 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H148.41c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.311-40.31zM147.556 553.478H429.73c22.263 0 40.311 18.048 40.311 40.31v282.176c0 22.263-18.048 40.312-40.31 40.312H147.555c-22.263 0-40.311-18.049-40.311-40.312V593.79c0-22.263 18.048-40.311 40.31-40.311zM593.927 106.992h282.176c22.263 0 40.31 18.048 40.31 40.31V429.48c0 22.263-18.047 40.31-40.31 40.31H593.927c-22.263 0-40.311-18.047-40.311-40.31V147.302c0-22.263 18.048-40.31 40.31-40.31zM730.22 920.502H623.926c-40.925 0-74.22-33.388-74.22-74.425V623.992c0-41.038 33.387-74.424 74.425-74.424h222.085c41.038 0 74.424 33.226 74.424 74.067v114.233c0 10.244-8.304 18.548-18.547 18.548s-18.548-8.304-18.548-18.548V623.635c0-20.388-16.746-36.974-37.33-36.974H624.13c-20.585 0-37.331 16.747-37.331 37.33v222.086c0 20.585 16.654 37.331 37.126 37.331H730.22c10.243 0 18.547 8.304 18.547 18.547 0 10.244-8.304 18.547-18.547 18.547z"></path></svg><ul class="categories-wrapper"><li class="category category0" role>Java核心</li><li class="category category1" role>JVM</li><meta property="articleSection" content="Java核心,JVM"></ul></span><span aria-label="标签🏷" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon tag-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="tag icon"><path d="M939.902 458.563L910.17 144.567c-1.507-16.272-14.465-29.13-30.737-30.737L565.438 84.098h-.402c-3.215 0-5.726 1.005-7.634 2.913l-470.39 470.39a10.004 10.004 0 000 14.164l365.423 365.424c1.909 1.908 4.42 2.913 7.132 2.913s5.223-1.005 7.132-2.913l470.39-470.39c2.01-2.11 3.014-5.023 2.813-8.036zm-240.067-72.121c-35.458 0-64.286-28.828-64.286-64.286s28.828-64.285 64.286-64.285 64.286 28.828 64.286 64.285-28.829 64.286-64.286 64.286z"></path></svg><ul class="tags-wrapper"><li class="tag tag4" role>Java</li></ul><meta property="keywords" content="Java"></span><span class="reading-time-info" aria-label="阅读时间⌛" data-balloon-pos="down" isoriginal="false" pageview="false"><svg xmlns="http://www.w3.org/2000/svg" class="icon timer-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="timer icon"><path d="M799.387 122.15c4.402-2.978 7.38-7.897 7.38-13.463v-1.165c0-8.933-7.38-16.312-16.312-16.312H256.33c-8.933 0-16.311 7.38-16.311 16.312v1.165c0 5.825 2.977 10.874 7.637 13.592 4.143 194.44 97.22 354.963 220.201 392.763-122.204 37.542-214.893 196.511-220.2 389.397-4.661 5.049-7.638 11.651-7.638 19.03v5.825h566.49v-5.825c0-7.379-2.849-13.981-7.509-18.9-5.049-193.016-97.867-351.985-220.2-389.527 123.24-37.67 216.446-198.453 220.588-392.892zM531.16 450.445v352.632c117.674 1.553 211.787 40.778 211.787 88.676H304.097c0-48.286 95.149-87.382 213.728-88.676V450.445c-93.077-3.107-167.901-81.297-167.901-177.093 0-8.803 6.99-15.793 15.793-15.793 8.803 0 15.794 6.99 15.794 15.793 0 80.261 63.69 145.635 142.01 145.635s142.011-65.374 142.011-145.635c0-8.803 6.99-15.793 15.794-15.793s15.793 6.99 15.793 15.793c0 95.019-73.789 172.82-165.96 177.093z"></path></svg><span>大约 17 分钟</span><meta property="timeRequired" content="PT17M"></span></div><hr></div><div class="toc-place-holder"><aside id="toc"><div class="toc-header">此页内容</div><div class="toc-wrapper"><ul class="toc-list"><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_01、加载与存储指令" class="router-link-active router-link-exact-active toc-link level3">01、加载与存储指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_02、算术指令" class="router-link-active router-link-exact-active toc-link level3">02、算术指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_03、类型转换指令" class="router-link-active router-link-exact-active toc-link level3">03、类型转换指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_04、对象的创建和访问指令" class="router-link-active router-link-exact-active toc-link level3">04、对象的创建和访问指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_05、方法调用和返回指令" class="router-link-active router-link-exact-active toc-link level3">05、方法调用和返回指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_06、操作数栈管理指令" class="router-link-active router-link-exact-active toc-link level3">06、操作数栈管理指令</a></li><!----><!--]--><!--[--><li class="toc-item"><a aria-current="page" href="/jvm/zijiema-zhiling.html#_07、控制转移指令" class="router-link-active router-link-exact-active toc-link level3">07、控制转移指令</a></li><!----><!--]--></ul></div></aside></div><!----><div class="theme-hope-content"><h1 id="jvm字节码指令详解" tabindex="-1"><a class="header-anchor" href="#jvm字节码指令详解" aria-hidden="true">#</a> JVM字节码指令详解</h1><p>大家好,我是二哥呀。Java 字节码指令是 JVM 体系中非常难啃的一块硬骨头,我估计有些读者会有这样的疑惑,“Java 字节码难学吗?我能不能学会啊?”</p><p>讲良心话,不是我谦虚,一开始学 Java 字节码和 Java 虚拟机方面的知识我也感觉头大!但硬着头皮学了一阵子之后,突然就开窍了,觉得好有意思,尤其是明白了 Java 代码在底层竟然是这样执行的时候,感觉既膨胀又飘飘然,浑身上下散发着自信的光芒!</p><p>Java 官方的虚拟机 Hotspot 是基于栈的,而不是基于寄存器的。</p><p>基于栈的优点是可移植性更好、指令更短、实现起来简单,但不能随机访问栈中的元素,完成相同功能所需要的指令数也比寄存器的要多,需要频繁的入栈和出栈。</p><p>基于寄存器的优点是速度快,有利于程序运行速度的优化,但操作数需要显式指定,指令也比较长。</p><p>Java 字节码由操作码和操作数组成。</p><ul><li>操作码(Opcode):一个字节长度(0-255,意味着指令集的操作码总数不可能超过 256 条),代表着某种特定的操作含义。</li><li>操作数(Operands):零个或者多个,紧跟在操作码之后,代表此操作需要的参数。</li></ul><p>由于 Java 虚拟机是基于栈而不是寄存器的结构,所以大多数指令都只有一个操作码。比如 <code>aload_0</code>(将局部变量表中下标为 0 的数据压入操作数栈中)就只有操作码没有操作数,而 <code>invokespecial #1</code>(调用成员方法或者构造方法,并传递常量池中下标为 1 的常量)就是由操作码和操作数组成的。</p><h3 id="_01、加载与存储指令" tabindex="-1"><a class="header-anchor" href="#_01、加载与存储指令" aria-hidden="true">#</a> 01、加载与存储指令</h3><p>加载(load)和存储(store)相关的指令是使用最频繁的指令,用于将数据从栈帧的局部变量表和操作数栈之间来回传递。</p><p><strong>1)将局部变量表中的变量压入操作数栈中</strong></p><ul><li><code>xload_&lt;n&gt;</code>(x 为 i、l、f、d、a,n 默认为 0 到 3),表示将第 n 个局部变量压入操作数栈中。</li><li>xload(x 为 i、l、f、d、a),通过指定参数的形式,将局部变量压入操作数栈中,当使用这个指令时,表示局部变量的数量可能超过了 4 个</li></ul><p>解释一下。</p><p>x 为操作码助记符,表明是哪一种数据类型。见下表所示。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-879da2f2-fb72-48a9-985e-5a28a9fc8814.png" alt=""></p><p>像 arraylength 指令,没有操作码助记符,它没有代表数据类型的特殊字符,但操作数只能是一个数组类型的对象。</p><p>大部分的指令都不支持 byte、short 和 char,甚至没有任何指令支持 boolean 类型。编译器会将 byte 和 short 类型的数据带符号扩展(Sign-Extend)为 int 类型,将 boolean 和 char 零位扩展(Zero-Extend)为 int 类型。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">load</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token keyword">long</span> birthday<span class="token punctuation">,</span> <span class="token keyword">boolean</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
沉默王二's avatar
沉默王二 已提交
46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>age <span class="token operator">+</span> name <span class="token operator">+</span> birthday <span class="token operator">+</span> sex<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>load()</code> 方法(4 个参数)的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-05bfae95-2a33-402c-9041-570093729c42.png" alt=""></p><ul><li>iload_1:将局部变量表中下标为 1 的 int 变量压入操作数栈中。</li><li>aload_2:将局部变量表中下标为 2 的引用数据类型变量(此时为 String)压入操作数栈中。</li><li>lload_3:将局部变量表中下标为 3 的 long 型变量压入操作数栈中。</li><li>iload 5:将局部变量表中下标为 5 的 int 变量(实际为 boolean)压入操作数栈中。</li></ul><p>通过查看局部变量表就能关联上了。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-79d74946-ce9e-41d4-b889-bda861f847bc.png" alt=""></p><p><strong>2)将常量池中的常量压入操作数栈中</strong></p><p>根据数据类型和入栈内容的不同,此类又可以细分为 const 系列、push 系列和 Idc 指令。</p><p><strong>const 系列</strong>,用于特殊的常量入栈,要入栈的常量隐含在指令本身。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-270c314d-872b-43b0-861f-417eafc046fd.png" alt=""></p><p><strong>push 系列</strong>,主要包括 bipush 和 sipush,前者接收 8 位整数作为参数,后者接收 16 位整数。</p><p><strong>Idc 指令</strong>,当 const 和 push 不能满足的时候,万能的 Idc 指令就上场了,它接收一个 8 位的参数,指向常量池中的索引。</p><ul><li><code>Idc_w</code>:接收两个 8 位数,索引范围更大。</li><li>如果参数是 long 或者 double,使用 <code>Idc2_w</code> 指令。</li></ul><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">pushConstLdc</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token comment">// 范围 [-1,5]</span>
    <span class="token keyword">int</span> iconst <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token comment">// 范围 [-128,127]</span>
    <span class="token keyword">int</span> bipush <span class="token operator">=</span> <span class="token number">127</span><span class="token punctuation">;</span>
    <span class="token comment">// 范围 [-32768,32767]</span>
    <span class="token keyword">int</span> sipush<span class="token operator">=</span> <span class="token number">32767</span><span class="token punctuation">;</span>
    <span class="token comment">// 其他 int</span>
    <span class="token keyword">int</span> ldc <span class="token operator">=</span> <span class="token number">32768</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> aconst <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> <span class="token class-name">IdcString</span> <span class="token operator">=</span> <span class="token string">&quot;沉默王二&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>pushConstLdc()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-b34fc802-18bb-46a1-8d24-de2087c9b6bf.png" alt=""></p><ul><li>iconst_m1:将 -1 入栈。范围 [-1,5]。</li><li>bipush 127:将 127 入栈。范围 [-128,127]。</li><li>sipush 32767:将 32767 入栈。范围 [-32768,32767]。</li><li>ldc #6 &lt;32768&gt;:将常量池中下标为 6 的常量 32768 入栈。</li><li>aconst_null:将 null 入栈。</li><li>ldc #7 &lt;沉默王二&gt;:将常量池中下标为 7 的常量“沉默王二”入栈。</li></ul><p><strong>3)将栈顶的数据出栈并装入局部变量表中</strong></p><p>主要是用来给局部变量赋值,这类指令主要以 store 的形式存在。</p><ul><li><code>xstore_&lt;n&gt;</code>(x 为 i、l、f、d、a,n 默认为 0 到 3)</li><li>xstore(x 为 i、l、f、d、a)</li></ul><p>明白了 <code>xload_&lt;n&gt;</code> 和 xload,再看 <code>xstore_&lt;n&gt;</code> 和 xstore 就会轻松得多,作用反了一下而已。</p><p>大家来想一个问题,为什么要有 <code>xstore_&lt;n&gt;</code><code>xload_&lt;n&gt;</code> 呢?它们的作用和 xstore n、xload n 不是一样的吗?</p><p><code>xstore_&lt;n&gt;</code> 和 xstore n 的区别在于,前者相当于只有操作码,占用 1 个字节;后者相当于由操作码和操作数组成,操作码占 1 个字节,操作数占 2 个字节,一共占 3 个字节。</p><p>由于局部变量表中前几个位置总是非常常用,虽然 <code>xstore_&lt;n&gt;</code><code>xload_&lt;n&gt;</code> 增加了指令数量,但字节码的体积变小了!</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">store</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">,</span> <span class="token class-name">String</span> name<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> temp <span class="token operator">=</span> age <span class="token operator">+</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token class-name">String</span> str <span class="token operator">=</span> name<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>store()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-d955468c-d07d-47cd-b82b-c03ecea8753d.png" alt=""></p><ul><li>istore_3:从操作数中弹出一个整数,并把它赋值给局部变量表中索引为 3 的变量。</li><li>astore 4:从操作数中弹出一个引用数据类型,并把它赋值给局部变量表中索引为 4 的变量。</li></ul><p>通过查看局部变量表就能关联上了。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-a08c20cb-c148-47c9-91e2-df37e68989a9.png" alt=""></p><h3 id="_02、算术指令" tabindex="-1"><a class="header-anchor" href="#_02、算术指令" aria-hidden="true">#</a> 02、算术指令</h3><p>算术指令用于对两个操作数栈上的值进行某种特定运算,并把结果重新压入操作数栈。可以分为两类:整型数据的运算指令和浮点数据的运算指令。</p><p>需要注意的是,<strong>数据运算可能会导致溢出</strong>,比如两个很大的正整数相加,很可能会得到一个负数。但 Java 虚拟机规范中并没有对这种情况给出具体结果,因此程序是不会显式报错的。所以,大家在开发过程中,如果涉及到较大的数据进行加法、乘法运算的时候,一定要注意!</p><p>当发生溢出时,将会使用有符号的无穷大 Infinity 来表示;如果某个操作结果没有明确的数学定义的话,将会使用 NaN 值来表示。而且所有使用 NaN 作为操作数的算术操作,结果都会返回 NaN。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">infinityNaN</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
    <span class="token keyword">double</span> j <span class="token operator">=</span> i <span class="token operator">/</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>j<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// Infinity</span>

    <span class="token keyword">double</span> d1 <span class="token operator">=</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
    <span class="token keyword">double</span> d2 <span class="token operator">=</span> d1 <span class="token operator">/</span> <span class="token number">0.0</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>d2<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// NaN</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><ul><li>任何一个非零的数除以浮点数 0(注意不是 int 类型),可以想象结果是无穷大 Infinity 的。</li><li>把这个非零的数换成 0 的时候,结果又不太好定义,就用 NaN 值来表示。</li></ul><p>Java 虚拟机提供了两种<strong>运算模式</strong></p><ul><li>向最接近数舍入:在进行浮点数运算时,所有的结果都必须舍入到一个适当的精度,不是特别精确的结果必须舍入为可被表示的最接近的精确值,如果有两种可表示的形式与该值接近,将优先选择最低有效位为零的(类似四舍五入)。</li><li>向零舍入:将浮点数转换为整数时,采用该模式,该模式将在目标数值类型中选择一个最接近但是不大于原值的数字作为最精确的舍入结果(类似取整)。</li></ul><p>我把所有的算术指令列一下:</p><ul><li>加法指令:iadd、ladd、fadd、dadd</li><li>减法指令:isub、lsub、fsub、dsub</li><li>乘法指令:imul、lmul、fmul、dmul</li><li>除法指令:idiv、ldiv、fdiv、ddiv</li><li>求余指令:irem、lrem、frem、drem</li><li>自增指令:iinc</li></ul><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">calculate</span><span class="token punctuation">(</span><span class="token keyword">int</span> age<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> add <span class="token operator">=</span> age <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> sub <span class="token operator">=</span> age <span class="token operator">-</span> <span class="token number">1</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> mul <span class="token operator">=</span> age <span class="token operator">*</span> <span class="token number">2</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> div <span class="token operator">=</span> age <span class="token operator">/</span> <span class="token number">3</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> rem <span class="token operator">=</span> age <span class="token operator">%</span> <span class="token number">4</span><span class="token punctuation">;</span>
    age<span class="token operator">++</span><span class="token punctuation">;</span>
    age<span class="token operator">--</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>calculate()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-598e4204-fd77-425b-b536-1e001cda8e13.png" alt=""></p><ul><li>iadd,加法</li><li>isub,减法</li><li>imul,乘法</li><li>idiv,除法</li><li>irem,取余</li><li>iinc,自增的时候 +1,自减的时候 -1</li></ul><h3 id="_03、类型转换指令" tabindex="-1"><a class="header-anchor" href="#_03、类型转换指令" aria-hidden="true">#</a> 03、类型转换指令</h3><p>可以分为两种:</p><p>1)宽化,小类型向大类型转换,比如 <code>int–&gt;long–&gt;float–&gt;double</code>,对应的指令有:i2l、i2f、i2d、l2f、l2d、f2d。</p><ul><li>从 int 到 long,或者从 int 到 double,是不会有精度丢失的;</li><li>从 int、long 到 float,或者 long 到 double 时,可能会发生精度丢失;</li><li>从 byte、char 和 short 到 int 的宽化类型转换实际上是隐式发生的,这样可以减少字节码指令,毕竟字节码指令只有 256 个,占一个字节。</li></ul><p>2)窄化,大类型向小类型转换,比如从 int 类型到 byte、short 或者 char,对应的指令有:i2b、i2s、i2c;从 long 到 int,对应的指令有:l2i;从 float 到 int 或者 long,对应的指令有:f2i、f2l;从 double 到 int、long 或者 float,对应的指令有:d2i、d2l、d2f。</p><ul><li>窄化很可能会发生精度丢失,毕竟是不同的数量级;</li><li>但 Java 虚拟机并不会因此抛出运行时异常。</li></ul><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">updown</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
    <span class="token keyword">double</span> d <span class="token operator">=</span> i<span class="token punctuation">;</span>
    
    <span class="token keyword">float</span> f <span class="token operator">=</span> <span class="token number">10f</span><span class="token punctuation">;</span>
    <span class="token keyword">long</span> ong <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token keyword">long</span><span class="token punctuation">)</span>f<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>updown()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-0c3e47c6-1e25-4926-a838-20cf146a8993.png" alt=""></p><ul><li>i2d,int 宽化为 double</li><li>f2l, float 窄化为 long</li></ul><h3 id="_04、对象的创建和访问指令" tabindex="-1"><a class="header-anchor" href="#_04、对象的创建和访问指令" aria-hidden="true">#</a> 04、对象的创建和访问指令</h3><p>Java 是一门面向对象的编程语言,那么 Java 虚拟机是如何从字节码层面进行支持的呢?</p><p><strong>1)创建指令</strong></p><p>数组也是一种对象,但它创建的字节码指令和普通的对象不同。创建数组的指令有三种:</p><ul><li>newarray:创建基本数据类型的数组</li><li>anewarray:创建引用类型的数组</li><li>multianewarray:创建多维数组</li></ul><p>普通对象的创建指令只有一个,就是 <code>new</code>,它会接收一个操作数,指向常量池中的一个索引,表示要创建的类型。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">newObject</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token class-name">String</span> name <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">(</span><span class="token string">&quot;沉默王二&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token class-name">File</span> file <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">File</span><span class="token punctuation">(</span><span class="token string">&quot;无愁河的浪荡汉子.book&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> <span class="token punctuation">[</span><span class="token punctuation">]</span> ages <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>newObject()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-8125da3d-876c-43fe-8347-cb2341408088.png" alt=""></p><ul><li><code>new #13 &lt;java/lang/String&gt;</code>,创建一个 String 对象。</li><li><code>new #15 &lt;java/io/File&gt;</code>,创建一个 File 对象。</li><li><code>newarray 10 (int)</code>,创建一个 int 类型的数组。</li></ul><p><strong>2)字段访问指令</strong></p><p>字段可以分为两类,一类是成员变量,一类是静态变量(static 关键字修饰的),所以字段访问指令可以分为两类:</p><ul><li>访问静态变量:getstatic、putstatic。</li><li>访问成员变量:getfield、putfield,需要创建对象后才能访问。</li></ul><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Writer</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token class-name">String</span> name<span class="token punctuation">;</span>
    <span class="token keyword">static</span> <span class="token class-name">String</span> mark <span class="token operator">=</span> <span class="token string">&quot;作者&quot;</span><span class="token punctuation">;</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">print</span><span class="token punctuation">(</span>mark<span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">Writer</span> w <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Writer</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token function">print</span><span class="token punctuation">(</span>w<span class="token punctuation">.</span>name<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token class-name">String</span> arg<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>arg<span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>main()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-70441cfc-7c6e-4a5e-b0dd-818fc3fa1a67.png" alt=""></p><ul><li><code>getstatic #2 &lt;com/itwanger/jvm/Writer.mark&gt;</code>,访问静态变量 mark</li><li><code>getfield #6 &lt;com/itwanger/jvm/Writer.name&gt;</code>,访问成员变量 name</li></ul><h3 id="_05、方法调用和返回指令" tabindex="-1"><a class="header-anchor" href="#_05、方法调用和返回指令" aria-hidden="true">#</a> 05、方法调用和返回指令</h3><p>方法调用指令有 5 个,分别用于不同的场景:</p><ul><li>invokevirtual:用于调用对象的成员方法,根据对象的实际类型进行分派,支持多态。</li><li>invokeinterface:用于调用接口方法,会在运行时搜索由特定对象实现的接口方法进行调用。</li><li>invokespecial:用于调用一些需要特殊处理的方法,包括构造方法、私有方法和父类方法。</li><li>invokestatic:用于调用静态方法。</li><li>invokedynamic:用于在运行时动态解析出调用点限定符所引用的方法,并执行。</li></ul><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">InvokeExamples</span> <span class="token punctuation">{</span>
    <span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">List</span> ls <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        ls<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">&quot;难顶&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>

        <span class="token class-name">ArrayList</span> als <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        als<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token string">&quot;学不动了&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span><span class="token string">&quot;invokestatic&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>

    <span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">void</span> <span class="token function">main</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> args<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token function">print</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        <span class="token class-name">InvokeExamples</span> invoke <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">InvokeExamples</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
        invoke<span class="token punctuation">.</span><span class="token function">run</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>我们用 <code>javap -c InvokeExamples.class</code> 来反编译一下。</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>Compiled from &quot;InvokeExamples.java&quot;
public class com.itwanger.jvm.InvokeExamples {
  public com.itwanger.jvm.InvokeExamples();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
       4: return

  private void run();
    Code:
       0: new           #2                  // class java/util/ArrayList
       3: dup
       4: invokespecial #3                  // Method java/util/ArrayList.&quot;&lt;init&gt;&quot;:()V
       7: astore_1
       8: aload_1
       9: ldc           #4                  // String 难顶
      11: invokeinterface #5,  2            // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
      16: pop
      17: new           #2                  // class java/util/ArrayList
      20: dup
      21: invokespecial #3                  // Method java/util/ArrayList.&quot;&lt;init&gt;&quot;:()V
      24: astore_2
      25: aload_2
      26: ldc           #6                  // String 学不动了
      28: invokevirtual #7                  // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
      31: pop
      32: return

  public static void print();
    Code:
       0: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
       3: ldc           #9                  // String invokestatic
       5: invokevirtual #10                 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
       8: return

  public static void main(java.lang.String[]);
    Code:
       0: invokestatic  #11                 // Method print:()V
       3: new           #12                 // class com/itwanger/jvm/InvokeExamples
       6: dup
       7: invokespecial #13                 // Method &quot;&lt;init&gt;&quot;:()V
      10: astore_1
      11: aload_1
      12: invokevirtual #14                 // Method run:()V
      15: return
}
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>InvokeExamples 类有 4 个方法,包括缺省的构造方法在内。</p><p>1)<code>InvokeExamples()</code> 构造方法中</p><p>缺省的构造方法内部会调用超类 Object 的初始化构造方法:</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>`invokespecial #1 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V`
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>2)成员方法 <code>run()</code></p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>invokeinterface #5,  2  // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>由于 ls 变量的引用类型为接口 List,所以 <code>ls.add()</code> 调用的是 <code>invokeinterface</code> 指令,等运行时再确定是不是接口 List 的实现对象 ArrayList 的 <code>add()</code> 方法。</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>invokevirtual #7 // Method java/util/ArrayList.add:(Ljava/lang/Object;)Z
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p>由于 als 变量的引用类型已经确定为 ArrayList,所以 <code>als.add()</code> 方法调用的是 <code>invokevirtual</code> 指令。</p><p>3)<code>main()</code> 方法中</p><div class="language-text ext-text line-numbers-mode"><pre class="language-text"><code>invokestatic  #11 // Method print:()V
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div></div></div><p><code>print()</code> 方法是静态的,所以调用的是 <code>invokestatic</code> 指令。</p><p>方法返回指令根据方法的返回值类型进行区分,常见的返回指令见下图。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-37513fa2-fdba-45db-adfc-c18225c6ff8b.png" alt=""></p><h3 id="_06、操作数栈管理指令" tabindex="-1"><a class="header-anchor" href="#_06、操作数栈管理指令" aria-hidden="true">#</a> 06、操作数栈管理指令</h3><p>常见的操作数栈管理指令有 pop、dup 和 swap。</p><ul><li>将一个或两个元素从栈顶弹出,并且直接废弃,比如 pop,pop2;</li><li>复制栈顶的一个或两个数值并将其重新压入栈顶,比如 dup,dup2,dup_×1,dup2_×1,dup_×2,dup2_×2;</li><li>将栈最顶端的两个槽中的数值交换位置,比如 swap。</li></ul><p>这些指令不需要指明数据类型,因为是按照位置压入和弹出的。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Dup</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> age<span class="token punctuation">;</span>
    <span class="token keyword">public</span> <span class="token keyword">int</span> <span class="token function">incAndGet</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">return</span> <span class="token operator">++</span>age<span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>incAndGet()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-642ca54e-5808-428d-9840-ebf478e95c17.png" alt=""></p><ul><li>aload_0:将 this 入栈。</li><li>dup:复制栈顶的 this。</li><li>getfield #2:将常量池中下标为 2 的常量加载到栈上,同时将一个 this 出栈。</li><li>iconst_1:将常量 1 入栈。</li><li>iadd:将栈顶的两个值相加后出栈,并将结果放回栈上。</li><li>dup_x1:复制栈顶的元素,并将其插入 this 下面。</li><li>putfield #2: 将栈顶的两个元素出栈,并将其赋值给字段 age。</li><li>ireturn:将栈顶的元素出栈返回。</li></ul><h3 id="_07、控制转移指令" tabindex="-1"><a class="header-anchor" href="#_07、控制转移指令" aria-hidden="true">#</a> 07、控制转移指令</h3><p>控制转移指令包括:</p><ul><li>比较指令,比较栈顶的两个元素的大小,并将比较结果入栈。</li><li>条件跳转指令,通常和比较指令一块使用,在条件跳转指令执行前,一般先用比较指令进行栈顶元素的比较,然后进行条件跳转。</li><li>比较条件转指令,类似于比较指令和条件跳转指令的结合体,它将比较和跳转两个步骤合二为一。</li><li>多条件分支跳转指令,专为 switch-case 语句设计的。</li><li>无条件跳转指令,目前主要是 goto 指令。</li></ul><p><strong>1)比较指令</strong></p><p>比较指令有:dcmpg,dcmpl、fcmpg、fcmpl、lcmp,指令的第一个字母代表的含义分别是 double、float、long。注意,没有 int 类型。</p><p>对于 double 和 float 来说,由于 NaN 的存在,有两个版本的比较指令。拿 float 来说,有 fcmpg 和 fcmpl,区别在于,如果遇到 NaN,fcmpg 会将 1 压入栈,fcmpl 会将 -1 压入栈。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">lcmp</span><span class="token punctuation">(</span><span class="token keyword">long</span> a<span class="token punctuation">,</span> <span class="token keyword">long</span> b<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">if</span><span class="token punctuation">(</span>a <span class="token operator">&gt;</span> b<span class="token punctuation">)</span><span class="token punctuation">{</span><span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>lcmp()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-e8fa6685-b3d4-4f42-8fc5-8a4d8a9efe7b.png" alt=""></p><p>lcmp 用于两个 long 型的数据进行比较。</p><p><strong>2)条件跳转指令</strong></p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-5de34f26-52ad-4e07-a20d-91ea92038984.png" alt=""></p><p>这些指令都会接收两个字节的操作数,它们的统一含义是,弹出栈顶元素,测试它是否满足某一条件,满足的话,跳转到对应位置。</p><p>对于 long、float 和 double 类型的条件分支比较,会先执行比较指令返回一个整型值到操作数栈中后再执行 int 类型的条件跳转指令。</p><p>对于 boolean、byte、char、short,以及 int,则直接使用条件跳转指令来完成。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">fi</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
    <span class="token keyword">if</span> <span class="token punctuation">(</span>a <span class="token operator">==</span> <span class="token number">0</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
        a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
        a <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>fi()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-d0561d5c-ae21-48e7-9e7c-4aae87d02f56.png" alt=""></p><p><code>3 ifne 12 (+9)</code> 的意思是,如果栈顶的元素不等于 0,跳转到第 12(3+9)行 <code>12 bipush 20</code></p><p><strong>3)比较条件转指令</strong></p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-bfab6edd-d63f-45a7-8838-997e7630fa2a.png" alt=""></p><p>前缀“if_”后,以字符“i”开头的指令针对 int 型整数进行操作,以字符“a”开头的指令表示对象的比较。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">compare</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
    <span class="token keyword">int</span> j <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
    <span class="token class-name">System</span><span class="token punctuation">.</span>out<span class="token punctuation">.</span><span class="token function">println</span><span class="token punctuation">(</span>i <span class="token operator">&gt;</span> j<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>compare()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-d4f9a680-1364-4af9-9474-c0763c9bc6f7.png" alt=""></p><p><code>11 if_icmple 18 (+7)</code> 的意思是,如果栈顶的两个 int 类型的数值比较的话,如果前者小于后者时跳转到第 18 行(11+7)。</p><p><strong>4)多条件分支跳转指令</strong></p><p>主要有 tableswitch 和 lookupswitch,前者要求多个条件分支值是连续的,它内部只存放起始值和终止值,以及若干个跳转偏移量,通过给定的操作数 index,可以立即定位到跳转偏移量位置,因此效率比较高;后者内部存放着各个离散的 case-offset 对,每次执行都要搜索全部的 case-offset 对,找到匹配的 case 值,并根据对应的 offset 计算跳转地址,因此效率较低。</p><p>举例来说。</p><div class="language-java ext-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">switchTest</span><span class="token punctuation">(</span><span class="token keyword">int</span> select<span class="token punctuation">)</span> <span class="token punctuation">{</span>
    <span class="token keyword">int</span> num<span class="token punctuation">;</span>
    <span class="token keyword">switch</span> <span class="token punctuation">(</span>select<span class="token punctuation">)</span> <span class="token punctuation">{</span>
        <span class="token keyword">case</span> <span class="token number">1</span><span class="token operator">:</span>
            num <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">case</span> <span class="token number">2</span><span class="token operator">:</span>
        <span class="token keyword">case</span> <span class="token number">3</span><span class="token operator">:</span>
            num <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span>
            <span class="token keyword">break</span><span class="token punctuation">;</span>
        <span class="token keyword">default</span><span class="token operator">:</span>
            num <span class="token operator">=</span> <span class="token number">40</span><span class="token punctuation">;</span>
    <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
213
</code></pre><div class="line-numbers" aria-hidden="true"><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div><div class="line-number"></div></div></div><p>通过 jclasslib 看一下 <code>switchTest()</code> 方法的字节码指令。</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/jvm/zijiema-zhiling-04e166ae-13c7-4025-804a-be88e2923a50.png" alt=""></p><p>case 2 的时候没有 break,所以 case 2 和 case 3 是连续的,用的是 tableswitch。如果等于 1,跳转到 28 行;如果等于 2 和 3,跳转到 34 行,如果是 default,跳转到 40 行。</p><p><strong>5)无条件跳转指令</strong></p><p>goto 指令接收两个字节的操作数,共同组成一个带符号的整数,用于指定指令的偏移量,指令执行的目的就是跳转到偏移量给定的位置处。</p><p>前面的例子里都出现了 goto 的身影,也很好理解。如果指令的偏移量特别大,超出了两个字节的范围,可以使用指令 goto_w,接收 4 个字节的操作数。</p><hr><p>更多指令,可以阅读下面这篇文章:</p><blockquote><p>https://segmentfault.com/a/1190000037628881</p></blockquote><blockquote><p>路漫漫其修远兮,吾将上下而求索</p></blockquote><p>想要走得更远,Java 字节码这块就必须得硬碰硬地吃透,希望二哥的这些分享可以帮助到大家~</p><p><img src="http://cdn.tobebetterjavaer.com/tobebetterjavaer/images/xingbiaogongzhonghao.png" alt=""></p></div><!----><footer class="page-meta"><div class="meta-item edit-link"><a href="https://github.com/itwanger/toBeBetterJavaer/edit/master/docs/jvm/zijiema-zhiling.md" rel="noopener noreferrer" target="_blank" aria-label="编辑此页" class="nav-link label"><!--[--><svg xmlns="http://www.w3.org/2000/svg" class="icon edit-icon" viewbox="0 0 1024 1024" fill="currentColor" aria-label="edit icon"><path d="M430.818 653.65a60.46 60.46 0 0 1-50.96-93.281l71.69-114.012 7.773-10.365L816.038 80.138A60.46 60.46 0 0 1 859.225 62a60.46 60.46 0 0 1 43.186 18.138l43.186 43.186a60.46 60.46 0 0 1 0 86.373L588.879 565.55l-8.637 8.637-117.466 68.234a60.46 60.46 0 0 1-31.958 11.229z"></path><path d="M728.802 962H252.891A190.883 190.883 0 0 1 62.008 771.98V296.934a190.883 190.883 0 0 1 190.883-192.61h267.754a60.46 60.46 0 0 1 0 120.92H252.891a69.962 69.962 0 0 0-69.098 69.099V771.98a69.962 69.962 0 0 0 69.098 69.098h475.911A69.962 69.962 0 0 0 797.9 771.98V503.363a60.46 60.46 0 1 1 120.922 0V771.98A190.883 190.883 0 0 1 728.802 962z"></path></svg><!--]-->编辑此页<span><svg class="external-link-icon" xmlns="http://www.w3.org/2000/svg" aria-hidden="true" focusable="false" x="0px" y="0px" viewbox="0 0 100 100" width="15" height="15"><path fill="currentColor" d="M18.8,85.1h56l0,0c2.2,0,4-1.8,4-4v-32h-8v28h-48v-48h28v-8h-32l0,0c-2.2,0-4,1.8-4,4v56C14.8,83.3,16.6,85.1,18.8,85.1z"></path><polygon fill="currentColor" points="45.7,48.7 51.3,54.3 77.2,28.5 77.2,37.2 85.2,37.2 85.2,14.9 62.8,14.9 62.8,22.9 71.5,22.9"></polygon></svg><span class="external-link-icon-sr-only">open in new window</span></span><!----></a></div><div class="meta-item update-time"><span class="label">上次编辑于: </span><span class="info">2022/5/14 上午7:14:28</span></div><div class="meta-item contributors"><span class="label">贡献者: </span><!--[--><!--[--><span class="contributor" title="email: www.qing_gee@163.com">itwanger</span>,<!--]--><!--[--><span class="contributor" title="email: www.qing_gee@163.com">沉默王二</span><!--]--><!--]--></div></footer><nav class="page-nav"><a href="/jvm/bytecode.html" class="nav-link prev" aria-label="从javap的角度轻松看懂字节码"><div class="hint"><span class="arrow left"></span>上一页</div><div class="link"><!---->从javap的角度轻松看懂字节码</div></a><a href="/jvm/how-jvm-run-zijiema-zhiling.html" class="nav-link next" aria-label="虚拟机是如何执行字节码指令的"><div class="hint">下一页<span class="arrow right"></span></div><div class="link">虚拟机是如何执行字节码指令的<!----></div></a></nav><!----><!----><!--]--></main><!--]--><footer class="footer-wrapper"><div class="footer"><a href="https://beian.miit.gov.cn/" target="_blank">豫ICP备2021038026号-1</a><img src="https://cdn.tobebetterjavaer.com/tobebetterjavaer/images/beian.png" height="15px" width="15px" /><a target="_blank" href="http://www.beian.gov.cn/portal/registerSystemInfo?recordcode=41030502000411"><span>豫公网安备 41030502000411号</span></a></div><div class="copyright">Copyright © 2022 沉默王二</div></footer><!--]--></div><!--]--><!----><!----><!--]--></div>
沉默王二's avatar
沉默王二 已提交
214
    <script type="module" src="/assets/app.615e41d8.js" defer></script>
沉默王二's avatar
沉默王二 已提交
215 216
  </body>
</html>