Files
www/public/blogs/java/jvm/JVM-字节码技术.html
zhuhjay 22e48d9558 build(www): 添加 Drone CI 流水线配置
- 新增 .drone.yml 文件用于定义 CI/CD 流程
- 配置了基于 Docker 的部署步骤
- 设置了工作区和卷映射以支持持久化数据
- 添加了构建准备阶段和 Docker 部署阶段
- 定义了环境变量和代理设置
- 配置了 artifacts 目录的处理逻辑
- 添加了 timezone 映射以确保时间同步
- 设置了 docker.sock 映射以支持 Docker in Docker
2025-11-01 13:36:00 +08:00

1323 lines
259 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters

This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>JVM之字节码技术 | ZhuHJay Blog</title>
<meta name="generator" content="VuePress 1.9.7">
<link rel="icon" href="/favicon.ico">
<meta name="description" content="my blog">
<meta name="viewport" content="width=device-width,initial-scale=1,user-scalable=no">
<link rel="preload" href="/assets/css/0.styles.93f9cd2e.css" as="style"><link rel="preload" href="/assets/js/app.049e1b5b.js" as="script"><link rel="preload" href="/assets/js/3.ff0e945d.js" as="script"><link rel="preload" href="/assets/js/1.1ced4111.js" as="script"><link rel="preload" href="/assets/js/20.c6871f96.js" as="script"><link rel="prefetch" href="/assets/js/10.21e2f029.js"><link rel="prefetch" href="/assets/js/11.18770288.js"><link rel="prefetch" href="/assets/js/12.588a1dd8.js"><link rel="prefetch" href="/assets/js/13.e66c15d0.js"><link rel="prefetch" href="/assets/js/14.141a3334.js"><link rel="prefetch" href="/assets/js/15.bd05cf61.js"><link rel="prefetch" href="/assets/js/16.346083d6.js"><link rel="prefetch" href="/assets/js/17.382f52f1.js"><link rel="prefetch" href="/assets/js/18.a55369bc.js"><link rel="prefetch" href="/assets/js/19.a2a264ee.js"><link rel="prefetch" href="/assets/js/21.2956f057.js"><link rel="prefetch" href="/assets/js/4.581595e5.js"><link rel="prefetch" href="/assets/js/5.55d6cfd7.js"><link rel="prefetch" href="/assets/js/6.9619dc5e.js"><link rel="prefetch" href="/assets/js/7.d2b7a379.js"><link rel="prefetch" href="/assets/js/8.9f502ca9.js"><link rel="prefetch" href="/assets/js/9.ec0bd674.js">
<link rel="stylesheet" href="/assets/css/0.styles.93f9cd2e.css">
</head>
<body>
<div id="app" data-server-rendered="true"><div class="theme-container" data-v-7dd95ae2><div data-v-7dd95ae2><div class="password-shadow password-wrapper-out" style="display:none;" data-v-59e6cb88 data-v-7dd95ae2 data-v-7dd95ae2><h3 class="title" data-v-59e6cb88>ZhuHJay Blog</h3> <p class="description" data-v-59e6cb88>my blog</p> <label id="box" class="inputBox" data-v-59e6cb88><input type="password" value="" data-v-59e6cb88> <span data-v-59e6cb88>Konck! Knock!</span> <button data-v-59e6cb88>OK</button></label> <div class="footer" data-v-59e6cb88><span data-v-59e6cb88><i class="iconfont reco-theme" data-v-59e6cb88></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-59e6cb88>vuePress-theme-reco</a></span> <span data-v-59e6cb88><i class="iconfont reco-copyright" data-v-59e6cb88></i> <a data-v-59e6cb88><span data-v-59e6cb88>ZhuHJay</span>
  
<span data-v-59e6cb88>2021 - </span>
2025
</a></span></div></div> <div class="hide" data-v-7dd95ae2><header class="navbar" data-v-7dd95ae2><div class="sidebar-button"><svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" role="img" viewBox="0 0 448 512" class="icon"><path fill="currentColor" d="M436 124H12c-6.627 0-12-5.373-12-12V80c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12zm0 160H12c-6.627 0-12-5.373-12-12v-32c0-6.627 5.373-12 12-12h424c6.627 0 12 5.373 12 12v32c0 6.627-5.373 12-12 12z"></path></svg></div> <a href="/" class="home-link router-link-active"><img src="/logo.png" alt="ZhuHJay Blog" class="logo"> <span class="site-name">ZhuHJay Blog</span></a> <div class="links"><div class="color-picker"><a class="color-button"><i class="iconfont reco-color"></i></a> <div class="color-picker-menu" style="display:none;"><div class="mode-options"><h4 class="title">Choose mode</h4> <ul class="color-mode-options"><li class="dark">dark</li><li class="auto active">auto</li><li class="light">light</li></ul></div></div></div> <div class="search-box"><i class="iconfont reco-search"></i> <input aria-label="Search" autocomplete="off" spellcheck="false" value=""> <!----></div> <nav class="nav-links can-hide"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont reco-home"></i>
首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-category"></i>
分类
</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/Java/" class="nav-link"><i class="undefined"></i>
Java
</a></li><li class="dropdown-item"><!----> <a href="/categories/NoSQL/" class="nav-link"><i class="undefined"></i>
NoSQL
</a></li><li class="dropdown-item"><!----> <a href="/categories/JavaScript/" class="nav-link"><i class="undefined"></i>
JavaScript
</a></li></ul></div></div><div class="nav-item"><a href="/tag/" class="nav-link"><i class="iconfont reco-tag"></i>
标签
</a></div><div class="nav-item"><a href="https://gitee.com/ZhuHJay" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-mayun"></i>
码云
<span><svg 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" class="icon outbound"><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="sr-only">(opens new window)</span></span></a></div> <!----></nav></div></header> <div class="sidebar-mask" data-v-7dd95ae2></div> <aside class="sidebar" data-v-7dd95ae2><div class="personal-info-wrapper" data-v-1fad0c41 data-v-7dd95ae2><img src="/avatar.png" alt="author-avatar" class="personal-img" data-v-1fad0c41> <h3 class="name" data-v-1fad0c41>
ZhuHJay
</h3> <div class="num" data-v-1fad0c41><div data-v-1fad0c41><h3 data-v-1fad0c41>11</h3> <h6 data-v-1fad0c41>文章</h6></div> <div data-v-1fad0c41><h3 data-v-1fad0c41>5</h3> <h6 data-v-1fad0c41>标签</h6></div></div> <ul class="social-links" data-v-1fad0c41></ul> <hr data-v-1fad0c41></div> <nav class="nav-links"><div class="nav-item"><a href="/" class="nav-link"><i class="iconfont reco-home"></i>
首页
</a></div><div class="nav-item"><div class="dropdown-wrapper"><a class="dropdown-title"><span class="title"><i class="iconfont reco-category"></i>
分类
</span> <span class="arrow right"></span></a> <ul class="nav-dropdown" style="display:none;"><li class="dropdown-item"><!----> <a href="/categories/Java/" class="nav-link"><i class="undefined"></i>
Java
</a></li><li class="dropdown-item"><!----> <a href="/categories/NoSQL/" class="nav-link"><i class="undefined"></i>
NoSQL
</a></li><li class="dropdown-item"><!----> <a href="/categories/JavaScript/" class="nav-link"><i class="undefined"></i>
JavaScript
</a></li></ul></div></div><div class="nav-item"><a href="/tag/" class="nav-link"><i class="iconfont reco-tag"></i>
标签
</a></div><div class="nav-item"><a href="https://gitee.com/ZhuHJay" target="_blank" rel="noopener noreferrer" class="nav-link external"><i class="iconfont reco-mayun"></i>
码云
<span><svg 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" class="icon outbound"><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="sr-only">(opens new window)</span></span></a></div> <!----></nav> <ul class="sidebar-links"><li><a href="/blogs/java/jvm/JVM-内存结构.html" class="sidebar-link">JVM之内存结构</a></li><li><a href="/blogs/java/jvm/JVM-垃圾回收.html" class="sidebar-link">JVM之垃圾回收</a></li><li><a href="/blogs/java/jvm/JVM-字节码技术.html" class="active sidebar-link">JVM之字节码技术</a></li><li><a href="/blogs/java/jvm/JVM-类加载.html" class="sidebar-link">JVM之类加载</a></li></ul> </aside> <div class="password-shadow password-wrapper-in" style="display:none;" data-v-59e6cb88 data-v-7dd95ae2><h3 class="title" data-v-59e6cb88>JVM之字节码技术</h3> <!----> <label id="box" class="inputBox" data-v-59e6cb88><input type="password" value="" data-v-59e6cb88> <span data-v-59e6cb88>Konck! Knock!</span> <button data-v-59e6cb88>OK</button></label> <div class="footer" data-v-59e6cb88><span data-v-59e6cb88><i class="iconfont reco-theme" data-v-59e6cb88></i> <a target="blank" href="https://vuepress-theme-reco.recoluan.com" data-v-59e6cb88>vuePress-theme-reco</a></span> <span data-v-59e6cb88><i class="iconfont reco-copyright" data-v-59e6cb88></i> <a data-v-59e6cb88><span data-v-59e6cb88>ZhuHJay</span>
  
<span data-v-59e6cb88>2021 - </span>
2025
</a></span></div></div> <div data-v-7dd95ae2><div data-v-7dd95ae2><main class="page"><section style="display:;"><div class="page-title"><h1 class="title">JVM之字节码技术</h1> <div data-v-8a445198><i class="iconfont reco-account" data-v-8a445198><span data-v-8a445198>ZhuHJay</span></i> <i class="iconfont reco-date" data-v-8a445198><span data-v-8a445198>2022/12/9</span></i> <!----> <i class="tags iconfont reco-tag" data-v-8a445198><span class="tag-item" data-v-8a445198>JVM</span></i></div></div> <div class="theme-reco-content content__default"><h2 id="_1-类文件结构"><a href="#_1-类文件结构" class="header-anchor">#</a> 1 类文件结构</h2> <p>一个简单的 HelloWorld.java 文件</p> <div class="language-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">HelloWorld</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 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;Hello World&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>将其执行 <code>javac -parameters -d . HelloWorld.java</code> 编译后的 HelloWorld.class 文件如下Notepad++使用十六进制进行查看)</p> <p><img src="/jvm/1670046032461.png" alt="1670046032461"></p> <p>根据 JVM 规范,类文件结构如下,这是在 JVM 运行中的所有字节码文件都需要遵循的</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>class-file {
u4 magic; //魔数
u2 minor_version; //小版本号
u2 major_version; //大版本号
u2 constant_pool_count; //常量池中常量个数+1
cp_info constant_pool[constant_pool_count-1]; //常量池
u2 access_flags; //类的访问控制符标识publicstaticfinalabstract等
u2 this_class; //该类的描述值为对常量池的引用引用的值为CONSTANT_Class_info
u2 super_class; //父类的描述值为对常量池的引用引用的值为CONSTANT_Class_info
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; //属性数包括InnerClassesEnclosingMethodSourceFile等
attribute_info attributes[attributes_count]; //属性表集合
}
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br></div></div><h3 id="_1-1-魔数"><a href="#_1-1-魔数" class="header-anchor">#</a> 1.1 魔数</h3> <p>0-3 字节表示它是否是【class】类型的文件</p> <p><img src="/jvm/1670046677428.png" alt="1670046677428"></p> <h3 id="_1-2-版本"><a href="#_1-2-版本" class="header-anchor">#</a> 1.2 版本</h3> <p>4-7 字节,表示类的版本 00 3452 表示是 Java 8</p> <p><img src="/jvm/1670046787159.png" alt="1670046787159"></p> <h3 id="_1-3-常量池"><a href="#_1-3-常量池" class="header-anchor">#</a> 1.3 常量池</h3> <p>8-9 字节表示常量池长度00 1f 31 表示常量池有 #1- #30 项,注意 #0 项不计入,也没有值,可以发现一个 Class 文件中最多具备 65535(2^16) 个常量,它包括了以下所有类型。</p> <p><img src="/jvm/1670047109146.png" alt="1670047109146"></p> <p>常量池类型映射表,目前为止 JVM 一共定义了 14 种类型的常量。</p> <table><thead><tr><th>Constant Type</th> <th>Value</th> <th>LengthByte</th> <th>Tip</th></tr></thead> <tbody><tr><td>CONSTANT_Class</td> <td>7</td> <td>2</td> <td>Class信息</td></tr> <tr><td>CONSTANT_Fieldref</td> <td>9</td> <td>4</td> <td>成员变量信息前2为 CONSTANT_Class后2为 CONSTANT_NameAndType</td></tr> <tr><td>CONSTANT_Methodref</td> <td>10</td> <td>4</td> <td>方法信息前2为 CONSTANT_Class后2为 CONSTANT_NameAndType</td></tr> <tr><td>CONSTANT_InterfaceMethodref</td> <td>11</td> <td>4</td> <td>接口方法信息前2为 CONSTANT_Class后2为 CONSTANT_NameAndType</td></tr> <tr><td>CONSTANT_String</td> <td>8</td> <td>2</td> <td>字符串常量名称</td></tr> <tr><td>CONSTANT_Integer</td> <td>3</td> <td>4</td> <td>int值</td></tr> <tr><td>CONSTANT_Float</td> <td>4</td> <td>4</td> <td>float值</td></tr> <tr><td>CONSTANT_Long</td> <td>5</td> <td>8</td> <td>long值</td></tr> <tr><td>CONSTANT_Double</td> <td>6</td> <td>8</td> <td>double值</td></tr> <tr><td>CONSTANT_NameAndType</td> <td>12</td> <td>4</td> <td>名称和类型信息前2为 命名信息后2为 类型信息</td></tr> <tr><td>CONSTANT_Utf8</td> <td>1</td> <td>2</td> <td>长度记录了该字符串的长度,通过该记录的长度来读取后续相应字节长度信息</td></tr> <tr><td>CONSTANT_MethodHandle</td> <td>15</td> <td>-</td> <td>表示方法句柄(后续遇到再补充)</td></tr> <tr><td>CONSTANT_MethodType</td> <td>16</td> <td>-</td> <td>表示方法类型(后续遇到再补充)</td></tr> <tr><td>CONSTANT_InvokeDynamic</td> <td>18</td> <td>-</td> <td>表示一个动态方法调用点(后续遇到再补充)</td></tr></tbody></table> <p>根据以上映射表来对其余字节码的分析</p> <p>常量池中 #1 项 0a10由映射表得知是一个 Method 信息,其通过后续的 00 066 和 00 1117 分别表示该方法的【所属类】引用常量池中 #6 项、【方法名】引用常量池中 #17 项。</p> <p><img src="/jvm/1670048081295.png" alt="1670048081295"></p> <p>常量池中 #2 项 099由映射表得知是一个 Field 信息,其通过后续的 00 1218 和 00 1319 分别表示该成员变量的【所属类】引用常量池中 #18 项、【成员变量名】引用常量池中 #19 项。</p> <p><img src="/jvm/1670048493839.png" alt="1670048493839"></p> <p>常量池中 #3 项 088由映射表得知是一个字符串常量名称其通过后续的 00 1420表示其引用了常量池中 #20 项。</p> <p><img src="/jvm/1670048714141.png" alt="1670048714141"></p> <p>依此类推进行其他常量池的解析,这里就不演示了,了解一个解析形式即可。</p> <p>以上分析结果的常量池大概就是使用反编译后的常量池结果,而且可以看到所有的字符串常量池中的信息一一对应</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>#1 = Methodref #6.#17 // java/lang/Object.&quot;&lt;init&gt;&quot;:()V
#2 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #20 // Hello World
#4 = Methodref #21.#22 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #23 // HelloWorld
#6 = Class #24 // java/lang/Object
#7 = Utf8 &lt;init&gt;
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 MethodParameters
#14 = Utf8 args
#15 = Utf8 SourceFile
#16 = Utf8 HelloWorld.java
#17 = NameAndType #7:#8 // &quot;&lt;init&gt;&quot;:()V
#18 = Class #25 // java/lang/System
#19 = NameAndType #26:#27 // out:Ljava/io/PrintStream;
#20 = Utf8 Hello World
#21 = Class #28 // java/io/PrintStream
#22 = NameAndType #29:#30 // println:(Ljava/lang/String;)V
#23 = Utf8 HelloWorld
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/System
#26 = Utf8 out
#27 = Utf8 Ljava/io/PrintStream;
#28 = Utf8 java/io/PrintStream
#29 = Utf8 println
#30 = Utf8 (Ljava/lang/String;)V
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br></div></div><h3 id="_1-4-访问标识与继承信息"><a href="#_1-4-访问标识与继承信息" class="header-anchor">#</a> 1.4 访问标识与继承信息</h3> <p>解析完常量池后的8的字节就是该部分的信息</p> <ul><li>2该class类型和访问修饰符Flag</li> <li>2通过常量池找到本类全限定名</li> <li>2通过常量池找到父类全限定名</li> <li>2表示接口数量</li></ul> <table><thead><tr><th>Flag Name</th> <th>Value</th> <th>Interpretation</th></tr></thead> <tbody><tr><td>ACC_PUBLIC</td> <td>0x0001</td> <td>public 访问权限</td></tr> <tr><td>ACC_FINAL</td> <td>0x0010</td> <td>final 修饰符</td></tr> <tr><td>ACC_SUPER</td> <td>0x0020</td> <td>Treat <code>superclass</code> methods specially when invoked by the invokespecial instruction. 父类调用方式</td></tr> <tr><td>ACC_INTERFACE</td> <td>0x0200</td> <td>interface 类型</td></tr> <tr><td>ACC_ABSTRACT</td> <td>0x0400</td> <td>abstract 类型</td></tr> <tr><td>ACC_SYNTHETIC</td> <td>0x1000</td> <td>通过合成/生成的代码,没有源代码</td></tr> <tr><td>ACC_ANNOTATION</td> <td>0x2000</td> <td>annotation 类型</td></tr> <tr><td>ACC_ENUM</td> <td>0x4000</td> <td>enum 类型</td></tr></tbody></table> <h3 id="_1-5-field-信息"><a href="#_1-5-field-信息" class="header-anchor">#</a> 1.5 Field 信息</h3> <p>解析完以上的信息的后续2字节表示成员变量的数量此案例文件并没有成员变量</p> <table><thead><tr><th>FieldType</th> <th>Type</th> <th>Interpretation</th></tr></thead> <tbody><tr><td>B</td> <td>byte</td> <td></td></tr> <tr><td>C</td> <td>char</td> <td></td></tr> <tr><td>D</td> <td>double</td> <td></td></tr> <tr><td>F</td> <td>float</td> <td></td></tr> <tr><td>I</td> <td>int</td> <td></td></tr> <tr><td>J</td> <td>long</td> <td></td></tr> <tr><td>L<code>ClassName</code>;</td> <td>reference</td> <td>引用类型</td></tr> <tr><td>S</td> <td>short</td> <td></td></tr> <tr><td>Z</td> <td>boolean</td> <td></td></tr> <tr><td>[</td> <td>reference</td> <td>一维数组</td></tr></tbody></table> <h3 id="_1-6-method-信息"><a href="#_1-6-method-信息" class="header-anchor">#</a> 1.6 Method 信息</h3> <p>解析完以上的信息的后续2字节表示方法的数量</p> <p>一个方法由 访问修饰符,名称,参数描述,方法属性数量,方法属性组成</p> <p>就是解析为以下反编译文件(使用十六进制分析过程过于庞大)</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>{
public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello World
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
MethodParameters:
Name Flags
args
}
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><h3 id="_1-7-附加属性"><a href="#_1-7-附加属性" class="header-anchor">#</a> 1.7 附加属性</h3> <p>解析为以下反编译文件的内容</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>SourceFile: &quot;HelloWorld.java&quot;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>参考文献 https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html</p> <h2 id="_2-字节码指令"><a href="#_2-字节码指令" class="header-anchor">#</a> 2 字节码指令</h2> <h3 id="_2-1-入门"><a href="#_2-1-入门" class="header-anchor">#</a> 2.1 入门</h3> <p>分析方法中的字节码指令信息</p> <p>构造方法对应的字节码信息如下图,对应的反编译信息如下文本块所示</p> <p><img src="/jvm/1670054933674.png" alt="1670054933674"></p> <div class="language- line-numbers-mode"><pre class="language-text"><code> public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
4: return
LineNumberTable:
line 1: 0
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>有以下对应关系</p> <ul><li>2a =&gt; aload_0加载 slot 0 的局部变量,即 this做为下面的 invokespecial 构造方法调用的参数</li> <li>b7 =&gt; invokespecial预备调用构造方法哪个方法呢</li> <li>00 01引用常量池中 #1 项,即【 Method java/lang/Object.&quot;&quot;😦)V 】</li> <li>b1表示返回</li></ul> <p>main方法对应的字节码信息如下图对应的反编译信息如下文本块所示</p> <p><img src="/jvm/1670055197971.png" alt="1670055197971"></p> <div class="language- line-numbers-mode"><pre class="language-text"><code> public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello World
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
MethodParameters:
Name Flags
args
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>有以下对应关系</p> <ul><li>b2 =&gt; getstatic用来加载静态变量哪个静态变量呢</li> <li>00 02引用常量池中 #2 项即【Field java/lang/System.out:Ljava/io/PrintStream;】</li> <li>12 =&gt; ldc加载参数哪个参数呢</li> <li>03引用常量池中 #3 项,即 【String Hello World】</li> <li>b6 =&gt; invokevirtual预备调用成员方法哪个方法呢</li> <li>00 04引用常量池中 #4 项即【Method java/io/PrintStream.println:(Ljava/lang/String;)V】</li> <li>b1表示返回</li></ul> <p>请参考 <a href="https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-6.html#jvms-6.5<span><svg 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" class="icon outbound"><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="sr-only">(opens new window)</span></span></a></p> <p><img src="/jvm/1670055453251.png" alt="1670055453251"></p> <h3 id="_2-2-javap-工具"><a href="#_2-2-javap-工具" class="header-anchor">#</a> 2.2 javap 工具</h3> <p>自己分析类文件结构太麻烦了Oracle 提供了 javap 工具来反编译 class 文件</p> <p>使用命令 <code>javap -v HelloWorld.class</code>,查看完整的反编译信息</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Classfile /G:/Idea_workspace/JVM/src/main/java/HelloWorld.class
Last modified 2022-12-3; size 462 bytes
MD5 checksum f882f9f216fff39f1b95dd6b16b209a7
Compiled from &quot;HelloWorld.java&quot;
public class HelloWorld
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #6.#17 // java/lang/Object.&quot;&lt;init&gt;&quot;:()V
#2 = Fieldref #18.#19 // java/lang/System.out:Ljava/io/PrintStream;
#3 = String #20 // Hello World
#4 = Methodref #21.#22 // java/io/PrintStream.println:(Ljava/lang/String;)V
#5 = Class #23 // HelloWorld
#6 = Class #24 // java/lang/Object
#7 = Utf8 &lt;init&gt;
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 MethodParameters
#14 = Utf8 args
#15 = Utf8 SourceFile
#16 = Utf8 HelloWorld.java
#17 = NameAndType #7:#8 // &quot;&lt;init&gt;&quot;:()V
#18 = Class #25 // java/lang/System
#19 = NameAndType #26:#27 // out:Ljava/io/PrintStream;
#20 = Utf8 Hello World
#21 = Class #28 // java/io/PrintStream
#22 = NameAndType #29:#30 // println:(Ljava/lang/String;)V
#23 = Utf8 HelloWorld
#24 = Utf8 java/lang/Object
#25 = Utf8 java/lang/System
#26 = Utf8 out
#27 = Utf8 Ljava/io/PrintStream;
#28 = Utf8 java/io/PrintStream
#29 = Utf8 println
#30 = Utf8 (Ljava/lang/String;)V
{
public HelloWorld();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
4: return
LineNumberTable:
line 1: 0
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=1, args_size=1
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: ldc #3 // String Hello World
5: invokevirtual #4 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
8: return
LineNumberTable:
line 3: 0
line 4: 8
MethodParameters:
Name Flags
args
}
SourceFile: &quot;HelloWorld.java&quot;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br></div></div><h3 id="_2-3-图解方法执行流程"><a href="#_2-3-图解方法执行流程" class="header-anchor">#</a> 2.3 图解方法执行流程</h3> <h4 id="_1-原始-java-代码"><a href="#_1-原始-java-代码" class="header-anchor">#</a> 1) 原始 Java 代码</h4> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_1</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 keyword">int</span> a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token class-name">Short</span><span class="token punctuation">.</span><span class="token constant">MAX_VALUE</span> <span class="token operator">+</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> c <span class="token operator">=</span> a <span class="token operator">+</span> b<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>c<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><h4 id="_2-编译后的字节码文件"><a href="#_2-编译后的字节码文件" class="header-anchor">#</a> 2) 编译后的字节码文件</h4> <p>使用命令 <code>javap -v Demo3_1.class</code> 进行反编译,查看字节码</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Classfile /G:/Idea_workspace/JVM/target/classes/com/zhuhjay/demo3/Demo3_1.class
Last modified 2022-12-3; size 619 bytes
MD5 checksum 2f036be3ec6ee9204c53f83b17dacc1f
Compiled from &quot;Demo3_1.java&quot;
public class com.zhuhjay.demo3.Demo3_1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #7.#25 // java/lang/Object.&quot;&lt;init&gt;&quot;:()V
#2 = Class #26 // java/lang/Short
#3 = Integer 32768
#4 = Fieldref #27.#28 // java/lang/System.out:Ljava/io/PrintStream;
#5 = Methodref #29.#30 // java/io/PrintStream.println:(I)V
#6 = Class #31 // com/zhuhjay/demo3/Demo3_1
#7 = Class #32 // java/lang/Object
#8 = Utf8 &lt;init&gt;
#9 = Utf8 ()V
#10 = Utf8 Code
#11 = Utf8 LineNumberTable
#12 = Utf8 LocalVariableTable
#13 = Utf8 this
#14 = Utf8 Lcom/zhuhjay/demo3/Demo3_1;
#15 = Utf8 main
#16 = Utf8 ([Ljava/lang/String;)V
#17 = Utf8 args
#18 = Utf8 [Ljava/lang/String;
#19 = Utf8 a
#20 = Utf8 I
#21 = Utf8 b
#22 = Utf8 c
#23 = Utf8 SourceFile
#24 = Utf8 Demo3_1.java
#25 = NameAndType #8:#9 // &quot;&lt;init&gt;&quot;:()V
#26 = Utf8 java/lang/Short
#27 = Class #33 // java/lang/System
#28 = NameAndType #34:#35 // out:Ljava/io/PrintStream;
#29 = Class #36 // java/io/PrintStream
#30 = NameAndType #37:#38 // println:(I)V
#31 = Utf8 com/zhuhjay/demo3/Demo3_1
#32 = Utf8 java/lang/Object
#33 = Utf8 java/lang/System
#34 = Utf8 out
#35 = Utf8 Ljava/io/PrintStream;
#36 = Utf8 java/io/PrintStream
#37 = Utf8 println
#38 = Utf8 (I)V
{
public com.zhuhjay.demo3.Demo3_1();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object.&quot;&lt;init&gt;&quot;:()V
4: return
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/zhuhjay/demo3/Demo3_1;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: bipush 10
2: istore_1
3: ldc #3 // int 32768
5: istore_2
6: iload_1
7: iload_2
8: iadd
9: istore_3
10: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
13: iload_3
14: invokevirtual #5 // Method java/io/PrintStream.println:(I)V
17: return
LineNumberTable:
line 9: 0
line 10: 3
line 11: 6
line 12: 10
line 13: 17
LocalVariableTable:
Start Length Slot Name Signature
0 18 0 args [Ljava/lang/String;
3 15 1 a I
6 12 2 b I
10 8 3 c I
}
SourceFile: &quot;Demo3_1.java&quot;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br><span class="line-number">36</span><br><span class="line-number">37</span><br><span class="line-number">38</span><br><span class="line-number">39</span><br><span class="line-number">40</span><br><span class="line-number">41</span><br><span class="line-number">42</span><br><span class="line-number">43</span><br><span class="line-number">44</span><br><span class="line-number">45</span><br><span class="line-number">46</span><br><span class="line-number">47</span><br><span class="line-number">48</span><br><span class="line-number">49</span><br><span class="line-number">50</span><br><span class="line-number">51</span><br><span class="line-number">52</span><br><span class="line-number">53</span><br><span class="line-number">54</span><br><span class="line-number">55</span><br><span class="line-number">56</span><br><span class="line-number">57</span><br><span class="line-number">58</span><br><span class="line-number">59</span><br><span class="line-number">60</span><br><span class="line-number">61</span><br><span class="line-number">62</span><br><span class="line-number">63</span><br><span class="line-number">64</span><br><span class="line-number">65</span><br><span class="line-number">66</span><br><span class="line-number">67</span><br><span class="line-number">68</span><br><span class="line-number">69</span><br><span class="line-number">70</span><br><span class="line-number">71</span><br><span class="line-number">72</span><br><span class="line-number">73</span><br><span class="line-number">74</span><br><span class="line-number">75</span><br><span class="line-number">76</span><br><span class="line-number">77</span><br><span class="line-number">78</span><br><span class="line-number">79</span><br><span class="line-number">80</span><br><span class="line-number">81</span><br><span class="line-number">82</span><br><span class="line-number">83</span><br><span class="line-number">84</span><br><span class="line-number">85</span><br><span class="line-number">86</span><br><span class="line-number">87</span><br><span class="line-number">88</span><br><span class="line-number">89</span><br><span class="line-number">90</span><br><span class="line-number">91</span><br><span class="line-number">92</span><br><span class="line-number">93</span><br></div></div><h4 id="_3-常量池载入运行时常量池"><a href="#_3-常量池载入运行时常量池" class="header-anchor">#</a> 3) 常量池载入运行时常量池</h4> <p>JVM 通过类加载器将以上字节码数据读入,将常量池数据存储到运行时常量池(属于方法区的一部分)中</p> <ul><li>#3 这个数据的来源是 <code>Short.MAX_VALUE + 1</code>java源码中比较小的数值并不会存储在常量池中而是与方法的字节码指令存储在一起一旦超出了 <code>Short.MAX_VALUE(32767)</code> 就会存储到常量池中。</li></ul> <img src="/jvm/1670221697470.png" alt="1670221697470" style="zoom:50%;"> <h4 id="_4-方法字节码载入方法区"><a href="#_4-方法字节码载入方法区" class="header-anchor">#</a> 4) 方法字节码载入方法区</h4> <img src="/jvm/1670222538332.png" alt="1670222538332" style="zoom:50%;"> <h4 id="_5-main-线程开始运行-分配栈帧内存"><a href="#_5-main-线程开始运行-分配栈帧内存" class="header-anchor">#</a> 5) main 线程开始运行,分配栈帧内存</h4> <p>会根据以下信息来进行栈帧分配操作数栈深度为2局部变量表长度为4</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>stack=2, locals=4, args_size=1
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><img src="/jvm/1670222781062.png" alt="1670222781062" style="zoom:50%;"> <h4 id="_6-执行引擎开始执行字节码"><a href="#_6-执行引擎开始执行字节码" class="header-anchor">#</a> 6) 执行引擎开始执行字节码</h4> <p><strong>bipush 10</strong></p> <ul><li>将一个 byte 压入操作数栈(其长度会补齐 4 个字节),类似的指令还有
<ul><li>sipush 将一个 short 压入操作数栈(其长度会补齐 4 个字节)</li> <li>ldc 将一个 int 压入操作数栈</li> <li>ldc2_w 将一个 long 压入操作数栈(分两次压入,因为 long 是 8 个字节)</li></ul></li> <li>这里小的数字都是和字节码指令存在一起,超过 short 范围的数字存入了常量池</li></ul> <img src="/jvm/1670223128743.png" alt="1670223128743" style="zoom:50%;"> <p><strong>istore_1</strong></p> <ul><li>将操作数栈顶数据弹出,存入局部变量表的 slot 1</li></ul> <img src="/jvm/1670223335018.png" alt="1670223335018" style="zoom:50%;"> <img src="/jvm/1670223376535.png" alt="1670223376535" style="zoom:50%;"> <p>以上操作代表源代码的 <code>int a = 10;</code> 这个赋值操作</p> <p><strong>ldc #3</strong></p> <ul><li>从常量池加载 #3 数据到操作数栈</li> <li><strong>注意</strong> <code>Short.MAX_VALUE</code> 是 32767所以 <code>32768 = Short.MAX_VALUE + 1</code> 实际是在编译期间计算好的(常量折叠优化)</li></ul> <img src="/jvm/1670223577473.png" alt="1670223577473" style="zoom:50%;"> <p><strong>istore_2</strong></p> <ul><li>将操作数栈顶数据弹出,存入局部变量表的 slot 2</li></ul> <img src="/jvm/1670223846251.png" alt="1670223846251" style="zoom:50%;"> <p>以上操作代表源代码的 <code>int b = Short.MAX_VALUE + 1;</code> 这个赋值操作</p> <p><strong>iload_1</strong></p> <ul><li>将局部变量表中的 slot 1 数据读取复制到操作数栈中</li></ul> <img src="/jvm/1670223953960.png" alt="1670223953960" style="zoom:50%;"> <p><strong>iload_2</strong></p> <ul><li>将局部变量表中的 slot 2 数据读取复制到操作数栈中</li></ul> <img src="/jvm/1670224060014.png" alt="1670224060014" style="zoom:50%;"> <p><strong>iadd</strong></p> <ul><li>将操作数栈中的数据进行相加的操作</li></ul> <img src="/jvm/1670224223804.png" alt="1670224223804" style="zoom:50%;"> <img src="/jvm/1670224265031.png" alt="1670224265031" style="zoom:50%;"> <p><strong>istore_3</strong></p> <ul><li>将操作数栈顶数据弹出,存入局部变量表的 slot 3</li></ul> <img src="/jvm/1670224443009.png" alt="1670224443009" style="zoom:50%;"> <p>以上操作代表源代码的 <code>int c = a + b;</code> 这个操作</p> <p><strong>getstatic #4</strong></p> <ul><li>从常量池中获取成员变量 #4 找到堆中的对象,将该对象的引用放入到操作数栈中</li></ul> <img src="/jvm/1670224527319.png" alt="1670224527319" style="zoom:50%;"> <p><strong>iload_3</strong></p> <ul><li>将局部变量表中的 slot 3 数据读取复制到操作数栈中</li></ul> <img src="/jvm/1670224818125.png" alt="1670224818125" style="zoom:50%;"> <p><strong>invokevirtual #5</strong></p> <ul><li>找到常量池 #5 项</li> <li>定位到方法区 <code>java/io/PrintStream.println:(I)V</code> 方法</li> <li>生成新的栈帧(分配 locals、stack等每执行一个方法都会有新的栈帧</li> <li>传递参数,执行新栈帧中的字节码</li></ul> <img src="/jvm/1670225026514.png" alt="1670225026514" style="zoom:50%;"> <ul><li>执行完毕,弹出栈帧</li> <li>清除 main 操作数栈内容</li></ul> <img src="/jvm/1670225112947.png" alt="1670225112947" style="zoom:50%;"> <p><strong>return</strong></p> <ul><li><p>完成 main 方法调用,弹出 main 栈帧</p></li> <li><p>程序结束</p></li></ul> <h3 id="_2-4-练习-分析i"><a href="#_2-4-练习-分析i" class="header-anchor">#</a> 2.4 练习 - 分析i++</h3> <p>从字节码角度分析 i++ 相关题目</p> <p>源码</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_2</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 keyword">int</span> a <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> b <span class="token operator">=</span> a<span class="token operator">++</span> <span class="token operator">+</span> <span class="token operator">++</span>a <span class="token operator">+</span> a<span class="token operator">--</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>a<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>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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>字节码</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
0: bipush 10
2: istore_1
3: iload_1
4: iinc 1, 1
7: iinc 1, 1
10: iload_1
11: iadd
12: iload_1
13: iinc 1, -1
16: iadd
17: istore_2
18: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
21: iload_1
22: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
25: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
28: iload_2
29: invokevirtual #3 // Method java/io/PrintStream.println:(I)V
32: return
LineNumberTable:
line 9: 0
line 10: 3
line 11: 18
line 12: 25
line 13: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 args [Ljava/lang/String;
3 30 1 a I
18 15 2 b I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>分析:</p> <ul><li><p><strong>注意</strong> iinc 指令是直接在局部变量 slot 上进行运算</p></li> <li><p>a++ 和 ++a 的区别是 先执行 iload 还是 先执行 iinc</p></li> <li><p>将一个 byte 数值类型 10 压入到操作数栈中</p></li></ul> <img src="/jvm/1670225735794.png" alt="1670225735794" style="zoom:50%;"> <ul><li>将操作数栈顶数据弹出,存入局部变量表的 slot 1此时完成了代码 <code>int a = 10</code> 的操作</li></ul> <img src="/jvm/1670225834483.png" alt="1670225834483" style="zoom:50%;"> <ul><li>将局部变量表中的 slot 1 的数据读取复制到操作数栈中,<code>a++</code> 执行顺序是先读取复制,再进行自增的操作</li></ul> <img src="/jvm/1670225887463.png" alt="1670225887463" style="zoom:50%;"> <ul><li>对局部变量表中的 slot 1 进行长度为 1 的自增,是直接在局部变量表中直接进行操作,而不是在操作数栈中进行</li> <li>此时局部变量表中的 a 和 操作数栈中的数值不是一个相等的值</li></ul> <img src="/jvm/1670225973371.png" alt="1670225973371" style="zoom:50%;"> <ul><li>现将进行 <code>++a</code> 的运算,会先对局部变量表中的 slot 1 中的数值进行自增,而后才将该结果读取复制到操作数栈中</li></ul> <img src="/jvm/1670226003812.png" alt="1670226003812" style="zoom:50%;"> <ul><li>读取局部变量表中 slot 1 的数值到操作数栈中</li></ul> <img src="/jvm/1670226078219.png" alt="1670226078219" style="zoom:50%;"> <ul><li>计算完 <code>a++</code><code>++a</code> 过后,操作数栈中已经存在两个数据了,所以会先对操作数栈中的数据进行相加的操作</li></ul> <img src="/jvm/1670226107200.png" alt="1670226107200" style="zoom:50%;"> <ul><li>现将进行 <code>a--</code> 的运算,先将局部变量表中 slot 1 读取复制到操作数栈中</li></ul> <img src="/jvm/1670226176345.png" alt="1670226176345" style="zoom:50%;"> <ul><li>将局部变量表中的 slot 1 进行自减操作</li></ul> <img src="/jvm/1670226329153.png" alt="1670226329153" style="zoom:50%;"> <ul><li>将操作数栈中的数据进行相加,到此为止 <code>a++ + ++a + a--</code> 的运算结束</li></ul> <img src="/jvm/1670226379924.png" alt="1670226379924" style="zoom:50%;"> <ul><li>最后将操作数栈中的数据存放到局部变量表中对应的位置上去</li></ul> <img src="/jvm/1670226433126.png" alt="1670226433126" style="zoom:50%;"> <h3 id="_2-5-条件判断指令"><a href="#_2-5-条件判断指令" class="header-anchor">#</a> 2.5 条件判断指令</h3> <table><thead><tr><th>指令</th> <th>助记符</th> <th>含义</th></tr></thead> <tbody><tr><td>0x99</td> <td>ifeq</td> <td>判断是否 == 0</td></tr> <tr><td>0x9a</td> <td>ifne</td> <td>判断是否 != 0</td></tr> <tr><td>0x9b</td> <td>iflt</td> <td>判断是否 &lt; 0</td></tr> <tr><td>0x9c</td> <td>ifge</td> <td>判断是否 &gt;= 0</td></tr> <tr><td>0x9d</td> <td>ifgt</td> <td>判断是否 &gt; 0</td></tr> <tr><td>0x9e</td> <td>ifle</td> <td>判断是否 &lt;= 0</td></tr> <tr><td>0x9f</td> <td>if_icmpeq</td> <td>两个int是否 ==</td></tr> <tr><td>0xa0</td> <td>if_icmpne</td> <td>两个int是否 !=</td></tr> <tr><td>0xa1</td> <td>if_icmplt</td> <td>两个int是否 &lt;</td></tr> <tr><td>0xa2</td> <td>if_icmpge</td> <td>两个int是否 &gt;=</td></tr> <tr><td>0xa3</td> <td>if_icmpgt</td> <td>两个int是否 &gt;</td></tr> <tr><td>0xa4</td> <td>if_icmple</td> <td>两个int是否 &lt;=</td></tr> <tr><td>0xa5</td> <td>if_acmpeq</td> <td>两个引用是否 ==</td></tr> <tr><td>0xa6</td> <td>if_acmpne</td> <td>两个引用是否 !=</td></tr> <tr><td>0xc6</td> <td>ifnull</td> <td>判断是否 == null</td></tr> <tr><td>0xc7</td> <td>ifnonnull</td> <td>判断是否 != null</td></tr></tbody></table> <ul><li><p>几点说明:</p> <ul><li>byteshortchar 都会按 int 比较,因为操作数栈都是 4 字节</li> <li>goto 用来进行跳转到指定行号的字节码</li></ul></li> <li><p>源码</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_3</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 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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div></li> <li><p>字节码</p> <ul><li>比较小的数是通过 <code>iconst</code> 指令</li> <li><code>ifne</code> 指令判断操作数栈中的两个数值是否不相等,如果不相等,则跳转到序号为 <code>12</code> 的指令,否则继续往下执行</li> <li>该程序 if 判断有两个执行路径
<ul><li><code>3 -&gt; 6 -&gt; 8 -&gt; 9 -&gt; 15</code>:执行到 <code>goto</code> 指令后会跳转到对应的序号指令继续执行</li> <li><code>3 -&gt; 12 -&gt; 14 0&gt; 15</code>:通过了 if 判断跳转到对应的序号指令继续执行</li></ul></li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>0: iconst_0
1: istore_1
2: iload_1
3: ifne 12
6: bipush 10
8: istore_1
9: goto 15
12: bipush 20
14: istore_1
15: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div></li></ul> <blockquote><p>Tip:</p> <p> 以上比较指令中没有 longfloatdouble 的比较,那么它们要比较怎么办?</p> <p>参考 <a href="https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.lcmp" target="_blank" rel="noopener noreferrer">https://docs.oracle.com/javase/specs/jvms/se7/html/jvms-6.html#jvms-6.5.lcmp<span><svg 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" class="icon outbound"><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="sr-only">(opens new window)</span></span></a></p></blockquote> <h3 id="_2-6-循环控制指令"><a href="#_2-6-循环控制指令" class="header-anchor">#</a> 2.6 循环控制指令</h3> <p>其实循环控制还是前面介绍的那些指令,例如 while 循环:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_4</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 keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>a <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
a<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>字节码,通过指令 <code>if_icmpge</code> 判断是否大于等于,是则跳出当前 while 循环,否则继续自增</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>再比如 do while 循环:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_5</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 keyword">int</span> a <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">do</span> <span class="token punctuation">{</span>
a<span class="token operator">++</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">while</span> <span class="token punctuation">(</span>a <span class="token operator">&lt;</span> <span class="token number">10</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>字节码,与 while 循环不同的地方就是do while 会先进行自增操作,之后才进行判断</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>0: iconst_0
1: istore_1
2: iinc 1, 1
5: iload_1
6: bipush 10
8: if_icmplt 2
11: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>最后再看看 for 循环:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_6</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 keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">;</span> i<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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>字节码,会发现 for 循环编译后的字节码和 while 循环是<strong>一模一样</strong></p> <div class="language- line-numbers-mode"><pre class="language-text"><code>0: iconst_0
1: istore_1
2: iload_1
3: bipush 10
5: if_icmpge 14
8: iinc 1, 1
11: goto 2
14: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><h3 id="_2-7-练习-判断结果"><a href="#_2-7-练习-判断结果" class="header-anchor">#</a> 2.7 练习 - 判断结果</h3> <p>请从字节码角度分析,下列代码运行的结果:</p> <ul><li>问题出现在 <code>x = x++</code>,这部分代码的字节码运行流程如下
<ul><li>从局部变量表中先获取 x 的数值并复制到操作数栈中,此时:<code>slot x:0; stack x:0</code></li> <li>对局部变量表中的 x 所在的槽位数值自增1此时<code>slot x:1; stack x:0</code></li> <li>将操作数栈中的值赋值给局部变量表中 x ,此时:<code>slot x:0; stack null</code></li> <li>一直重复以上操作x 的结果永远都是 0</li></ul></li> <li>若将以上问题代码改为 <code>x = ++x</code>,将不会出现以上的问题</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_7</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 keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">while</span> <span class="token punctuation">(</span>i <span class="token operator">&lt;</span> <span class="token number">10</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
x <span class="token operator">=</span> x<span class="token operator">++</span><span class="token punctuation">;</span>
i<span class="token operator">++</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>x<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 0</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h3 id="_2-8-构造方法"><a href="#_2-8-构造方法" class="header-anchor">#</a> 2.8 构造方法</h3> <h4 id="_1-clinit-v"><a href="#_1-clinit-v" class="header-anchor">#</a> 1) <code>&lt;clinit&gt;()V</code></h4> <div class="language-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">Demo3_8</span> <span class="token punctuation">{</span>
<span class="token keyword">static</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">static</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>编译器会按从上至下的顺序,收集所有 static 静态代码块和静态成员赋值的代码,合并为一个特殊的方法<code>&lt;clinit&gt;()V</code> ,该方法会在类加载的初始化阶段被调用</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=1, locals=0, args_size=0
0: bipush 10
2: putstatic #2 // Field i:I
5: bipush 20
7: putstatic #2 // Field i:I
10: bipush 30
12: putstatic #2 // Field i:I
15: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><h4 id="_2-init-v"><a href="#_2-init-v" class="header-anchor">#</a> 2) <code>&lt;init&gt;()V</code></h4> <div class="language-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">Demo3_9</span> <span class="token punctuation">{</span>
<span class="token keyword">private</span> <span class="token class-name">String</span> a <span class="token operator">=</span> <span class="token string">&quot;s1&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">{</span>
b <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">int</span> b <span class="token operator">=</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token punctuation">{</span>
a <span class="token operator">=</span> <span class="token string">&quot;s2&quot;</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</span> <span class="token class-name">Demo3_9</span><span class="token punctuation">(</span><span class="token class-name">String</span> a<span class="token punctuation">,</span> <span class="token keyword">int</span> b<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>a <span class="token operator">=</span> a<span class="token punctuation">;</span>
<span class="token keyword">this</span><span class="token punctuation">.</span>b <span class="token operator">=</span> b<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 class-name">Demo3_9</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Demo3_9</span><span class="token punctuation">(</span><span class="token string">&quot;s3&quot;</span><span class="token punctuation">,</span> <span class="token number">30</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>d<span class="token punctuation">.</span>a<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// s3</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>d<span class="token punctuation">.</span>b<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 30</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br></div></div><p>编译器会按从上至下的顺序,收集所有 {} 代码块和成员变量赋值的代码,形成新的构造方法,但原始构造方法内的代码总是在最后</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>public com.zhuhjay.demo3.Demo3_9(java.lang.String, int);
descriptor: (Ljava/lang/String;I)V
flags: ACC_PUBLIC
Code:
stack=2, locals=3, args_size=3
0: aload_0
1: invokespecial #1 // 调用父类的构造方法(Object)
4: aload_0
5: ldc #2 // &lt;- &quot;s1&quot;
7: putfield #3 // -&gt; this.a
10: aload_0
11: bipush 20 // &lt;- 20
13: putfield #4 // -&gt; this.b
16: aload_0
17: bipush 10 // &lt;- 10
19: putfield #4 // -&gt; this.b
22: aload_0
23: ldc #5 // &lt;- &quot;s2&quot;
25: putfield #3 // -&gt; this.a
28: aload_0
29: aload_1 // &lt;- &quot;s3&quot;
30: putfield #3 // -&gt; this.a
33: aload_0
34: iload_2 // &lt;- 30
35: putfield #4 // -&gt; this.b
38: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br></div></div><h3 id="_2-9-方法调用"><a href="#_2-9-方法调用" class="header-anchor">#</a> 2.9 方法调用</h3> <p>看一下几种不同的方法调用对应的字节码指令</p> <div class="language-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">Demo3_10</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Demo3_10</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">void</span> <span class="token function">test1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token keyword">final</span> <span class="token keyword">void</span> <span class="token function">test2</span><span class="token punctuation">(</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">void</span> <span class="token function">test3</span><span class="token punctuation">(</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">test4</span><span class="token punctuation">(</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 class-name">Demo3_10</span> d <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Demo3_10</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
d<span class="token punctuation">.</span><span class="token function">test1</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
d<span class="token punctuation">.</span><span class="token function">test2</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
d<span class="token punctuation">.</span><span class="token function">test3</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
d<span class="token punctuation">.</span><span class="token function">test4</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Demo3_10</span><span class="token punctuation">.</span><span class="token function">test4</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>字节码</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>0: new #2 // class com/zhuhjay/demo3/Demo3_10
3: dup
4: invokespecial #3 // Method &quot;&lt;init&gt;&quot;:()V
7: astore_1
8: aload_1
9: invokespecial #4 // Method test1:()V
12: aload_1
13: invokespecial #5 // Method test2:()V
16: aload_1
17: invokevirtual #6 // Method test3:()V
20: aload_1
21: pop
22: invokestatic #7 // Method test4:()V
25: invokestatic #7 // Method test4:()V
28: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><ul><li><p><code>new</code> 是创建【对象】,给对象分配堆内存,执行成功会将【对象引用】压入操作数栈</p></li> <li><p><code>dup</code> 是赋值操作数栈栈顶的内容,本例即为【对象引用】,为什么需要两份引用呢,一个是要配合 <code>invokespecial</code> 调用该对象的构造方法 <code>&quot;&lt;init&gt;&quot;:()V</code> (会消耗掉栈顶一个引用),另一个要配合 <code>astore_1</code> 赋值给局部变量</p></li> <li><p>最终方法final私有方法private构造方法都是由 <code>invokespecial</code> 指令来调用,属于 静态绑定</p></li> <li><p>普通成员方法是由 <code>invokevirtual</code> 调用,属于动态绑定,即支持多态成员方法与静态方法调用的另一个区别是,执行方法前是否需要【对象引用】</p></li> <li><p>比较有意思的是 <code>d.test4();</code> 是通过【对象引用】调用一个静态方法,可以看到在调用 <code>invokestatic</code> 之前执行了 <code>pop</code> 指令,把【对象引用】从操作数栈弹掉了</p></li> <li><p>还有一个执行 <code>invokespecial</code> 的情况是通过 <code>super</code> 调用父类方法</p></li></ul> <h3 id="_2-10-多态的原理"><a href="#_2-10-多态的原理" class="header-anchor">#</a> 2.10 多态的原理</h3> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">package</span> <span class="token namespace">com<span class="token punctuation">.</span>zhuhjay<span class="token punctuation">.</span>demo3</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">class</span> <span class="token class-name">Demo3_11</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">test</span><span class="token punctuation">(</span><span class="token class-name">Animal</span> animal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
animal<span class="token punctuation">.</span><span class="token function">eat</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>animal<span class="token punctuation">.</span><span class="token function">toString</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>
<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 keyword">throws</span> <span class="token class-name">IOException</span> <span class="token punctuation">{</span>
<span class="token function">test</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Dog</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token function">test</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">Cat</span><span class="token punctuation">(</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>in<span class="token punctuation">.</span><span class="token function">read</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>
<span class="token keyword">abstract</span> <span class="token keyword">class</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">abstract</span> <span class="token keyword">void</span> <span class="token function">eat</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">String</span> <span class="token function">toString</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 string">&quot;我是&quot;</span> <span class="token operator">+</span> <span class="token keyword">this</span><span class="token punctuation">.</span><span class="token function">getClass</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">getSimpleName</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>
<span class="token keyword">class</span> <span class="token class-name">Dog</span> <span class="token keyword">extends</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">eat</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;啃骨头&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">Cat</span> <span class="token keyword">extends</span> <span class="token class-name">Animal</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">eat</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;吃鱼&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><h4 id="_1-运行代码"><a href="#_1-运行代码" class="header-anchor">#</a> 1) 运行代码</h4> <p><strong>注意</strong>:运行代码前需要添加虚拟机参数 <code>-XX:-UseCompressedOops -XX:-UseCompressedClassPointers</code>,禁止指针压缩,省去了地址换算</p> <p>停在 <code>System.in.read()</code> 方法上,这时运行 <code>jps</code> 获取进程 id</p> <h4 id="_2-运行-hsdb-工具"><a href="#_2-运行-hsdb-工具" class="header-anchor">#</a> 2) 运行 HSDB 工具</h4> <p>进入 JDK 目录,执行命令 <code>java -cp ./lib/sa-jdi.jar sun.jvm.hotspot.HSDB</code></p> <p>进入图形界面后 Attach 到对应的 进程id效果如下</p> <img src="/jvm/1670338229940.png" alt="1670338229940" style="zoom:50%;"> <h4 id="_3-查找内存中的对象"><a href="#_3-查找内存中的对象" class="header-anchor">#</a> 3) 查找内存中的对象</h4> <p>打开 <code>Tools -&gt; Find Object By Query</code> 工具</p> <p>输入 <code>select d from com.zhuhjay.demo3.Dog d</code> 并执行,语法同 SQL 一般,查询结果就是在内存中存在的 Dog 对象内存地址。</p> <p><img src="/jvm/1670338644448.png" alt="1670338644448"></p> <h4 id="_4-查看对象内存结构"><a href="#_4-查看对象内存结构" class="header-anchor">#</a> 4) 查看对象内存结构</h4> <p>点击超链接可以看到对象的内存结构,此对象没有任何属性,因此只有对象头的 16 字节,前 8 字节是 MarkWord后 8 字节就是对象的 Class 指针</p> <p>但目前看不到它的实际地址,在底层是 C++ 的数据结构,可以看到类中的一些数据,子类父类等等,虚引用表长度 <code>_vtable_len</code></p> <img src="/jvm/1670338857348.png" alt="1670338857348" style="zoom:80%;"> <h4 id="_5-查看对象的内存地址"><a href="#_5-查看对象的内存地址" class="header-anchor">#</a> 5) 查看对象的内存地址</h4> <p>通过 <code>Windows -&gt; Console</code> 进入命令行模式,执行 <code>mem 0x0000023338896cd0 2</code></p> <ul><li><code>mem</code> 有两个参数,参数 1 是对象地址,参数 2 是查看 2 行(即 16 字节)</li></ul> <p>在结果中的第二行即为 Class 的内存地址</p> <img src="/jvm/1670339471963.png" alt="1670339471963" style="zoom:80%;"> <h4 id="_6-查看类的-vtable"><a href="#_6-查看类的-vtable" class="header-anchor">#</a> 6) 查看类的 vtable</h4> <ul><li><p>方法一:<code>Alt+R</code> 进入 <code>Inspector</code> 工具,输入刚刚查询到的 Class 内存地址</p> <img src="/jvm/1670339740477.png" alt="1670339740477" style="zoom:80%;"></li> <li><p>方法二:打开 <code>Tools -&gt; Class Browser</code> 输入 Dog 查找,也一样可以找到该 Class 对应的内存地址,然后使用方法一进行查询</p> <img src="/jvm/1670339913417.png" alt="1670339913417" style="zoom:67%;"></li></ul> <p>无论通过哪种方法,都可以找到 <code>Dog Class</code><code>vtable</code> 长度为 6意思就是 <code>Dog</code> 类有 6 个虚方法多态相关的finalstatic 不会列入)</p> <p>那么这 6 个方法都是谁呢?从 Class 的起始地址开始算,偏移 <code>0x1b8</code> 就是 <code>vtable</code> 的起始地址,进行计算得到:</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>0x00000233675d3c90
0x1b8 +
---------------------
0x00000233675d3e48
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br></div></div><p>然后使用 <code>Windows -&gt; Console</code> 工具执行命令,就能够得到这 6 个虚方法的入口地址了</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>mem 0x00000233675d3e48 6
0x00000233675d3e48: 0x00000233671d1b10
0x00000233675d3e50: 0x00000233671d15e8
0x00000233675d3e58: 0x00000233675d3758
0x00000233675d3e60: 0x00000233671d1540
0x00000233675d3e68: 0x00000233671d1678
0x00000233675d3e70: 0x00000233675d3c38
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><h4 id="_7-验证方法地址"><a href="#_7-验证方法地址" class="header-anchor">#</a> 7) 验证方法地址</h4> <p>通过 <code>Tools -&gt; Class Browser</code> 查看每个类的方法定义,比较可知每一个地址都对上了查询到的所有虚方法地址</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>Dog - public void eat() @0x00000233675d3c38;
Animal - public java.lang.String toString() @0x00000233675d3758;
Object - protected void finalize() @0x00000233671d1b10;
Object - public boolean equals(java.lang.Object) @0x00000233671d15e8;
Object - public native int hashCode() @0x00000233671d1540;
Object - protected native java.lang.Object clone() @0x00000233671d1678;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h4 id="_8-小结"><a href="#_8-小结" class="header-anchor">#</a> 8) 小结</h4> <p>当执行 <code>invokevirtual</code> 指令时</p> <ol><li>先通过栈帧中的对象引用找到对象</li> <li>分析对象头,找到对象的实际 Class</li> <li>Class 结构中有 <code>vtable</code>,它在类加载的链接阶段就已经根据方法的重写规则生成好了</li> <li>查表得到方法的具体地址</li> <li>执行方法的字节码</li></ol> <h3 id="_2-11-异常处理"><a href="#_2-11-异常处理" class="header-anchor">#</a> 2.11 异常处理</h3> <h4 id="_1-try-catch"><a href="#_1-try-catch" class="header-anchor">#</a> 1) try-catch</h4> <div class="language-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">Demo3_12_1</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 keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
i <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">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>部分字节码如下</p> <ul><li>可以看到多出来一个 <code>Exception table</code> 的结构,<code>[from, to)</code> 是前闭后开的检测范围,一旦这个范围内的字节码执行出现异常,则通过 <code>type</code> 匹配异常类型,如果一致,进入 <code>target</code> 所指示行号</li> <li>8 行的字节码指令 <code>astore_2</code> 是将异常对象引用存入局部变量表的 <code>slot 2</code> 位置,记录异常对象信息</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: iconst_0
1: istore_1
2: bipush 10
4: istore_1
5: goto 12
8: astore_2
9: bipush 20
11: istore_1
12: return
Exception table:
from to target type
2 5 8 Class java/lang/Exception
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
9 3 2 e Ljava/lang/Exception;
0 13 0 args [Ljava/lang/String;
2 11 1 i I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><h4 id="_2-多个-single-catch-块的情况"><a href="#_2-多个-single-catch-块的情况" class="header-anchor">#</a> 2) 多个 single-catch 块的情况</h4> <div class="language-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">Demo3_12_2</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 keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
i <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">catch</span> <span class="token punctuation">(</span><span class="token class-name">ArithmeticException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">NullPointerException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">30</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br></div></div><p>部分字节码信息如下</p> <ul><li>因为异常出现时,只能进入 <code>Exception table</code> 中一个分支,所以局部变量表 <code>Slot 2</code> 位置被共用</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: iconst_0
1: istore_1
2: bipush 10
4: istore_1
5: goto 26
8: astore_2
9: bipush 20
11: istore_1
12: goto 26
15: astore_2
16: bipush 30
18: istore_1
19: goto 26
22: astore_2
23: bipush 40
25: istore_1
26: return
Exception table:
from to target type
2 5 8 Class java/lang/ArithmeticException
2 5 15 Class java/lang/NullPointerException
2 5 22 Class java/lang/Exception
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
9 3 2 e Ljava/lang/ArithmeticException;
16 3 2 e Ljava/lang/NullPointerException;
23 3 2 e Ljava/lang/Exception;
0 27 0 args [Ljava/lang/String;
2 25 1 i I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><h4 id="_3-multi-catch-的情况"><a href="#_3-multi-catch-的情况" class="header-anchor">#</a> 3) multi-catch 的情况</h4> <div class="language-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">Demo3_12_3</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 keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
i <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">catch</span> <span class="token punctuation">(</span><span class="token class-name">ArithmeticException</span> <span class="token operator">|</span> <span class="token class-name">NullPointerException</span> <span class="token operator">|</span> <span class="token class-name">NumberFormatException</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>部分字节码如下</p> <ul><li>将异常入口进行一次收集,局部变量表 <code>Slot 2</code> 只收集一个,并且是这些异常的父类型</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=1
0: iconst_0
1: istore_1
2: bipush 10
4: istore_1
5: goto 12
8: astore_2
9: bipush 20
11: istore_1
12: return
Exception table:
from to target type
2 5 8 Class java/lang/ArithmeticException
2 5 8 Class java/lang/NullPointerException
2 5 8 Class java/lang/NumberFormatException
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
9 3 2 e Ljava/lang/RuntimeException;
0 13 0 args [Ljava/lang/String;
2 11 1 i I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br></div></div><h4 id="_4-finally"><a href="#_4-finally" class="header-anchor">#</a> 4) finally</h4> <div class="language-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">Demo3_12_4</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 keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
i <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">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">20</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">30</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>部分字节码如下</p> <ul><li>可以看到 finally 中的代码被<strong>复制</strong>了 3 份,分别放入 try 流程catch 流程以及 catch 剩余的异常类型流程</li> <li>JVM 会自动捕捉其没有被 catch 块捕获的异常,且如果真的捕获到了这部分异常,同样也会执行 finally 中的代码,并且使用 <code>athrow</code> 指令将异常向外抛出</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=4, args_size=1
0: iconst_0
1: istore_1 // 0 -&gt; i
2: bipush 10 // try ----------------------
4: istore_1 // 10 -&gt; i |
5: bipush 30 // finally |
7: istore_1 // 30 -&gt; i |
8: goto 27 // return -------------------
11: astore_2 // catch Exception -&gt; e -----
12: bipush 20 // |
14: istore_1 // 20 -&gt; i |
15: bipush 30 // finally |
17: istore_1 // 30 -&gt; i |
18: goto 27 // return -------------------
21: astore_3 // catch any -&gt; slot 3 ------
22: bipush 30 // finally |
24: istore_1 // 30 -&gt; i |
25: aload_3 // &lt;- slot 3 |
26: athrow // throw --------------------
27: return
Exception table:
from to target type
2 5 11 Class java/lang/Exception
2 5 21 any
11 15 21 any
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
12 3 2 e Ljava/lang/Exception;
0 28 0 args [Ljava/lang/String;
2 26 1 i I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br><span class="line-number">35</span><br></div></div><h3 id="_2-12-练习-finally-面试题"><a href="#_2-12-练习-finally-面试题" class="header-anchor">#</a> 2.12 练习 - finally 面试题</h3> <h4 id="_1-finally-出现了-return"><a href="#_1-finally-出现了-return" class="header-anchor">#</a> 1) finally 出现了 return</h4> <div class="language-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">Demo3_13_1</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 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 function">test</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>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">20</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>部分字节码如下</p> <ul><li>由于 finally 中的 <code>ireturn</code> 被插入了所有可能的流程,因此返回结果肯定以 finally 的为准</li> <li>至于字节码中第 2 行,似乎没啥用,且留个伏笔,看下个例子</li> <li>跟上例中的 finally 相比,发现没有 <code>athrow</code> 了,这告诉我们:<strong>如果在 finally 中出现了 return会吞掉异常</strong></li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static int test();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=2, args_size=0
0: bipush 10 // &lt;- 10 放入栈顶
2: istore_0 // 10 -&gt; slot 0 (从栈顶移除)
3: bipush 20 // &lt;- 20 放入栈顶 (finally代码)
5: ireturn // 返回栈顶 int(20)
6: astore_1 // catch any -&gt; slot 1
7: bipush 20 // &lt;- 20 放入栈顶 (finally代码)
9: ireturn // 返回栈顶 int(20)
Exception table:
from to target type
0 3 6 any
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>若将案例代码改为如下</p> <ul><li>制造一个异常 <code>int i = 1/0</code>,运行后发现不会有异常出现,且结果与上个例子相同</li></ul> <div class="language-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">Demo3_13_1</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 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 function">test</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>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">1</span><span class="token operator">/</span><span class="token number">0</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">10</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> <span class="token number">20</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><h4 id="_2-finally-对返回值影响"><a href="#_2-finally-对返回值影响" class="header-anchor">#</a> 2) finally 对返回值影响</h4> <div class="language-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">Demo3_13_2</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 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 function">test</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>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">int</span> <span class="token function">test</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">0</span><span class="token punctuation">;</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
<span class="token keyword">return</span> i<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
i <span class="token operator">=</span> <span class="token number">100</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br></div></div><p>部分字节码如下</p> <ul><li>finally 中不带 return就可以正常的捕获异常了从字节码中 <code>athrow</code> 看出)</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static int test();
descriptor: ()I
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=3, args_size=0
0: iconst_0 // &lt;- 0 放入栈顶
1: istore_0 // 0 -&gt; i
2: iload_0 // &lt;- i(0)
3: istore_1 // 0 -&gt; slot 1暂存至 slot 1目的是为了固定返回值
4: bipush 100 // &lt;- 100 放入栈顶
6: istore_0 // 100 -&gt; i
7: iload_1 // &lt;- i(0),读取返回值放置栈顶
8: ireturn // 返回栈顶 i(0)
9: astore_2 // catch 部分
10: bipush 100
12: istore_0
13: aload_2
14: athrow
Exception table:
from to target type
2 4 9 any
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
2 13 0 i I
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br></div></div><h3 id="_2-13-synchronized"><a href="#_2-13-synchronized" class="header-anchor">#</a> 2.13 synchronized</h3> <div class="language-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">Demo3_14</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 class-name">Object</span> lock <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Object</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">synchronized</span> <span class="token punctuation">(</span>lock<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;ok&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>部分字节码如下</p> <ul><li>JVM 会自动给 <code>synchronized</code> 代码块中的代码进行异常捕获,当捕获到异常或者 <code>synchronized</code> 代码块运行结束时,都会进行锁的释放,并且锁的释放过程也会进行异常的捕获,确保锁的释放</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=4, args_size=1
0: new #2 // new Object
3: dup // 复制一份,用来初始化
4: invokespecial #1 // invokespecial -&gt; &lt;init&gt;:()V
7: astore_1 // 将 Object 引用 -&gt; lock
8: aload_1 // &lt;- lock (synchronized开始)
9: dup // 复制一份,一个用于加锁指令一个用于解锁指令
10: astore_2 // 将 Object 引用 -&gt; slot 2
11: monitorenter // 加锁指令
12: getstatic #3 // &lt;- System.out
15: ldc #4 // &lt;- &quot;ok&quot;
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
20: aload_2 // &lt;- slot 2(解锁指令使用的 lock引用)
21: monitorexit // 解锁指令
22: goto 30
25: astore_3 // catch any -&gt; slot 3
26: aload_2 // &lt;- slot 2(解锁指令使用的 lock引用)
27: monitorexit // 解锁指令
28: aload_3
29: athrow // 异常抛出
30: return
Exception table:
from to target type
12 22 25 any
25 28 25 any
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
0 31 0 args [Ljava/lang/String;
8 23 1 lock Ljava/lang/Object;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><blockquote><p><strong>注意</strong>:方法级别的 <code>synchronized</code> 不会在字节码指令中有所体现</p></blockquote> <h2 id="_3-编译器处理"><a href="#_3-编译器处理" class="header-anchor">#</a> 3 编译器处理</h2> <p>所谓的 <code>语法糖</code> ,其实就是指 java 编译器把 <code>*.java</code> 源码编译为 <code>*.class</code> 字节码的过程中,自动生成和转换的一些代码,主要是为了减轻程序员的负担,算是 java 编译器给我们的一个额外福利</p> <p>注意,以下代码的分析,借助了 <code>javap</code> 工具idea 的反编译功能idea 插件 <code>jclasslib</code> 等工具。另外, 编译器转换的结果直接就是 class 字节码,只是为了便于阅读,给出了几乎等价 的 java 源码方式,并不是编译器还会转换出中间的 java 源码,切记。</p> <h3 id="_3-1-默认构造器"><a href="#_3-1-默认构造器" class="header-anchor">#</a> 3.1 默认构造器</h3> <div class="language-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">Candy1</span> <span class="token punctuation">{</span> <span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><p>编译成class后的代码</p> <div class="language-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">Candy1</span> <span class="token punctuation">{</span>
<span class="token comment">// 这个无参构造是编译器帮助我们加上的</span>
<span class="token keyword">public</span> <span class="token class-name">Candy1</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 即调用父类 Object 的无参构造方法,即调用 java/lang/Object.&quot;&lt;init&gt;&quot;:()V</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><h3 id="_3-2-自动拆装箱"><a href="#_3-2-自动拆装箱" class="header-anchor">#</a> 3.2 自动拆装箱</h3> <p>这个特性是 <code>JDK 5</code> 开始加入的:<code>代码一</code></p> <div class="language-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">Candy2</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 class-name">Integer</span> x <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y <span class="token operator">=</span> x<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>这段代码在 <code>JDK 5</code> 之前是无法编译通过的,必须改写为:<code>代码二</code></p> <div class="language-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">Candy2</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 class-name">Integer</span> x <span class="token operator">=</span> <span class="token class-name">Integer</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">int</span> y <span class="token operator">=</span> x<span class="token punctuation">.</span><span class="token function">intValue</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br></div></div><p>显然之前版本的代码太麻烦了,需要在基本类型和包装类型直接来回转换(尤其是集合类中操作的都是包装类型),因此这些转换的事情在 <code>JDK 5</code> 以后都由编译器在编译阶段完成,即 <code>代码一</code> 都会在编译阶段被转为 <code>代码二</code></p> <h3 id="_3-3-泛型集合取值"><a href="#_3-3-泛型集合取值" class="header-anchor">#</a> 3.3 泛型集合取值</h3> <p>泛型也是在 <code>JDK 5</code> 开始加入的特性,但 java 在编译泛型代码后会执行 <code>泛型擦除</code> 的动作,即泛型信息在编译为字节码之后就丢失了,实际的类型都当做了 <code>Object</code> 类型来处理:</p> <div class="language-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">Candy3</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 class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">ArrayList</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token punctuation">&gt;</span></span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
list<span class="token punctuation">.</span><span class="token function">add</span><span class="token punctuation">(</span><span class="token number">10</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 实际调用的是 List.add(Object e)</span>
<span class="token class-name">Integer</span> x <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 实际调用的是 Object obj = List.get(int index);</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><p>所以在取值时,编译器真正生成的字节码中,还要额外做一个类型转换的操作:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 需要将 Object 转为 Integer</span>
<span class="token class-name">Integer</span> x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">)</span>list<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>如果前面的 x 变量类型修改为 int 基本类型那么最终生成的字节码是:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 需要将 Object 转为 Integer, 并执行拆箱操作</span>
<span class="token keyword">int</span> x <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">)</span>list<span class="token punctuation">.</span><span class="token function">get</span><span class="token punctuation">(</span><span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">.</span><span class="token function">intValue</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><p>擦除的是字节码上的泛型信息,可以看到 <code>LocalVariableTypeTable</code> 仍然保留了方法参数泛型的信息</p> <ul><li>JVM 将代码 <code>Integer x = list.get(0);</code> 通过 <code>Object obj = List.get(int index);</code> 方式获取出来后,会使用 <code>checkcast</code> 指令对照泛型信息表来进行类型的转换</li></ul> <div class="language- line-numbers-mode"><pre class="language-text"><code>public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=2, locals=3, args_size=1
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: bipush 10
11: invokestatic #4 // Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;
14: invokeinterface #5, 2 // InterfaceMethod java/util/List.add:(Ljava/lang/Object;)Z
19: pop
20: aload_1
21: iconst_0
22: invokeinterface #6, 2 // InterfaceMethod java/util/List.get:(I)Ljava/lang/Object;
27: checkcast #7 // class java/lang/Integer
30: astore_2
31: return
LineNumberTable: ...
LocalVariableTable:
Start Length Slot Name Signature
0 32 0 args [Ljava/lang/String;
8 24 1 list Ljava/util/List;
31 1 2 x Ljava/lang/Integer;
LocalVariableTypeTable:
Start Length Slot Name Signature
8 24 1 list Ljava/util/List&lt;Ljava/lang/Integer;&gt;;
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br></div></div><p>使用反射,仍然能够获得这些信息(只能获取到方法参数上和返回值的泛型信息):</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token class-name">Set</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> <span class="token function">test</span><span class="token punctuation">(</span><span class="token class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">String</span><span class="token punctuation">&gt;</span></span> list<span class="token punctuation">,</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">&gt;</span></span> map<span class="token punctuation">)</span> <span class="token punctuation">{</span><span class="token keyword">return</span> <span class="token keyword">null</span><span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br></div></div><div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token class-name">Method</span> test <span class="token operator">=</span> <span class="token class-name">Candy3</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getMethod</span><span class="token punctuation">(</span><span class="token string">&quot;test&quot;</span><span class="token punctuation">,</span> <span class="token class-name">List</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> <span class="token class-name">Map</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Type</span><span class="token punctuation">[</span><span class="token punctuation">]</span> types <span class="token operator">=</span> test<span class="token punctuation">.</span><span class="token function">getGenericParameterTypes</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Type</span> type <span class="token operator">:</span> types<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>type <span class="token keyword">instanceof</span> <span class="token class-name">ParameterizedType</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">ParameterizedType</span> parameterizedType <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">ParameterizedType</span><span class="token punctuation">)</span> type<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;原始类型 - &quot;</span> <span class="token operator">+</span> parameterizedType<span class="token punctuation">.</span><span class="token function">getRawType</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Type</span><span class="token punctuation">[</span><span class="token punctuation">]</span> arguments <span class="token operator">=</span> parameterizedType<span class="token punctuation">.</span><span class="token function">getActualTypeArguments</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> arguments<span class="token punctuation">.</span>length<span class="token punctuation">;</span> i<span class="token operator">++</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">printf</span><span class="token punctuation">(</span><span class="token string">&quot;\t泛型参数[%d] - %s\n&quot;</span><span class="token punctuation">,</span> i<span class="token punctuation">,</span> arguments<span class="token punctuation">[</span>i<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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>输出</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>原始类型 - interface java.util.List
泛型参数[0] - class java.lang.String
原始类型 - interface java.util.Map
泛型参数[0] - class java.lang.Integer
泛型参数[1] - class java.lang.Object
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h3 id="_3-4-可变参数"><a href="#_3-4-可变参数" class="header-anchor">#</a> 3.4 可变参数</h3> <p>可变参数也是 <code>JDK 5</code> 开始加入的新特性: 例如:</p> <div class="language-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">Candy4</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">foo</span><span class="token punctuation">(</span><span class="token class-name">String</span><span class="token punctuation">.</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 class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> array <span class="token operator">=</span> args<span class="token punctuation">;</span> <span class="token comment">// 直接赋值</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>array<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">foo</span><span class="token punctuation">(</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>可变参数 <code>String... args</code> 其实是一个 <code>String[] args</code> ,从代码中的赋值语句中就可以看出来。 同样 java 编译器会在编译期间将上述代码变换为:</p> <div class="language-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">Candy4</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">foo</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 class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> array <span class="token operator">=</span> args<span class="token punctuation">;</span> <span class="token comment">// 直接赋值</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>array<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">foo</span><span class="token punctuation">(</span><span class="token keyword">new</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">,</span> <span class="token string">&quot;world&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><blockquote><p><strong>注意</strong> 如果调用了 <code>foo()</code> 则等价代码为 <code>foo(new String[]{})</code> ,创建了一个空的数组,而不会传递 <code>null</code> 进去</p></blockquote> <h3 id="_3-5-foreach-循环"><a href="#_3-5-foreach-循环" class="header-anchor">#</a> 3.5 foreach 循环</h3> <p>仍是 <code>JDK 5</code> 开始引入的语法糖,数组的循环:</p> <div class="language-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">Candy5_1</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 keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> array <span class="token operator">=</span> <span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token keyword">int</span> e <span class="token operator">:</span> array<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>e<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>字节码信息如下</p> <ul><li>数组赋初值的简化写法也是语法糖</li> <li>数组的 <code>foreach</code> 会被编译成 <code>fori</code></li></ul> <div class="language-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">Candy5_1</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Candy5_1</span><span class="token punctuation">(</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 keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> array <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token keyword">for</span><span class="token punctuation">(</span><span class="token keyword">int</span> i <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span> i <span class="token operator">&lt;</span> array<span class="token punctuation">.</span>length<span class="token punctuation">;</span> <span class="token operator">++</span>i<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> e <span class="token operator">=</span> array<span class="token punctuation">[</span>i<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>e<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>而集合的循环:</p> <div class="language-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">Candy5_2</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 class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span> i <span class="token operator">:</span> list<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>i<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br></div></div><p>实际被编译器转换为对迭代器的调用:</p> <ul><li>使用迭代器进行遍历(只有实现了 <code>Iterable</code> 接口的集合才能使用 <code>foreach</code> 语法糖 </li></ul> <div class="language-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">Candy5_2</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Candy5_2</span><span class="token punctuation">(</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 class-name">List</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Integer</span><span class="token punctuation">&gt;</span></span> list <span class="token operator">=</span> <span class="token class-name">Arrays</span><span class="token punctuation">.</span><span class="token function">asList</span><span class="token punctuation">(</span><span class="token number">1</span><span class="token punctuation">,</span> <span class="token number">2</span><span class="token punctuation">,</span> <span class="token number">3</span><span class="token punctuation">,</span> <span class="token number">4</span><span class="token punctuation">,</span> <span class="token number">5</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Iterator</span> iter <span class="token operator">=</span> list<span class="token punctuation">.</span><span class="token function">iterator</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">while</span><span class="token punctuation">(</span>iter<span class="token punctuation">.</span><span class="token function">hasNext</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token class-name">Integer</span> e <span class="token operator">=</span> <span class="token punctuation">(</span><span class="token class-name">Integer</span><span class="token punctuation">)</span>iter<span class="token punctuation">.</span><span class="token function">next</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>e<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><blockquote><p><strong>注意</strong> foreach 循环写法,能够配合数组,以及所有实现了 <code>Iterable</code> 接口的集合类一起使用,其 中 <code>Iterable</code> 用来获取集合的迭代器( <code>Iterator</code> </p></blockquote> <h3 id="_3-6-switch-字符串"><a href="#_3-6-switch-字符串" class="header-anchor">#</a> 3.6 switch 字符串</h3> <p><code>JDK 7</code> 开始switch 可以作用于字符串和枚举类,这个功能其实也是语法糖,例如:</p> <div class="language-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">Candy6_1</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">choose</span><span class="token punctuation">(</span><span class="token class-name">String</span> str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token string">&quot;hello&quot;</span><span class="token operator">:</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;h&quot;</span><span class="token punctuation">)</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 string">&quot;world&quot;</span><span class="token operator">:</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;w&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><blockquote><p><strong>注意</strong> switch 配合 String 和枚举使用时,变量不能为 <code>null</code>,原因分析完语法糖转换后的代码应当自然清楚</p></blockquote> <p>会被编译器转换为:</p> <div class="language-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">Candy6_1</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Candy6_1</span><span class="token punctuation">(</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">choose</span><span class="token punctuation">(</span><span class="token class-name">String</span> str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">byte</span> x <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">switch</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token number">99162322</span><span class="token operator">:</span> <span class="token comment">// hello 的 hashCode</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token string">&quot;hello&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
x <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</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">113318802</span><span class="token operator">:</span> <span class="token comment">// world 的 hashCode</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token string">&quot;world&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
x <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">switch</span><span class="token punctuation">(</span>x<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</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;h&quot;</span><span class="token punctuation">)</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">1</span><span class="token operator">:</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;w&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br></div></div><p>可以看到,执行了两遍 switch第一遍是根据字符串的 <code>hashCode</code><code>equals</code> 将字符串的转换为相应 byte 类型,第二遍才是利用 byte 执行进行比较。</p> <p>为什么第一遍时必须既比较 <code>hashCode</code>,又利用 <code>equals</code> 比较呢?<code>hashCode</code> 是为了提高效率,减少可能的比较;而 <code>equals</code> 是为了防止 <code>hashCode</code> 冲突,例如 <code>BM</code><code>C.</code> 这两个字符串的 <code>hashCode</code> 值都是 2123 ,如果有如下代码:</p> <div class="language-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">Candy6_1</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">choose</span><span class="token punctuation">(</span><span class="token class-name">String</span> str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token string">&quot;BM&quot;</span><span class="token operator">:</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;h&quot;</span><span class="token punctuation">)</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 string">&quot;C.&quot;</span><span class="token operator">:</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;w&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br></div></div><p>编译结果为</p> <div class="language-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">Candy6_1</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Candy6_1</span><span class="token punctuation">(</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">choose</span><span class="token punctuation">(</span><span class="token class-name">String</span> str<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">byte</span> var2 <span class="token operator">=</span> <span class="token operator">-</span><span class="token number">1</span><span class="token punctuation">;</span>
<span class="token keyword">switch</span><span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">hashCode</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token number">2123</span><span class="token operator">:</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token string">&quot;C.&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
var2 <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token keyword">if</span> <span class="token punctuation">(</span>str<span class="token punctuation">.</span><span class="token function">equals</span><span class="token punctuation">(</span><span class="token string">&quot;BM&quot;</span><span class="token punctuation">)</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
var2 <span class="token operator">=</span> <span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">default</span><span class="token operator">:</span>
<span class="token keyword">switch</span><span class="token punctuation">(</span>var2<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token number">0</span><span class="token operator">:</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;h&quot;</span><span class="token punctuation">)</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">1</span><span class="token operator">:</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;w&quot;</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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><h3 id="_3-7-switch-枚举"><a href="#_3-7-switch-枚举" class="header-anchor">#</a> 3.7 switch 枚举</h3> <p>switch 枚举的例子,原始代码</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">Sex</span> <span class="token punctuation">{</span>
<span class="token constant">MALE</span><span class="token punctuation">,</span> <span class="token constant">FEMALE</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><div class="language-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">Candy7</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">foo</span><span class="token punctuation">(</span><span class="token class-name">Sex</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>sex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">case</span> <span class="token constant">MALE</span><span class="token operator">:</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;&quot;</span><span class="token punctuation">)</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 constant">FEMALE</span><span class="token operator">:</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;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span><span class="token keyword">break</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>编译后会生成以下文件</p> <ul><li>其中 <code>Candy7$1.class</code> 文件是用来映射枚举类 Sex 的一个静态内部类</li></ul> <p><img src="/jvm/1670415162524.png" alt="1670415162524"></p> <p>字节码如下</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>static final int[] $SwitchMap$com$zhuhjay$jit$Sex;
descriptor: [I
flags: ACC_STATIC, ACC_FINAL, ACC_SYNTHETIC
static {};
descriptor: ()V
flags: ACC_STATIC
Code:
stack=3, locals=1, args_size=0
0: invokestatic #1 // Method com/zhuhjay/jit/Sex.values:()[Lcom/zhuhjay/jit/Sex;
3: arraylength
4: newarray int
6: putstatic #2 // Field $SwitchMap$com$zhuhjay$jit$Sex:[I
9: getstatic #2 // Field $SwitchMap$com$zhuhjay$jit$Sex:[I
12: getstatic #3 // Field com/zhuhjay/jit/Sex.MALE:Lcom/zhuhjay/jit/Sex;
15: invokevirtual #4 // Method com/zhuhjay/jit/Sex.ordinal:()I
18: iconst_1
19: iastore
20: goto 24
23: astore_0
24: getstatic #2 // Field $SwitchMap$com$zhuhjay$jit$Sex:[I
27: getstatic #6 // Field com/zhuhjay/jit/Sex.FEMALE:Lcom/zhuhjay/jit/Sex;
30: invokevirtual #4 // Method com/zhuhjay/jit/Sex.ordinal:()I
33: iconst_2
34: iastore
35: goto 39
38: astore_0
39: return
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br></div></div><p>也就是会生成以下代码</p> <div class="language-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">Candy7</span> <span class="token punctuation">{</span>
<span class="token comment">/**
* 定义一个合成类(仅 jvm 使用,对我们不可见)
* 用来映射枚举的 ordinal 与数组元素的关系
* 枚举的 ordinal 表示枚举对象的序号,从 0 开始
* 即 MALE 的 ordinal()=0FEMALE 的 ordinal()=1
*/</span>
<span class="token keyword">static</span> <span class="token keyword">class</span> <span class="token class-name">Candy7</span>$<span class="token number">1</span> <span class="token punctuation">{</span>
<span class="token comment">// 数组大小即为枚举元素个数里面存储case用来对比的数字</span>
<span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token punctuation">]</span> $<span class="token class-name">SwitchMap</span>$com$zhuhjay$jit$<span class="token class-name">Sex</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token keyword">int</span><span class="token punctuation">[</span><span class="token number">2</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
$<span class="token class-name">SwitchMap</span>$com$zhuhjay$jit$<span class="token class-name">Sex</span><span class="token punctuation">[</span><span class="token class-name">Sex</span><span class="token punctuation">.</span><span class="token constant">MALE</span><span class="token punctuation">.</span><span class="token function">ordinal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">1</span><span class="token punctuation">;</span>
$<span class="token class-name">SwitchMap</span>$com$zhuhjay$jit$<span class="token class-name">Sex</span><span class="token punctuation">[</span><span class="token class-name">Sex</span><span class="token punctuation">.</span><span class="token constant">FEMALE</span><span class="token punctuation">.</span><span class="token function">ordinal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span> <span class="token operator">=</span> <span class="token number">2</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">foo</span><span class="token punctuation">(</span><span class="token class-name">Sex</span> sex<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">int</span> x <span class="token operator">=</span> <span class="token class-name">Candy7</span>$<span class="token number">1.</span>$<span class="token class-name">SwitchMap</span>$com$zhuhjay$jit$<span class="token class-name">Sex</span><span class="token punctuation">[</span>sex<span class="token punctuation">.</span><span class="token function">ordinal</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">]</span><span class="token punctuation">;</span>
<span class="token keyword">switch</span> <span class="token punctuation">(</span>x<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>
<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;&quot;</span><span class="token punctuation">)</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 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;&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">break</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br></div></div><h3 id="_3-8-枚举类"><a href="#_3-8-枚举类" class="header-anchor">#</a> 3.8 枚举类</h3> <p><code>JDK 7</code> 新增了枚举类,以前面的性别枚举为例</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">enum</span> <span class="token class-name">Sex</span> <span class="token punctuation">{</span>
<span class="token constant">MALE</span><span class="token punctuation">,</span> <span class="token constant">FEMALE</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>转换后的代码如下</p> <ul><li>继承 <code>Enum</code> 枚举类</li> <li><code>final</code> 修饰类</li> <li>实例个数都在本类中创建,并且不可修改,属于常量</li> <li>私有构造方法,保护枚举类</li> <li><code>Enum.valueOf(Sex.class, name)</code> 底层原理就是 <code>Map</code>,通过键查找对应的枚举</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">public</span> <span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Sex</span> <span class="token keyword">extends</span> <span class="token class-name">Enum</span><span class="token generics"><span class="token punctuation">&lt;</span><span class="token class-name">Sex</span><span class="token punctuation">&gt;</span></span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Sex</span> <span class="token constant">MALE</span><span class="token punctuation">;</span>
<span class="token keyword">public</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Sex</span> <span class="token constant">FEMALE</span><span class="token punctuation">;</span>
<span class="token keyword">private</span> <span class="token keyword">static</span> <span class="token keyword">final</span> <span class="token class-name">Sex</span><span class="token punctuation">[</span><span class="token punctuation">]</span> $<span class="token constant">VALUES</span><span class="token punctuation">;</span>
<span class="token keyword">static</span> <span class="token punctuation">{</span>
<span class="token constant">MALE</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Sex</span><span class="token punctuation">(</span><span class="token string">&quot;MALE&quot;</span><span class="token punctuation">,</span> <span class="token number">0</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token constant">FEMALE</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Sex</span><span class="token punctuation">(</span><span class="token string">&quot;FEMALE&quot;</span><span class="token punctuation">,</span> <span class="token number">1</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
$<span class="token constant">VALUES</span> <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Sex</span><span class="token punctuation">[</span><span class="token punctuation">]</span><span class="token punctuation">{</span><span class="token constant">MALE</span><span class="token punctuation">,</span> <span class="token constant">FEMALE</span><span class="token punctuation">}</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">private</span> <span class="token class-name">Sex</span><span class="token punctuation">(</span><span class="token class-name">String</span> name<span class="token punctuation">,</span> <span class="token keyword">int</span> ordinal<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">super</span><span class="token punctuation">(</span>name<span class="token punctuation">,</span> ordinal<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 class-name">Sex</span><span class="token punctuation">[</span><span class="token punctuation">]</span> <span class="token function">values</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 constant">VALUES</span><span class="token punctuation">.</span><span class="token function">clone</span><span class="token punctuation">(</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 class-name">Sex</span> <span class="token function">valueOf</span><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">return</span> <span class="token class-name">Enum</span><span class="token punctuation">.</span><span class="token function">valueOf</span><span class="token punctuation">(</span><span class="token class-name">Sex</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">,</span> name<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br></div></div><h3 id="_3-9-try-with-resources"><a href="#_3-9-try-with-resources" class="header-anchor">#</a> 3.9 try-with-resources</h3> <p><code>JDK 7</code> 开始新增了对需要关闭的资源处理的特殊语法 <code>try-with-resources</code></p> <p>其中资源对象需要实现 <code>AutoCloseable</code> 接口,例如 <code>InputStream</code><code>OutputStream</code><code>Connection</code><code>Statement</code><code>ResultSet</code> 等接口都实现了 <code>AutoCloseable</code> ,使用 <code>try-with-resources</code> 可以不用写 <code>finally</code> 语句块,编译器会帮助生成关闭资源代码,例如:</p> <div class="language-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">Candy9</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 keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">InputStream</span> is <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span><span class="token string">&quot;E:\\10067\\Documents\\dist\\index.html&quot;</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>is<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br></div></div><p>编译后代码如下</p> <ul><li>更完整的关流操作,甚至可以保留压制异常 <code>var2.addSuppressed(var11);</code></li></ul> <div class="language-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">Candy9</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Candy9</span><span class="token punctuation">(</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 keyword">try</span> <span class="token punctuation">{</span>
<span class="token class-name">InputStream</span> is <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">FileInputStream</span><span class="token punctuation">(</span><span class="token string">&quot;E:\\10067\\Documents\\dist\\index.html&quot;</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token class-name">Throwable</span> var2 <span class="token operator">=</span> <span class="token keyword">null</span><span class="token punctuation">;</span>
<span class="token keyword">try</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>is<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> var12<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// var2 是我们代码出现的异常</span>
var2 <span class="token operator">=</span> var12<span class="token punctuation">;</span>
<span class="token keyword">throw</span> var12<span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">finally</span> <span class="token punctuation">{</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>is <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 如果我们代码有异常</span>
<span class="token keyword">if</span> <span class="token punctuation">(</span>var2 <span class="token operator">!=</span> <span class="token keyword">null</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token keyword">try</span> <span class="token punctuation">{</span>
is<span class="token punctuation">.</span><span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Throwable</span> var11<span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 当关流的时候也出现了异常,那么作为压制异常添加</span>
var2<span class="token punctuation">.</span><span class="token function">addSuppressed</span><span class="token punctuation">(</span>var11<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">else</span> <span class="token punctuation">{</span>
<span class="token comment">// 我们代码没有异常,关流出现了异常,那么 var14 关流的异常</span>
is<span class="token punctuation">.</span><span class="token function">close</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>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> var14<span class="token punctuation">)</span> <span class="token punctuation">{</span>
var14<span class="token punctuation">.</span><span class="token function">printStackTrace</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>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br><span class="line-number">16</span><br><span class="line-number">17</span><br><span class="line-number">18</span><br><span class="line-number">19</span><br><span class="line-number">20</span><br><span class="line-number">21</span><br><span class="line-number">22</span><br><span class="line-number">23</span><br><span class="line-number">24</span><br><span class="line-number">25</span><br><span class="line-number">26</span><br><span class="line-number">27</span><br><span class="line-number">28</span><br><span class="line-number">29</span><br><span class="line-number">30</span><br><span class="line-number">31</span><br><span class="line-number">32</span><br><span class="line-number">33</span><br><span class="line-number">34</span><br></div></div><p>为什么要设计一个 <code>addSuppressed(Throwable e)</code> (添加被压制异常)的方法呢?是为了防止异常信息的丢失(想想 <code>try-with-resources</code> 生成的 <code>fianlly</code> 中如果抛出了异常):</p> <div class="language-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">Test1</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 keyword">try</span> <span class="token punctuation">(</span><span class="token class-name">MyResource</span> resource <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">MyResource</span><span class="token punctuation">(</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">1</span><span class="token operator">/</span><span class="token number">0</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span> <span class="token keyword">catch</span> <span class="token punctuation">(</span><span class="token class-name">Exception</span> e<span class="token punctuation">)</span> <span class="token punctuation">{</span>
e<span class="token punctuation">.</span><span class="token function">printStackTrace</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>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">MyResource</span> <span class="token keyword">implements</span> <span class="token class-name">AutoCloseable</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token keyword">void</span> <span class="token function">close</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token keyword">throws</span> <span class="token class-name">Exception</span> <span class="token punctuation">{</span>
<span class="token keyword">throw</span> <span class="token keyword">new</span> <span class="token class-name">Exception</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 punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br><span class="line-number">12</span><br><span class="line-number">13</span><br><span class="line-number">14</span><br><span class="line-number">15</span><br></div></div><p>执行以上代码有以下结果,可以发现异常信息被完整的保留了下来</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>java.lang.ArithmeticException: / by zero
at com.zhuhjay.jit.Test1.main(Test1.java:10)
Suppressed: java.lang.Exception: 关流异常
at com.zhuhjay.jit.MyResource.close(Test1.java:20)
at com.zhuhjay.jit.Test1.main(Test1.java:11)
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><h3 id="_3-10-方法重写时的桥接方法"><a href="#_3-10-方法重写时的桥接方法" class="header-anchor">#</a> 3.10 方法重写时的桥接方法</h3> <p>我们都知道,方法重写时对返回值分两种情况:</p> <ul><li>父子类的返回值完全一致</li> <li>子类返回值可以是父类返回值的子类(比较绕口,见下面的例子)</li></ul> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Number</span> <span class="token function">m</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 number">1</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
<span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">m</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 number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br><span class="line-number">11</span><br></div></div><p>对于子类java 编译器会做如下处理:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">class</span> <span class="token class-name">B</span> <span class="token keyword">extends</span> <span class="token class-name">A</span> <span class="token punctuation">{</span>
<span class="token keyword">public</span> <span class="token class-name">Integer</span> <span class="token function">m</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 number">2</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token comment">// 此方法才是真正重写了父类 public Number m() 方法</span>
<span class="token keyword">public</span> synthetic bridge <span class="token class-name">Number</span> <span class="token function">m</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token comment">// 调用 public Integer m()</span>
<span class="token keyword">return</span> <span class="token function">m</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>其中桥接方法比较特殊,仅对 java 虚拟机可见,并且与原来的 <code>public Integer m()</code> 没有命名冲突,可以用下面反射代码来验证:</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token keyword">for</span> <span class="token punctuation">(</span><span class="token class-name">Method</span> declaredMethod <span class="token operator">:</span> <span class="token class-name">B</span><span class="token punctuation">.</span><span class="token keyword">class</span><span class="token punctuation">.</span><span class="token function">getDeclaredMethods</span><span class="token punctuation">(</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>declaredMethod<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br></div></div><p>发现有两个 <code>m()</code> 方法,证明了字节码中桥接方法的存在</p> <div class="language- line-numbers-mode"><pre class="language-text"><code>public java.lang.Integer com.zhuhjay.jit.B.m()
public java.lang.Number com.zhuhjay.jit.B.m()
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br></div></div><h3 id="_3-11-匿名内部类"><a href="#_3-11-匿名内部类" class="header-anchor">#</a> 3.11 匿名内部类</h3> <div class="language-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">Candy11</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 class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</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">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;ok&quot;</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>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>源代码编译后会生成一个额外的类</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 额外生成的类</span>
<span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Candy11</span>$<span class="token number">1</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>
<span class="token class-name">Candy11</span>$<span class="token function">1</span><span class="token punctuation">(</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">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">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;ok&quot;</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br></div></div><div class="language-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">Candy11</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 class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Candy11</span>$<span class="token function">1</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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><p>引用局部变量的匿名内部类,源代码:</p> <div class="language-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">Candy11</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 keyword">final</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 class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Runnable</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token punctuation">{</span>
<span class="token annotation punctuation">@Override</span>
<span class="token keyword">public</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">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;ok&quot;</span> <span class="token operator">+</span> args<span class="token punctuation">.</span>length<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>
<span class="token punctuation">}</span>
<span class="token punctuation">}</span>
</code></pre> <div class="line-numbers-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><p>会在额外生成的类中添加一个有参构造方法,通过参数的方式传递给该类的成员变量的存储,后续让方法获取成员变量的信息来达到目的</p> <div class="language-java line-numbers-mode"><pre class="language-java"><code><span class="token comment">// 额外生成的类</span>
<span class="token keyword">final</span> <span class="token keyword">class</span> <span class="token class-name">Candy11</span>$<span class="token number">1</span> <span class="token keyword">implements</span> <span class="token class-name">Runnable</span> <span class="token punctuation">{</span>
<span class="token keyword">final</span> <span class="token class-name">String</span><span class="token punctuation">[</span><span class="token punctuation">]</span> val$args<span class="token punctuation">;</span>
<span class="token class-name">Candy11</span>$<span class="token function">1</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 keyword">this</span><span class="token punctuation">.</span>val$args <span class="token operator">=</span> args<span class="token punctuation">;</span>
<span class="token punctuation">}</span>
<span class="token keyword">public</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">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;ok&quot;</span> <span class="token operator">+</span> val$args<span class="token punctuation">.</span>length<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br><span class="line-number">6</span><br><span class="line-number">7</span><br><span class="line-number">8</span><br><span class="line-number">9</span><br><span class="line-number">10</span><br></div></div><div class="language-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">Candy11</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 keyword">final</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 class-name">Runnable</span> runnable <span class="token operator">=</span> <span class="token keyword">new</span> <span class="token class-name">Candy11</span>$<span class="token function">1</span><span class="token punctuation">(</span>args<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-wrapper"><span class="line-number">1</span><br><span class="line-number">2</span><br><span class="line-number">3</span><br><span class="line-number">4</span><br><span class="line-number">5</span><br></div></div><blockquote><p><strong>注意</strong> 这同时解释了为什么匿名内部类引用局部变量时,局部变量必须是 <code>final</code> 的:因为在创建 <code>Candy11$1</code> 对象时,将 <code>args</code> 的值赋值给了 <code>Candy11$1</code> 对象的 <code>val$args</code> 属性,所以 <code>args</code> 不应该再发生变化,如果变化了,那么 <code>val$args</code> 属性没有机会跟着一起变化。(当不对变量进行修改时,编译器会将局部变量用 <code>final</code> 修饰)</p></blockquote></div></section> <footer class="page-edit"><!----> <!----></footer> <div class="page-nav"><p class="inner"><span class="prev"><a href="/blogs/java/jvm/JVM-垃圾回收.html" class="prev">
JVM之垃圾回收
</a></span> <span class="next"><a href="/blogs/java/jvm/JVM-类加载.html">
JVM之类加载
</a></span></p></div> <div class="comments-wrapper"><!----></div></main></div> <!----></div> <ul class="sub-sidebar sub-sidebar-wrapper" style="width:12rem;" data-v-b57cc07c data-v-7dd95ae2><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-类文件结构" class="sidebar-link reco-side-_1-类文件结构" data-v-b57cc07c>1 类文件结构</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-1-魔数" class="sidebar-link reco-side-_1-1-魔数" data-v-b57cc07c>1.1 魔数</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-2-版本" class="sidebar-link reco-side-_1-2-版本" data-v-b57cc07c>1.2 版本</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-3-常量池" class="sidebar-link reco-side-_1-3-常量池" data-v-b57cc07c>1.3 常量池</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-4-访问标识与继承信息" class="sidebar-link reco-side-_1-4-访问标识与继承信息" data-v-b57cc07c>1.4 访问标识与继承信息</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-5-field-信息" class="sidebar-link reco-side-_1-5-field-信息" data-v-b57cc07c>1.5 Field 信息</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-6-method-信息" class="sidebar-link reco-side-_1-6-method-信息" data-v-b57cc07c>1.6 Method 信息</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_1-7-附加属性" class="sidebar-link reco-side-_1-7-附加属性" data-v-b57cc07c>1.7 附加属性</a></li><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-字节码指令" class="sidebar-link reco-side-_2-字节码指令" data-v-b57cc07c>2 字节码指令</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-1-入门" class="sidebar-link reco-side-_2-1-入门" data-v-b57cc07c>2.1 入门</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-2-javap-工具" class="sidebar-link reco-side-_2-2-javap-工具" data-v-b57cc07c>2.2 javap 工具</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-3-图解方法执行流程" class="sidebar-link reco-side-_2-3-图解方法执行流程" data-v-b57cc07c>2.3 图解方法执行流程</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-4-练习-分析i" class="sidebar-link reco-side-_2-4-练习-分析i" data-v-b57cc07c>2.4 练习 - 分析i++</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-5-条件判断指令" class="sidebar-link reco-side-_2-5-条件判断指令" data-v-b57cc07c>2.5 条件判断指令</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-6-循环控制指令" class="sidebar-link reco-side-_2-6-循环控制指令" data-v-b57cc07c>2.6 循环控制指令</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-7-练习-判断结果" class="sidebar-link reco-side-_2-7-练习-判断结果" data-v-b57cc07c>2.7 练习 - 判断结果</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-8-构造方法" class="sidebar-link reco-side-_2-8-构造方法" data-v-b57cc07c>2.8 构造方法</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-9-方法调用" class="sidebar-link reco-side-_2-9-方法调用" data-v-b57cc07c>2.9 方法调用</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-10-多态的原理" class="sidebar-link reco-side-_2-10-多态的原理" data-v-b57cc07c>2.10 多态的原理</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-11-异常处理" class="sidebar-link reco-side-_2-11-异常处理" data-v-b57cc07c>2.11 异常处理</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-12-练习-finally-面试题" class="sidebar-link reco-side-_2-12-练习-finally-面试题" data-v-b57cc07c>2.12 练习 - finally 面试题</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_2-13-synchronized" class="sidebar-link reco-side-_2-13-synchronized" data-v-b57cc07c>2.13 synchronized</a></li><li class="level-2" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-编译器处理" class="sidebar-link reco-side-_3-编译器处理" data-v-b57cc07c>3 编译器处理</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-1-默认构造器" class="sidebar-link reco-side-_3-1-默认构造器" data-v-b57cc07c>3.1 默认构造器</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-2-自动拆装箱" class="sidebar-link reco-side-_3-2-自动拆装箱" data-v-b57cc07c>3.2 自动拆装箱</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-3-泛型集合取值" class="sidebar-link reco-side-_3-3-泛型集合取值" data-v-b57cc07c>3.3 泛型集合取值</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-4-可变参数" class="sidebar-link reco-side-_3-4-可变参数" data-v-b57cc07c>3.4 可变参数</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-5-foreach-循环" class="sidebar-link reco-side-_3-5-foreach-循环" data-v-b57cc07c>3.5 foreach 循环</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-6-switch-字符串" class="sidebar-link reco-side-_3-6-switch-字符串" data-v-b57cc07c>3.6 switch 字符串</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-7-switch-枚举" class="sidebar-link reco-side-_3-7-switch-枚举" data-v-b57cc07c>3.7 switch 枚举</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-8-枚举类" class="sidebar-link reco-side-_3-8-枚举类" data-v-b57cc07c>3.8 枚举类</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-9-try-with-resources" class="sidebar-link reco-side-_3-9-try-with-resources" data-v-b57cc07c>3.9 try-with-resources</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-10-方法重写时的桥接方法" class="sidebar-link reco-side-_3-10-方法重写时的桥接方法" data-v-b57cc07c>3.10 方法重写时的桥接方法</a></li><li class="level-3" data-v-b57cc07c><a href="/blogs/java/jvm/JVM-%E5%AD%97%E8%8A%82%E7%A0%81%E6%8A%80%E6%9C%AF.html#_3-11-匿名内部类" class="sidebar-link reco-side-_3-11-匿名内部类" data-v-b57cc07c>3.11 匿名内部类</a></li></ul></div></div></div><div class="global-ui"><div class="back-to-ceiling" style="right:1rem;bottom:6rem;width:2.5rem;height:2.5rem;border-radius:.25rem;line-height:2.5rem;display:none;" data-v-c6073ba8 data-v-c6073ba8><svg t="1574745035067" viewBox="0 0 1024 1024" version="1.1" xmlns="http://www.w3.org/2000/svg" p-id="5404" class="icon" data-v-c6073ba8><path d="M526.60727968 10.90185116a27.675 27.675 0 0 0-29.21455937 0c-131.36607665 82.28402758-218.69155461 228.01873535-218.69155402 394.07834331a462.20625001 462.20625001 0 0 0 5.36959153 69.94390903c1.00431239 6.55289093-0.34802892 13.13561351-3.76865779 18.80351572-32.63518765 54.11355614-51.75690182 118.55860487-51.7569018 187.94566865a371.06718723 371.06718723 0 0 0 11.50484808 91.98906777c6.53300375 25.50556257 41.68394495 28.14064038 52.69160883 4.22606766 17.37162448-37.73630017 42.14135425-72.50938081 72.80769204-103.21549295 2.18761121 3.04276886 4.15646224 6.24463696 6.40373557 9.22774369a1871.4375 1871.4375 0 0 0 140.04691725 5.34970492 1866.36093723 1866.36093723 0 0 0 140.04691723-5.34970492c2.24727335-2.98310674 4.21612437-6.18497483 6.3937923-9.2178004 30.66633723 30.70611158 55.4360664 65.4791928 72.80769147 103.21549355 11.00766384 23.91457269 46.15860503 21.27949489 52.69160879-4.22606768a371.15156223 371.15156223 0 0 0 11.514792-91.99901164c0-69.36717486-19.13165746-133.82216804-51.75690182-187.92578088-3.42062944-5.66790279-4.76302748-12.26056868-3.76865837-18.80351632a462.20625001 462.20625001 0 0 0 5.36959269-69.943909c-0.00994388-166.08943902-87.32547796-311.81420293-218.6915546-394.09823051zM605.93803103 357.87693858a93.93749974 93.93749974 0 1 1-187.89594924 6.1e-7 93.93749974 93.93749974 0 0 1 187.89594924-6.1e-7z" p-id="5405" data-v-c6073ba8></path><path d="M429.50777625 765.63860547C429.50777625 803.39355007 466.44236686 1000.39046097 512.00932183 1000.39046097c45.56695499 0 82.4922232-197.00623328 82.5015456-234.7518555 0-37.75494459-36.9345906-68.35043303-82.4922232-68.34111062-45.57627738-0.00932239-82.52019037 30.59548842-82.51086798 68.34111062z" p-id="5406" data-v-c6073ba8></path></svg></div></div></div>
<script src="/assets/js/app.049e1b5b.js" defer></script><script src="/assets/js/3.ff0e945d.js" defer></script><script src="/assets/js/1.1ced4111.js" defer></script><script src="/assets/js/20.c6871f96.js" defer></script>
</body>
</html>