- 新增 .drone.yml 文件用于定义 CI/CD 流程 - 配置了基于 Docker 的部署步骤 - 设置了工作区和卷映射以支持持久化数据 - 添加了构建准备阶段和 Docker 部署阶段 - 定义了环境变量和代理设置 - 配置了 artifacts 目录的处理逻辑 - 添加了 timezone 映射以确保时间同步 - 设置了 docker.sock 映射以支持 Docker in Docker
1323 lines
259 KiB
HTML
1323 lines
259 KiB
HTML
<!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">"Hello World"</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; //类的访问控制符标识(public,static,final,abstract等)
|
||
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; //属性数,包括InnerClasses,EnclosingMethod,SourceFile等
|
||
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 34(52) 表示是 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>Length(Byte)</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 项 0a(10),由映射表得知是一个 Method 信息,其通过后续的 00 06(6) 和 00 11(17) 分别表示该方法的【所属类】引用常量池中 #6 项、【方法名】引用常量池中 #17 项。</p> <p><img src="/jvm/1670048081295.png" alt="1670048081295"></p> <p>常量池中 #2 项 09(9),由映射表得知是一个 Field 信息,其通过后续的 00 12(18) 和 00 13(19) 分别表示该成员变量的【所属类】引用常量池中 #18 项、【成员变量名】引用常量池中 #19 项。</p> <p><img src="/jvm/1670048493839.png" alt="1670048493839"></p> <p>常量池中 #3 项 08(8),由映射表得知是一个字符串常量名称,其通过后续的 00 14(20)表示其引用了常量池中 #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."<init>":()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 <init>
|
||
#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 // "<init>":()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."<init>":()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: "HelloWorld.java"
|
||
</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."<init>":()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 => aload_0:加载 slot 0 的局部变量,即 this,做为下面的 invokespecial 构造方法调用的参数</li> <li>b7 => invokespecial:预备调用构造方法,哪个方法呢?</li> <li>00 01:引用常量池中 #1 项,即【 Method java/lang/Object.""😦)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 => getstatic:用来加载静态变量,哪个静态变量呢?</li> <li>00 02:引用常量池中 #2 项,即【Field java/lang/System.out:Ljava/io/PrintStream;】</li> <li>12 => ldc:加载参数,哪个参数呢?</li> <li>03:引用常量池中 #3 项,即 【String Hello World】</li> <li>b6 => 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 "HelloWorld.java"
|
||
public class HelloWorld
|
||
minor version: 0
|
||
major version: 52
|
||
flags: ACC_PUBLIC, ACC_SUPER
|
||
Constant pool:
|
||
#1 = Methodref #6.#17 // java/lang/Object."<init>":()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 <init>
|
||
#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 // "<init>":()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."<init>":()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: "HelloWorld.java"
|
||
</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 "Demo3_1.java"
|
||
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."<init>":()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 <init>
|
||
#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 // "<init>":()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."<init>":()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: "Demo3_1.java"
|
||
</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>判断是否 < 0</td></tr> <tr><td>0x9c</td> <td>ifge</td> <td>判断是否 >= 0</td></tr> <tr><td>0x9d</td> <td>ifgt</td> <td>判断是否 > 0</td></tr> <tr><td>0x9e</td> <td>ifle</td> <td>判断是否 <= 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是否 <</td></tr> <tr><td>0xa2</td> <td>if_icmpge</td> <td>两个int是否 >=</td></tr> <tr><td>0xa3</td> <td>if_icmpgt</td> <td>两个int是否 ></td></tr> <tr><td>0xa4</td> <td>if_icmple</td> <td>两个int是否 <=</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>byte,short,char 都会按 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 -> 6 -> 8 -> 9 -> 15</code>:执行到 <code>goto</code> 指令后会跳转到对应的序号指令继续执行</li> <li><code>3 -> 12 -> 14 0> 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> 以上比较指令中没有 long,float,double 的比较,那么它们要比较怎么办?</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"><</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"><</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"><</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"><</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><clinit>()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><clinit>()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><init>()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">"s1"</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">"s2"</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">"s3"</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 // <- "s1"
|
||
7: putfield #3 // -> this.a
|
||
10: aload_0
|
||
11: bipush 20 // <- 20
|
||
13: putfield #4 // -> this.b
|
||
16: aload_0
|
||
17: bipush 10 // <- 10
|
||
19: putfield #4 // -> this.b
|
||
22: aload_0
|
||
23: ldc #5 // <- "s2"
|
||
25: putfield #3 // -> this.a
|
||
28: aload_0
|
||
29: aload_1 // <- "s3"
|
||
30: putfield #3 // -> this.a
|
||
33: aload_0
|
||
34: iload_2 // <- 30
|
||
35: putfield #4 // -> 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 "<init>":()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>"<init>":()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">"我是"</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">"啃骨头"</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">"吃鱼"</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 -> 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 -> 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 -> 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 个虚方法(多态相关的,final,static 不会列入)</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 -> 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 -> 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 -> i
|
||
2: bipush 10 // try ----------------------
|
||
4: istore_1 // 10 -> i |
|
||
5: bipush 30 // finally |
|
||
7: istore_1 // 30 -> i |
|
||
8: goto 27 // return -------------------
|
||
11: astore_2 // catch Exception -> e -----
|
||
12: bipush 20 // |
|
||
14: istore_1 // 20 -> i |
|
||
15: bipush 30 // finally |
|
||
17: istore_1 // 30 -> i |
|
||
18: goto 27 // return -------------------
|
||
21: astore_3 // catch any -> slot 3 ------
|
||
22: bipush 30 // finally |
|
||
24: istore_1 // 30 -> i |
|
||
25: aload_3 // <- 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 // <- 10 放入栈顶
|
||
2: istore_0 // 10 -> slot 0 (从栈顶移除)
|
||
3: bipush 20 // <- 20 放入栈顶 (finally代码)
|
||
5: ireturn // 返回栈顶 int(20)
|
||
6: astore_1 // catch any -> slot 1
|
||
7: bipush 20 // <- 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 // <- 0 放入栈顶
|
||
1: istore_0 // 0 -> i
|
||
2: iload_0 // <- i(0)
|
||
3: istore_1 // 0 -> slot 1,暂存至 slot 1,目的是为了固定返回值
|
||
4: bipush 100 // <- 100 放入栈顶
|
||
6: istore_0 // 100 -> i
|
||
7: iload_1 // <- 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">"ok"</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 -> <init>:()V
|
||
7: astore_1 // 将 Object 引用 -> lock
|
||
8: aload_1 // <- lock (synchronized开始)
|
||
9: dup // 复制一份,一个用于加锁指令一个用于解锁指令
|
||
10: astore_2 // 将 Object 引用 -> slot 2
|
||
11: monitorenter // 加锁指令
|
||
12: getstatic #3 // <- System.out
|
||
15: ldc #4 // <- "ok"
|
||
17: invokevirtual #5 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
|
||
20: aload_2 // <- slot 2(解锁指令使用的 lock引用)
|
||
21: monitorexit // 解锁指令
|
||
22: goto 30
|
||
25: astore_3 // catch any -> slot 3
|
||
26: aload_2 // <- 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."<init>":()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"><</span><span class="token class-name">Integer</span><span class="token punctuation">></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"><</span><span class="token punctuation">></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."<init>":()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<Ljava/lang/Integer;>;
|
||
</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"><</span><span class="token class-name">Integer</span><span class="token punctuation">></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"><</span><span class="token class-name">String</span><span class="token punctuation">></span></span> list<span class="token punctuation">,</span> <span class="token class-name">Map</span><span class="token generics"><span class="token punctuation"><</span><span class="token class-name">Integer</span><span class="token punctuation">,</span> <span class="token class-name">Object</span><span class="token punctuation">></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">"test"</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">"原始类型 - "</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"><</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">"\t泛型参数[%d] - %s\n"</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">"hello"</span><span class="token punctuation">,</span> <span class="token string">"world"</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">"hello"</span><span class="token punctuation">,</span> <span class="token string">"world"</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"><</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"><</span><span class="token class-name">Integer</span><span class="token punctuation">></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"><</span><span class="token class-name">Integer</span><span class="token punctuation">></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">"hello"</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">"h"</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">"world"</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">"w"</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">"hello"</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">"world"</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">"h"</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">"w"</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">"BM"</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">"h"</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">"C."</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">"w"</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">"C."</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">"BM"</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">"h"</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">"w"</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">"男"</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">"女"</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()=0,FEMALE 的 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">"男"</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">"女"</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"><</span><span class="token class-name">Sex</span><span class="token punctuation">></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">"MALE"</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">"FEMALE"</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">"E:\\10067\\Documents\\dist\\index.html"</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">"E:\\10067\\Documents\\dist\\index.html"</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">"关流异常"</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">"ok"</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">"ok"</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">"ok"</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">"ok"</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>
|