<div class="htmledit_views" id="content_views">html
<h3><a name="t0"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">0. 前言</span></h3> <p> <span style="font-size:12px;"> 了解JVM虚拟机原理是每个Java程序员修炼的必经之路。可是因为JVM虚拟机中有不少的东西讲述的比较宽泛,在当前接触到的关于JVM虚拟机原理的教程或者博客中,绝大部分都是充斥的文字性的描述,很难给人以形象化的认知,看完以后感受仍是稀里糊涂的。<br></span></p> <p><span style="font-size:12px;"> 感于以上的种种,我打算把我在学习JVM虚拟机的过程当中学到的东西,结合本身的理解,总结成《Java虚拟机原理图解》 这个系列,以图解的形式,将抽象的JVM虚拟机的知识具体化,但愿可以对想了解Java虚拟机原理的的Java程序员 提供点帮助。</span></p> <blockquote><fieldset><legend>读完本文,你将会学到:</legend> <p><strong>一、类中定义的method方法是如何在class文件中组织的</strong></p> <p><strong>二、method方法的表示-方法表集合在class文件的什么位置</strong></p> <p><strong>三、<span style="font-family:'Comic Sans MS';">类中的method方法的实现代码---即机器码指令存放到哪了,并初步了解机器指令</span></strong></p> <p><strong><span style="font-family:'Comic Sans MS';">4. 为何没有在类中定义本身的构造函数,却可使用new ClassName()构造函数建立对象</span></strong></p> <p><strong><span style="font-family:'Comic Sans MS';">5. IDE代码提示功能的基本原理<br></span></strong></p> </fieldset><br><p></p> </blockquote> <h3><a name="t1"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">1.概述</span></h3> <p><span style="font-size:14px;"><span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;"><strong> 方法表集合</strong>是指由若干个<strong><span style="font-family:'Comic Sans MS';"><span style="font-family:'Microsoft YaHei';">方法表</span>(method_info)</span></strong>组成的集合。对于在类中定义的若干个,通过<span style="font-family:'Comic Sans MS';"><strong>JVM</strong></span>编译成<strong><span style="font-family:'Comic Sans MS';">class</span></strong>文件后,会将相应的<span style="font-size:14px;"><span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;"><strong><span style="font-family:'Comic Sans MS';">method</span></strong></span></span></span>方法信息组织到一个叫作<strong>方法表集合</strong>的结构中,<strong>字段表集合</strong>是一个类数组结构,以下图所示:</span></span></span></p> <blockquote> <p><img src="https://img-blog.csdn.net/20141114104145226" alt=""><br></p> </blockquote> <h3><a name="t2"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">2. method方法的描述-方法表集合在class文件中的位置</span></h3> <p> <span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Comic Sans MS';">method</span></strong>方法的描述-<strong>方法表集合</strong>紧跟在<strong>字段表集合</strong>的后面(想了解<strong>字段表集合</strong>的读者能够<a href="http://blog.csdn.net/luanlouis/article/details/41046443" rel="nofollow" data-token="aff2d62ea4e1c9da373263a4d3b46e65">点击我查看</a>),以下图所示:</span></p> <p> <img src="https://img-blog.csdn.net/20141114104728083" alt=""><br></p> <p><br></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">接下来让咱们看看<strong><span style="font-family:'Comic Sans MS';">Method_info</span></strong> 结构体是怎么组织<strong><span style="font-family:'Comic Sans MS';">method</span></strong>方法信息的:</span></p> </blockquote> <h3><a name="t3"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">3. 一个类中的method方法应该包含哪些信息?----method_info结构体的定义</span></h3> <p> <span style="font-family:'Microsoft YaHei';font-size:12px;">对于一个方法的表示,咱们根据咱们能够归纳的信息以下所示:</span><br></p> <p> <img src="https://img-blog.csdn.net/20141114150716551" alt=""><br></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 实际上<span style="font-family:'Comic Sans MS';"><strong>JVM</strong></span>还会对<strong><span style="font-family:'Comic Sans MS';">method</span></strong>方法的描述添加其余信息,咱们将在后面详细讨论。</span><span style="font-family:'Microsoft YaHei';font-size:12px;">如上图中的<strong><span style="font-family:'Comic Sans MS';">method_info结</span>构体</strong>的定义,该结构体的定义跟描述<strong><span style="font-family:'Comic Sans MS';">field</span>字段</strong> 的<strong><span style="font-family:'Comic Sans MS';">field_info</span>结构体</strong>的结构几乎彻底一致,以下图所示</span>。<br></p> <p> <img src="https://img-blog.csdn.net/20141114144708625" alt=""><br></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 方法表的结构体由:<span style="color:#FF0000;"><strong>访问标志(<span style="font-family:'Comic Sans MS';">access_flags</span>)、名称索引(<span style="font-family:'Comic Sans MS';">name_index</span>)、描述索引(<span style="font-family:'Comic Sans MS';">descriptor_index</span>)、属性表(<span style="font-family:'Comic Sans MS';">attribute_info</span>)集合</strong></span>组成。</span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>访问标志(<span style="font-family:'Comic Sans MS';">access_flags</span>):</strong></span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Comic Sans MS';">method_info</span>结构体</strong>最前面的<strong>两个字节</strong>表示的<strong>访问标志(access_flags)</strong>,记录这这个方法的做用域、静态or非静态、可变性、是否可同步、是否本地方法、是否抽象等信息,实际上不止这些信息,咱们后面会详细介绍访问标志这两个字节的每一位具体表示什么意思。</span></p> </blockquote> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';"><strong>名称索引(<span style="font-family:'Comic Sans MS';">name_index</span>):</strong><br></span></span></p> <blockquote> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';">紧跟在访问标志(access_flags)后面的<strong>两个字节</strong>称为<strong>名称索引</strong>,这两个字节中的值指向了常量池中的某一个常量池项,这个方法的名称以UTF-8格式的字符串存储在这个<strong>常量池项</strong>中。如<span><span style="font-family:'Comic Sans MS';">public void methodName()</span></span>,很显然,“<span style="font-family:'Comic Sans MS';"><span>methodName</span></span>”则表示着这个方法的名称,那么在常量池中会有一个<span style="font-family:'Comic Sans MS';">CONSTANT_Utf8_info</span>格式的常量池项,里面存储着<span style="font-family:'Microsoft YaHei';">“<span style="font-family:'Comic Sans MS';"><span>methodName</span></span>”</span>字符串,而<span style="font-family:'Comic Sans MS';">mehodName</span>()方法的方法表中的名称索引则指向了这个常量池项。</span></span></p> </blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>描述索引(<span style="font-family:'Comic Sans MS';">descriptor_index</span>):</strong></span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>描述索引表示的是这个方法的特征或者说是签名</strong>,<strong>一个方法会有若干个参数和返回值</strong>,而若干个参数的数据类型和返回值的数据类型构成了这个方法的描述,其基本格式为: <strong> (参数数据类型描述列表)返回值数据类型 </strong> 。咱们将在后面继续讨论。<br></span></p> </blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>属性表(<span style="font-family:'Comic Sans MS';">attribute_info</span>)集合:</strong><br></span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 这个属性表集合很是重要,方法的实现被JVM编译成JVM的<em><strong>机器码指令</strong></em>,<span style="font-family:'Microsoft YaHei';"><em><strong>机器码指令</strong></em></span>就存放在一个<strong><span style="font-family:'Comic Sans MS';">Code</span></strong>类型的属性表中;若是方法声明要抛出异常,那么异常信息会在一个<strong><span style="font-family:'Comic Sans MS';">Exceptions</span></strong>类型的属性表中予以展示。<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span>类型的属性表能够说是很是复杂的内容,也是本文最难的地方。</span></p> <p><br></p> </blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><em>接下来,咱们将一一击破它们,看看它们究竟是怎么表示的。</em><br></span></p> </blockquote> <h3><a name="t4"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">4. 访问标志(access_flags)---记录着method方法的访问信息</span></h3> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">访问标志(<strong><span style="font-family:'Comic Sans MS';color:#FF6600;">access_flags</span></strong>)共占有<strong>2</strong> 个字节,分为 <strong>16 </strong>位,这<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong> 16</strong></span>位 表示的含义以下所示:</span><br></p> <p><img src="https://img-blog.csdn.net/20141114161151578" alt=""></p> </blockquote> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">举例:某个类中定义了以下方法:</span></p> <pre><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">greeting</span><span class="hljs-params">()</span></span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li></ol></code><div class="hljs-button signin" data-title="登陆后复制" onclick="hljs.signin(event)"></div></pre><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">greeting()</span></strong>方法的修饰符有:<span style="color:#000099;"><span><span style="font-family:'Comic Sans MS';">public、static、synchronized、final</span></span></span> 这几个修饰符修饰,那么相对应地,<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">greeting()</span></strong></span>方法的访问标志中的<span style="font-family:'Comic Sans MS';color:#FF0000;">ACC_PUBLIC、ACC_STATIC、ACC_SYNCHRONIZED、ACC_FINAL</span>标志位都应该是<strong>1</strong>,即:</span></span> <p><img src="https://img-blog.csdn.net/20141114170949140" alt=""><br></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">从上图中能够看出<strong>访问标志</strong>的值应该是二进制<strong>00000000 00111001,即十六进制0x0039</strong>。咱们将在文章的最后一个例子中证明这里点。</span></p> </blockquote> <h3><a name="t5"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">5. 名称索引和描述符索引----一个方法的签名</span></h3> <blockquote> <p><span style="font-size:12px;"> <span style="font-family:'Microsoft YaHei';"> 紧接着<strong>访问标志(<span style="font-family:'Comic Sans MS';">access_flags</span>)</strong>后面的<strong>两个字节</strong>,叫作<strong>名称索引</strong>(<strong><span style="font-family:'Comic Sans MS';">name_index</span></strong>),这两个字节中的值是指向了常量池中某个常量池项的索引,该常量池项表示这这个方法名称的字符串。</span></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>方法描述符索引(<span style="font-family:'Comic Sans MS';">descrptor_index</span>)</strong>是紧跟在<strong>名称索引</strong>后面的两个字节,这两个字节中的值跟名称索引中的值性质同样,都是指向了常量池中的某个常量池项。这两个字节中的指向的常量池项,<strong>是表示了方法描述符的字符串</strong>。</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <u><span style="color:#FF0000;"><strong>所谓的方法描述符,实质上就是指用一个什么样的字符串来描述一个方法,</strong></span></u>方法描述符的组成以下图所示:</span></p> </blockquote> <blockquote> <p><img src="https://img-blog.csdn.net/20141114180514489" alt=""><br></p> </blockquote> <p> <span style="font-size:12px;"> <span style="font-family:'Microsoft YaHei';"> 关于不一样的<strong>数据类型的描述符</strong>是怎样的,我已经在<a name="41046443" href="http://blog.csdn.net/luanlouis/article/details/41046443" rel="nofollow" data-token="aff2d62ea4e1c9da373263a4d3b46e65">《Java虚拟机原理图解》1.4 class文件中的字段表集合--field字段在class文件中是怎样组织的</a> 第五部分字段的数据类型表示和字段名称表示 进行过详细的阐释,感兴趣的读者能够前去查看。</span></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <br></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 举例:对于以下定义的的<strong><span style="font-family:'Comic Sans MS';">greeting()</span></strong>方法,咱们来看一下对应的<strong><span style="font-family:'Comic Sans MS';">method_info</span></strong>结构体中的名称索引和描述符索引信息是怎样组织的。</span></p> <p></p> <pre><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">greeting</span><span class="hljs-params">()</span></span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li></ol></code><div class="hljs-button signin" data-title="登陆后复制" onclick="hljs.signin(event)"></div></pre> <span style="font-size:12px;"> <span style="font-size:12px;"> <span style="font-family:'Microsoft YaHei';">以下图所示,<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">method_info</span></strong></span>结构体的名称索引中存储了一个索引值<strong>x</strong>,指向了常量池中的第<strong>x</strong>项,第<strong> x</strong>项表示的是字符串"<span style="color:#FF0000;"><strong><span style="font-family:'Comic Sans MS';">greeting</span></strong></span>",即表示该方法名称是"<span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';"><span style="color:#FF0000;"><strong><span style="font-family:'Comic Sans MS';">greeting</span></strong></span></span></span>";描述符索引中的<strong><span style="font-family:'Comic Sans MS';">y</span></strong> 值指向了常量池的第<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">y</span></strong></span>项,该项表示字符串"<strong><span style="color:#FF0000;">()V</span></strong>",即表示该方法没有参数,返回值是<strong>void</strong>类型。</span></span></span> <p></p> <blockquote> <p><img src="https://img-blog.csdn.net/20141115094626151" alt=""><br></p> </blockquote> <p><br></p> <h3><a name="t6"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">6.属性表集合--记录方法的机器指令和抛出异常等信息</span><br></h3> <p> <span style="font-size:12px;"> <span style="font-family:'Microsoft YaHei';"> 属性表集合记录了某个方法的一些属性信息,这些信息包括:</span></span></p> <blockquote> <ul><li><span style="font-family:'Microsoft YaHei';font-size:12px;">这个方法的代码实现,<span style="color:#FF0000;">即<strong>方法的可执行的机器指令</strong></span></span></li><li><span style="font-family:'Microsoft YaHei';font-size:12px;">这个方法声明的<strong>要抛出的异常信息</strong></span></li><li><span style="font-family:'Microsoft YaHei';font-size:12px;">这个方法是否<strong>被@deprecated注解表示</strong></span></li><li><span style="font-family:'Microsoft YaHei';font-size:12px;">这个方法是不是<strong>编译器自动生成的</strong></span></li></ul></blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>属性表(attribute_info)</strong>结构体的通常结构以下所示:</span></p> <p> <img src="https://img-blog.csdn.net/20141115145825045" alt=""></p> <h4><span style="font-family:'Microsoft YaHei';font-size:14px;">6.1 Code类型的属性表--method方法中的机器指令的信息</span></h4> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>Code</strong>类型的<strong>属性表(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_info</span>)</strong>能够说是<span style="color:#FF6600;"><strong>class</strong></span>文件中最为重要的部分,由于它包含的是<strong>JVM</strong>能够运行的机器码指令,<strong>JVM</strong>可以运行这个类,就是从这个属性中取出机器码的。除了要执行的机器码,它还包含了一些其余信息,以下所示:</span></p> <p><img src="https://img-blog.csdn.net/20141116114625218" alt=""></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>Code属性表</strong>的组成部分:</span></p> <p><span style="font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';">机器指令----code:</span></strong></span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">目前的<strong><span style="font-family:'Comic Sans MS';">JVM</span></strong>使用一个字节表示机器操做码,即对<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">JVM</span></strong></span>底层而言,它能表示的机器操做码很少于<strong>2</strong>的 <strong>8</strong> 次方,即 <strong>256</strong>个。<strong><span style="font-family:'Comic Sans MS';">class</span></strong>文件中的机器指令部分是<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">class</span></strong></span>文件中最重要的部分,而且很是复杂,本文的重点不止介绍它,我将专门在一片博文中讨论它,敬请期待。</span></p> </blockquote> <p><span style="font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';">异常处理跳转信息---exception_table:</span></strong></span></p> <blockquote> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;">若是代码中出现了<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">try{}catch{}</span></strong></span>块,那么<span style="font-family:'Microsoft YaHei';"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">try{}</span></strong></span></span>块内的机器指令的地址范围记录下来,而且记录对应的<span style="font-family:'Microsoft YaHei';"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">catch{}</span></strong></span></span>块中的起始机器指令地址,当运行时在<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">try</span></strong></span>块中有异常抛出的话,<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">JVM</span></strong></span>会将<span style="font-family:'Microsoft YaHei';"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">catch{}</span></strong></span></span>块对应懂得其实机器指令地址传递给<strong>PC寄存器</strong>,从而实现指令跳转;</span></span></p> </blockquote> <p><span style="font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';">Java源码行号和机器指令的对应关系---LineNumberTable属性表:</span></strong></span></p> <blockquote> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>编译器在将<span style="font-family:'Comic Sans MS';">java</span>源码编译成<span style="font-family:'Microsoft YaHei';"><span style="font-family:'Comic Sans MS';">class</span></span>文件时,会将源码中的语句行号跟编译好的机器指令关联起来,这样的<span style="font-family:'Microsoft YaHei';"><span style="font-family:'Comic Sans MS';">class</span></span>文件加载到内存中并运行时,若是抛出异常,<span style="font-family:'Microsoft YaHei';"><span style="font-family:'Comic Sans MS';">JVM</span></span>能够根据这个对应关系,抛出异常信息,告诉咱们咱们的源码的多少行有问题,方便咱们定位问题。</strong>这个信息不是运行时必不可少的信息,可是默认状况下,编译器会生成这一项信息,若是你项取消这一信息,你可使用<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">-g:none</span></strong></span> 或<strong><span style="font-family:'Comic Sans MS';color:#FF6600;">-g:lines</span></strong>来取消或者要求设置这一项信息。若是使用了<span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';color:#FF6600;">-g:none</span></strong></span>来生成class文件,<strong><span style="color:#FF0000;"><u>class文件中将不会有LineNumberTable属性表,形成的影响就是 未来若是代码报错,将没法定位错误信息</u>报错的行,而且若是项调试代码,将不能在此类中打断点(由于没有指定行号。)</span></strong></span></span></p> </blockquote> <p><span style="font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';">局部变量表描述信息----LocalVariableTable属性表:</span></strong></span></p> <blockquote> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;">局部变量表信息会记录栈帧局部变量表中的变量和<span style="font-family:'Microsoft YaHei';"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">java</span></strong></span></span>源码中定义的变量之间的关系,这个信息不是运行时必须的属性,默认状况下不会生成到<span style="font-family:'Microsoft YaHei';"><span style="font-family:'Microsoft YaHei';"><strong><span style="font-family:'Comic Sans MS';">class</span></strong></span></span>文件中。你能够根据<strong><span style="font-family:'Comic Sans MS';color:#FF6600;">javac</span></strong>指令的<span style="font-family:'Microsoft YaHei';"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">-g:none</span></strong></span></span>或者<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>-g:vars</strong></span>选项来取消或者设置这一项信息。</span></span></p> <p><span style="font-size:12px;"><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';"><span style="color:#FF0000;"><strong>它有什么做用呢?</strong></span> 当咱们使用IDE进行开发时,最喜欢的莫过于它们的代码提示功能了。若是在项目中引用到了第三方的jar包,而第三方的包中的class文件中有无<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>LocalVariableTable</strong></span>属性表的区别以下所示:</span></span></span></p> <p><img src="https://img-blog.csdn.net/20141116221304421" alt=""></p> </blockquote> <fieldset><legend><span style="font-family:'Microsoft YaHei';font-size:12px;">Code属性表结构体的解释:</span></legend> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">1.<span style="font-family:'Comic Sans MS';"><strong><span style="color:#FF9900;"><span style="color:#FF6600;">attribute_name_index</span></span></strong></span><strong>,属性名称索引</strong>,占有<strong>2</strong>个字节,其内的值指向了常量池中的某一项,该项表示字符串“<span style="color:#3333FF;"><span><span style="font-family:'Comic Sans MS';"><strong>Code</strong></span></span></span>”;<br> 2. <span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">attribute_length</span></strong></span><strong>,属性长度</strong>,占有<strong> 4</strong>个字节,其内的值表示后面有多少个字节是属于此Code属性表的;<br> 3. <span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">max_stack,</span></strong></span><strong>操做数栈深度的最大值</strong>,占有<strong> 2</strong> 个字节,在方法执行的任意时刻,操做数栈都不该该超过这个值,虚拟机的运行的时候,会根据这个值来设置该方法对应的<strong>栈帧(Stack Frame)</strong>中的操做数栈的深度;<br> 4. <span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>max_locals</strong></span>,<strong>最大局部变量数目,</strong>占有<strong> 2</strong>个字节,其内的值表示局部变量表所须要的存储空间大小;<br> 5. <strong><span style="font-family:'Comic Sans MS';color:#FF6600;">code_length</span></strong>,<strong>机器指令长度</strong>,占有<strong> 4</strong> 个字节,表示跟在其后的多少个字节表示的是机器指令;<br> 6. <span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>code,</strong></span><strong>机器指令区域</strong>,该区域占有的字节数目由 <span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Comic Sans MS';color:#FF6600;">code_length</span></strong></span>中的值决定。JVM最底层的要执行的机器指令就存储在这里;<br> 7.<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"> exception_table_length</span></strong></span>,<strong>显式异常表长度</strong>,占有<strong>2</strong>个字节,若是在方法代码中出现了<span style="font-family:'Comic Sans MS';color:#FF6600;">try{} catch()</span>形式的结构,该值不会为空,紧跟其后会跟着若干个<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">exception_table</span></strong></span>结构体,以表示异常捕获状况;<br> 8. <span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">exception_table</span></strong></span>,<strong>显式异常表</strong>,占有<strong>8</strong> 个字节,<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">start_pc,end_pc,handler_pc</span></strong></span>中的值都表示的是<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">PC</span></strong></span>计数器中的指令地址。<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">exception_table</span></strong></span></span>表示的意思是:若是字节码从第<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">start_pc</span></strong></span></span></span></strong></span></span>行到第<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">end_pc</span></strong></span></span>行之间出现了<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">catch_type</span></strong></span>所描述的异常类型,那么将跳转到<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">handler_pc</span></strong></span></span>行继续处理。<br> 9.<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"> attribute_count,</span></strong></span><strong>属性计数器</strong>,占有<strong> 2</strong> 个字节,表示<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span>属性表的其余属性的数目<br> 10. <span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">attribute_info</span></strong></span>,表示<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span></span><strong>属性表</strong>具备的属性表,它主要分为两个类型的属性表:“<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">LineNumberTable</span></strong></span>”类型和“<span style="font-family:'Comic Sans MS';"><strong><span style="color:#FF6600;">LocalVariableTable</span></strong></span>”类型。<br> “<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">LineNumberTable</span></strong></span></span>”类型的属性表记录着<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Java</span></strong></span>源码和机器指令之间的对应关系<br> “<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';"><strong><span style="color:#FF6600;">LocalVariableTable</span></strong></span></span>”类型的属性表记录着局部变量描述</span></p> </fieldset><p><em><strong><span style="font-family:'Microsoft YaHei';font-size:14px;">举例:</span></strong></em></p> <p><span style="font-family:'Microsoft YaHei';"> <span style="font-size:12px;"> <em> 以下定义Simple类,使用javac -g:none Simple.java 编译出Simple.class 文件,并使用javap -v Simple > Simple.txt 查看反编译的信息,而后看Simple.class文件中的方法表集合是怎样组织的:</em></span></span></p> <pre><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">package</span> com.louis.jvm;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">class</span> <span class="hljs-title">Simple</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">static</span> <span class="hljs-keyword">synchronized</span> <span class="hljs-keyword">final</span> <span class="hljs-keyword">void</span> <span class="hljs-title">greeting</span><span class="hljs-params">()</span></span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-keyword">int</span> a = <span class="hljs-number">10</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="7"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> }</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="8"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button signin" data-title="登陆后复制" onclick="hljs.signin(event)"></div></pre> <p><em><strong><span style="font-family:'Microsoft YaHei';font-size:14px;">1. Simple.class文件组织信息以下所示:</span></strong></em></p> <p><img src="https://img-blog.csdn.net/20141117100511124" alt=""><br></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">如上所示,方法表集合使用了蓝色线段圈了起来。</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">请注意:方法表集合的头两个字节,即<strong>方法表计数器(<span style="font-family:'Comic Sans MS';color:#FF6600;">method_count</span>)</strong>的值是<strong>0x0002</strong>,它表示该类中有<strong>2 </strong>个方法。细心的读者会注意到,咱们的<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>Simple.java</strong></span>中就定义了一个<span style="font-family:'Comic Sans MS';color:#FF6600;">greeting()</span>方法,为何<strong>class</strong>文件中会显示有两个方法呢??</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">在<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>Simple.classz中</strong></span></span>出现了两个方法表,分别表明构造方法<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong><init>()</strong></span>和<strong> <span style="font-family:'Comic Sans MS';color:#FF6600;">greeting()</span></strong>方法,如今让咱们分别来讨论这两个方法:</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><br></span></p> <p><em><strong><span style="font-family:'Microsoft YaHei';font-size:14px;">2. Simple.class 中的<init>() 方法:</span></strong></em></p> <p><img src="https://img-blog.csdn.net/20141117111623566" alt=""><br></p> <p><span style="font-family:SimHei;"><strong><span style="font-size:14px;"> 解释:</span></strong></span></p> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 1.<strong> 方法访问标志(<span style="font-family:'Comic Sans MS';color:#FF6600;">access_flags</span>)</strong>: 占有<span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span></strong></span>个字节,值为<strong>0x0001</strong>,即标志位的第 <strong>16</strong> 位为<strong> 1</strong>,因此该<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"><init>()</span></strong></span>方法的修饰符是:<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">ACC_PUBLIC</span></strong></span>;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 2.<strong> 名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">name_index</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span>个字节,值为<strong> 0x0004</strong>,指向常量池的第<strong> 4</strong>项,该项表示字符串“<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"><init></span></strong></span></span>”,即该方法的名称是“<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"><init></span></strong></span></span>”;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 3<strong>.描述符索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">descriptor_index</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span></span>个字节,值为<strong>0x0005</strong>,指向常量池的第 <strong> 5</strong> 项,该项表示字符串“<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">()V</span></strong></span>”,即表示该方法不带参数,而且无返回值(构造函数确实也没有返回值);</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">4. <strong>属性计数器(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_count</span>):</strong> 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span></span></span>个字节,值为<strong>0x0001</strong>,表示该方法表中含有一个属性表,后面会紧跟着一个属性表;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">5.<strong> 属性表的名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_name_index</span>)</strong>:占有<strong> 2</strong> 个字节,值为<strong>0x0006</strong>,指向常量池中的第<strong>6</strong> 项,该项表示字符串“<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span>”,表示这个属性表是<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span></span>类型的属性表;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">6. <strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">4</span></strong></span></span></span></span>个字节,值为<strong>0x0000 0011</strong>,即十进制的 <strong>17</strong>,代表后续的<strong> 17</strong> 个字节能够表示这个<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span></span>属性表的属性信息;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">7. <strong>操做数栈的最大深度(<span style="font-family:'Comic Sans MS';color:#FF6600;">max_stack</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">2</span></strong></span></span></span></span>个字节,值为<strong>0x0001</strong>,表示栈帧中操做数栈的最大深度是<strong>1</strong>;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">8. <strong>局部变量表的最大容量(<span style="font-family:'Comic Sans MS';color:#FF6600;">max_variable</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">2</span></strong></span></span></span></span>个字节,值为<strong>0x0001</strong>, <span style="font-family:'Comic Sans MS';"><strong>JVM</strong></span>在调用该方法时,根据这个值设置栈帧中的局部变量表的大小;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">9. <strong>机器指令数目(<span style="font-family:'Comic Sans MS';color:#FF6600;">code_length</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">4</span></strong></span></span></span></span></span>个字节,值为<strong>0x0000 0005</strong>,表示后续的<strong>5 </strong>个字节<strong> <span style="color:#3333FF;">0x2A 、0xB七、 0x00、0x0一、0xB1</span></strong>表示机器指令;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">10. <strong>机器指令集<span style="font-family:'Comic Sans MS';">(<span style="color:#FF6600;">code[code_length]</span></span>)</strong>:这里共有<span style="font-family:'Microsoft YaHei';font-size:12px;"> <span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong> <span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">5</span></strong></span></span></span></span></span></strong></span></span></span></span></span>个字节,值为<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="color:#3333FF;">0x2A 、0xB七、 0x00、0x0一、0xB1</span></strong></span></strong></span>;</span></p> </blockquote> <blockquote></blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">11.<strong> 显式异常表集合(<span style="font-family:'Comic Sans MS';color:#FF6600;">exception_table_count</span>)</strong>: 占有<strong>2</strong> 个字节,值为<strong>0x0000</strong>,表示方法中没有须要处理的异常信息;</span></p> <p><span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;">12. <strong> Code属性表的属性表集合(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_count</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>2</strong> </span>个字节,值为<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>0x0000</strong></span>,表示它没有其余的属性表集合,由于咱们使用了<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">-g:none</span></strong></span> 禁止编译器生成<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span><strong>属性表</strong>的<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"> LineNumberTable 和LocalVariableTable</span></strong></span>;</span><br></span></p> <p><span style="font-family:'Microsoft YaHei';"><br></span></p> <p><em><strong><span style="font-family:'Microsoft YaHei';font-size:14px;">B. Simple.class 中的greeting() 方法:</span></strong></em></p> <p><img src="https://img-blog.csdn.net/20141117123854641" alt=""><br></p> <p></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 解释:</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 1. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>方法访问标志(<span style="font-family:'Comic Sans MS';color:#FF6600;">access_flags</span>)</strong></span>: 占有<strong> 2</strong>个字节,值为 <strong>0x0039</strong> ,即二进制的<strong>00000000 00111001</strong>,即标志位的第<strong>十一、十二、1三、16</strong>位为<strong>1</strong>,根据上面讲的方法标志位的表示,能够获得该<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>greeting()</strong></span>方法的修饰符有:<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>ACC_SYNCHRONIZED、ACC_FINAL、ACC_STATIC、ACC_PUBLIC</strong></span>;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 2.<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong> 名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">name_index</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span>个字节</span>,值为<strong> 0x0007</strong>,指向常量池的第<strong> 7</strong> 项,该项表示字符串“<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>greeting</strong></span></span>”,即该方法的名称是“<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>greeting</strong></span></span>”;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 3. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>描述符索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">descriptor_index</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span></span>个字节,</span>值为<strong>0x0005</strong>,指向常量池的第<strong> 5</strong> 项,该项表示字符串“<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>()V</strong></span>”,即表示该方法不带参数,而且无返回值;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">4. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>属性计数器(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_count</span>):</strong> 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span></span></span>个字节,</span>值为<strong>0x0001</strong>,表示该方法表中含有一个属性表,后面会紧跟着一个属性表;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">5.<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>属性表的名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_name_index</span>)</strong>:</span><span style="font-family:'Microsoft YaHei';font-size:12px;"></span><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;">占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;"> 2</span> </strong></span></span></span></span>个字节,</span></span>值为<strong>0x0006</strong>,指向常量池中的第<strong>6 </strong>项,该项表示字符串“<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span>”,表示这个属性表是<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span></span>类型的属性表;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">6. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">4</span></strong></span></span></span></span>个字节,</span>值为<strong>0x0000 0010</strong>,即十进制的<strong>16</strong>,代表后续的<strong>16</strong>个字节能够表示这个<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span></span>属性表的属性信息;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">7. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>操做数栈的最大深度(<span style="font-family:'Comic Sans MS';color:#FF6600;">max_stack</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">2</span></strong></span></span></span></span>个字节,</span>值为<strong>0x0001</strong>,表示栈帧中操做数栈的最大深度是<strong>1</strong>;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">8. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>局部变量表的最大容量(<span style="font-family:'Comic Sans MS';color:#FF6600;">max_variable</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF6600;"><strong><span style="color:#000000;">2</span></strong></span></span></span></span>个字节</span>,值为<strong>0x0001</strong>, <strong>JVM</strong>在调用该方法时,根据这个值设置栈帧中的局部变量表的大小;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">9. <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>机器指令数目(<span style="font-family:'Comic Sans MS';color:#FF6600;">code_length</span>)</strong>:</span>占有<strong>4 </strong>个字节,值为<strong>0x0000 0004,</strong>表示后续的<strong>4</strong>个字节<strong><span><span style="color:#000099;"><span style="color:#3333FF;"><span>0x十、 0x0A、 0x3B、0xB1</span></span></span></span></strong>的是表示机器指令;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">10.<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>机器指令集(code[code_length])</strong></span>:这里共有<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>4 </strong></span>个字节,值为<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span><span style="color:#000099;"><span style="color:#3333FF;"><span>0x十、 0x0A、 0x3B、0xB1</span></span></span></span></strong></span> ;</span></p> <blockquote></blockquote> <p></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">11.<strong> 显式异常表集合(<span style="font-family:'Comic Sans MS';color:#FF6600;">exception_table_count</span>)</strong>: 占有<strong>2</strong> 个字节,值为<strong>0x0000</strong>,表示方法中没有须要处理的异常信息;</span></p> <span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;">12. <strong> Code属性表的属性表集合(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_count</span>)</strong>: 占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>2</strong> </span>个字节,值为<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>0x0000</strong></span>,表示它没有其余的属性表集合,由于咱们使用了<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">-g:none</span></strong></span> 禁止编译器生成<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';">Code</span></strong></span><strong>属性表</strong>的<span style="color:#FF6600;"><strong><span style="font-family:'Comic Sans MS';"> LineNumberTable 和LocalVariableTable</span></strong></span>;</span></span> <p><br></p> <p><br></p> </blockquote> <h4><span style="font-family:'Microsoft YaHei';font-size:14px;">6.2 Exceptions类型的属性表----method方法声明的要抛出的异常信息</span></h4> <blockquote> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">有些方法在定义的时候,会声明该方法会抛出什么类型的异常,以下定义一个<span style="color:#FF0000;"><strong><span style="font-family:'Comic Sans MS';">Interface</span></strong></span>接口,它声明了<span style="font-family:'Comic Sans MS';color:#FF6600;">sayHello()</span>方法,抛出<span style="font-family:'Comic Sans MS';color:#FF6600;">Exception</span>异常:</span></p> <pre><code class="language-java hljs"><ol class="hljs-ln"><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="1"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">package</span> com.louis.jvm;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="2"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="3"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"><span class="hljs-keyword">public</span> <span class="hljs-class"><span class="hljs-keyword">interface</span> <span class="hljs-title">Interface</span> </span>{</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="4"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> </div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="5"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line"> <span class="hljs-function"><span class="hljs-keyword">public</span> <span class="hljs-keyword">void</span> <span class="hljs-title">sayHello</span><span class="hljs-params">()</span> <span class="hljs-keyword">throws</span> Exception</span>;</div></div></li><li><div class="hljs-ln-numbers"><div class="hljs-ln-line hljs-ln-n" data-line-number="6"></div></div><div class="hljs-ln-code"><div class="hljs-ln-line">}</div></div></li></ol></code><div class="hljs-button signin" data-title="登陆后复制" onclick="hljs.signin(event)"></div></pre> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">如今让咱们看一下<strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong>类型的<strong>属性表(attribute_info)</strong>结构体是怎样组织的:</span><br></p> <p><img src="https://img-blog.csdn.net/20141115154139486" alt=""></p> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';">如上图所示,<strong><span style="font-family:'Microsoft YaHei';"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong></span><span style="font-family:'Microsoft YaHei';">类型的<strong>属性表(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_info</span>)</strong>结构体由一下元素组成:</span></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>属性名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_name_index</span>)</strong>:占有<strong> 2</strong>个字节,其中的值指向了常量池中的表示"<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong></span>"字符串的常量池项;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong>:它比较特殊,占有<strong>4</strong>个字节,它的值表示跟在其后面多少个字节表示异常信息;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>异常数量(<span style="font-family:'Comic Sans MS';color:#FF6600;">number_of_exceptions</span>)</strong>:占有<strong>2</strong> 个字节,它的值表示方法声明抛出了多少个异常,即表示跟在其后有多少个<strong>异常名称索引</strong>;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>异常名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">exceptions_index_table</span>)</strong>:占有<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>2</strong></span>个字节,它的值指向了常量池中的某一项,该项是一个<span style="font-family:'Comic Sans MS';color:#FF6600;">CONSTANT_Class_info</span>类型的项,表示这个异常的彻底限定名称;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"><br></span></p> <fieldset><legend><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong></span>类型的<strong>属性表</strong>的长度计算</span></legend> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">若是某个方法定义中,没有声明抛出异常,那么,表示该方法的<strong>方法表(<span style="font-family:'Comic Sans MS';color:#FF6600;">method_info</span>)</strong>结构体中的属性表集合中不会有Exceptions类型的属性表;换句话说,若是方法声明了要抛出的异常,<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>方法表(<span style="font-family:'Comic Sans MS';color:#FF6600;">method_info</span>)</strong></span>结构体中的属性表集合中必然会有<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong></span></span>类型的属性表,而且该属性表中的异常数量<span style="color:#FF0000;">不小于1</span>。</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">咱们假设异常数量中的值为<span style="color:#FF0000;"> N</span>,那么后面的异常名称索引的数量就为<span style="color:#FF0000;">N</span>,它们总共占有的字节数为<span style="color:#FF0000;"><strong>N*2</strong></span>,而异常数量占有<span style="color:#FF0000;"><strong>2</strong></span>个字节,那么将有下面的这个关系式:</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <span style="font-family:'Microsoft YaHei';font-size:12px;"> <strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong></span>中的值= <strong>2 + 2*</strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>异常数量(<span style="font-family:'Comic Sans MS';color:#FF6600;">number_of_exceptions</span>)</strong></span>中的值</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> <span style="font-family:'Microsoft YaHei';font-size:12px;"> <span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';">Exception</span></span>s</strong></span></span>类型的<strong>属性表(<span style="font-family:'Comic Sans MS';color:#FF0000;">attribute_info</span>)</strong>的长度=<strong>2+4+</strong><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong></span>中的值<br></span></p> </fieldset><p><span style="font-family:'Microsoft YaHei';font-size:12px;">举例:</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">将上面定义的<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="color:#FF0000;"><strong><span style="font-family:'Comic Sans MS';">Interface</span></strong></span></span>接口类编译成<strong><span style="font-family:'Comic Sans MS';">class</span></strong>文件,而后咱们查看<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Comic Sans MS';">Interface</span></strong></span></span>.<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong><span style="font-family:'Comic Sans MS';">class</span></strong></span>文件,找出方法表集合所在位置和相应的数据,并辅助<span style="font-family:'Comic Sans MS';"><strong><span>javap -v Inerface </span></strong></span>查看常量池信息,以下图所示: </span><img src="https://img-blog.csdn.net/20141115114030609" alt=""></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 因为<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';color:#FF6600;">sayHello()</span></span>方法是在的<strong><span style="font-family:'Comic Sans MS';">Interface</span></strong>接口类中声明的,它没有被实现,因此它对应的<strong>方法表(<span style="font-family:'Comic Sans MS';color:#FF6600;">method_info</span>)</strong>结构体中的<strong>属性表集合</strong>中<span style="color:#FF0000;">没有</span><strong>Code类型的属性表</strong>。<br></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">注:</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">1. <strong>方法计数器(<span style="font-family:'Comic Sans MS';color:#FF6600;">methods_count</span>)</strong>中的值为<strong>0x0001</strong>,代表其后的<strong>方法表<span style="font-family:'Comic Sans MS';color:#FF6600;">(method_info</span>)</strong>就一个,即咱们就定义了一个方法,其后会紧跟着一个<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong>方法表<span style="font-family:'Comic Sans MS';color:#FF6600;">(method_info</span>)</strong></span>结构体;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">2. <strong>方法的访问标志(<span style="font-family:'Comic Sans MS';color:#FF6600;">access_flags</span>)</strong>的值是<strong>0x0401</strong>,二进制是<strong>00000100 00000001</strong>,第<strong>6</strong>位和第<strong>16</strong>位是<strong>1</strong>,对应上面的标志位信息,能够得出它的<strong>访问标志符</strong>有:<span style="font-family:'Comic Sans MS';color:#FF6600;"><strong>ACC_ABSTRACT、ACC_PUBLIC</strong></span>。细心的读者可能会发现,在上面声明的<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';color:#FF6600;">sayHello()</span></span></span>方法中并无声明为<span style="font-family:'Comic Sans MS';color:#FF6600;">abstract</span>类型啊。确实如此,这是由于<strong><span style="color:#FF0000;">编译器对于接口内声明的方法自动加上ACC_ABSTRACT标志</span></strong>。</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">3. <strong>名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">name_index</span>)</strong>中的值为<strong>0x0005</strong>,<strong>0x0005</strong>指向了常量池的第<strong>5</strong>项,第五项表示的字符串为“<span style="font-family:'Comic Sans MS';"><strong><span style="color:#000099;">sayHello</span></strong></span>”,即表示的方法名称是<span style="font-family:'Microsoft YaHei';font-size:12px;"><span style="font-family:'Comic Sans MS';"><strong><span style="color:#000099;">sayHello</span></strong></span></span></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">4. <strong>描述符索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">descriptor_index</span>)</strong>中的值为<strong>0x0006</strong>,<strong>0x0006</strong>指向了常量池中的第<strong>6</strong>项,第<strong>6</strong>项表示的字符串为“<strong>()V</strong>” 表示这个方法的无入参,返回值为<strong><span style="font-family:'Comic Sans MS';">void</span></strong>类型</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">5. <strong>属性表计数器(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_count</span>)</strong>中的值为<strong>0x0001</strong>,表示后面的<strong>属性表</strong>的个数就<strong>1</strong>个,后面紧跟着一个<span style="font-family:'Comic Sans MS';"><strong><span style="color:#FF6600;">attribute_info</span></strong></span>结构体;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">6. <strong>属性表(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_info</span>)</strong>中的<strong>属性名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_name_index</span>)</strong>中的值为<strong>0x0007</strong>,<strong>0x0007</strong>指向了常量池中的第<strong>7</strong> 项,第<span style="font-family:'Microsoft YaHei';font-size:12px;"><strong> 7</strong></span>项指向字符串“<span style="font-family:'Comic Sans MS';"><strong><span style="color:#FF6600;">Exceptions</span></strong></span>”,即表示该属性表表示的异常信息;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">7. <strong>属性长度(<span style="font-family:'Comic Sans MS';color:#FF6600;">attribute_length</span>)</strong>中的值为:<strong>0x00000004</strong>,即后续的<strong>4</strong>个字节将会被解析成属性值;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">8. <strong>异常数量(<span style="font-family:'Comic Sans MS';color:#FF6600;">number_of_exceptions</span>)</strong>中的值为<strong>0x0001</strong>,表示这个方法声明抛出的异常个数是<strong>1</strong>个;</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">9.<strong>异常名称索引(<span style="font-family:'Comic Sans MS';color:#FF6600;">exception_index_table</span>)</strong>中的值为<strong>0x0008</strong>,指向了常量池中的第<strong>8</strong>项,第<strong>8</strong>项表示的是<strong><span style="font-family:'Comic Sans MS';">CONSTANT_Class_info</span></strong>类型的常量池项,表示“<span style="font-family:'Comic Sans MS';"><strong><span style="color:#000099;">java/lang/Exception</span></strong></span>”,即表示此方法抛出了<span style="font-family:'Comic Sans MS';"><strong>java.lang.Exception</strong></span>异常。</span></p> <br></blockquote> <br><h3><a name="t7"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">7. IDE代码提示功能实现的基本原理<br></span></h3> <p> <span style="font-family:'Microsoft YaHei';font-size:12px;">如今对于企业级的开发,开发者们愈来愈依赖IDE如Intellij IDEA、Eclipse、MyEclipse、NetBeans等,利用他们提供的高级功能,能够极大地提升编码的速度和效率。</span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> 每一个IDE都提供了代码提示功能,它们实现的基本原理其实就是IDE针对它们项目下的包中全部的class文件进行建模,解析出它们的方法信息,当咱们必定的条件时,IDE会自动地将合适条件的方法列表展现给开发者,供开发者使用。</span></p> <blockquote> <p><img src="https://img-blog.csdn.net/20141117142215355" alt=""></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;">在上面将Code属性表的时候也讲了,若是编译的第三方包,没有LocalVariableTable属性表信息,IDE的提示信息会稍有不一样:</span></p> <p><img src="https://img-blog.csdn.net/20141117142426801" alt=""></p> <p><br></p> <p><br></p> </blockquote> <p></p> <h3><a name="t8"></a><span style="font-family:'Microsoft YaHei';font-size:14px;">8. 写在后面<br></span></h3> <p> <span style="font-family:'Microsoft YaHei';"> <span style="font-size:12px;"> 以上就是Class文件的方法表集合的所有内容。</span></span></p> <p><span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;"> 读者可能以为本文关于方法表的Code属性表讨论的不够深刻,在讨论Code属性表的时候,我简单介绍了它的两个属性表LineNumberTable 和LocalVariableTable这两个在有什么实际做用,可是没有详细第介绍它们,而且在列举的例子中,刻意地使用了 -g:none 选项 ,以使生成的class文件没有这两项信息,这么作是由于Code 属性太过复杂,而本文主要是想让读者了解的是 方法表集合,因此就生成了最精简的Code属性表,以减小读者的负担。</span></span></p> <p><span style="font-family:'Microsoft YaHei';"><span style="font-size:12px;"> <strong><em><span style="color:#000099;">接下来的一篇文章,我打算专门来讨论Code属性表,揭开Code属性表的全部秘密,敬请关注~~</span></em></strong><br></span></span></p> <p><span style="font-size:12px;"><span style="font-family:'Microsoft YaHei';"> 本文还引出了一个须要讨论的话题:就是<span style="color:#000099;"><em><strong>Code属性表中的机器指令</strong></em></span></span></span>,<span style="font-family:'Microsoft YaHei';font-size:12px;">机器指令的运行要依赖于JVM体系结构的设计机制,理解机器指令的运行机制,这将是根很是很是难啃的骨头.......<br></span></p> <p><span style="font-family:'Microsoft YaHei';font-size:12px;"> </span><br></p> <p><br></p> <p><br></p> <blockquote> <p></p> <fieldset><legend>做者给读者的一些建议:</legend> <p><span style="font-family:'Comic Sans MS';">1. 因为class文件的信息繁杂,为了减小class文件的复杂程度,本文列举的例子都是针对特定状况精简的,尽可能减小没必要要的学习障碍,因此做者但愿读者好好研究一下本文所列举的例子,读者最好本身动手,本身编译源代码,生成class文件,并查看class文件中的信息,而后逐字节分析,若是你真这么作了,你会发现,class文件的组织格式原来真的很简单..</span></p> <p><span style="font-family:'Comic Sans MS';">2. 阅读了本文,并不能保证让你彻底、系统地掌握class文件组织形式。若是你想全面系统地掌握它,你还须要阅读:</span><br></p> <p> <em> <a href="http://download.csdn.net/detail/u010349169/7439669" rel="nofollow" data-token="b4592b628b95b59a3c3c9ba19ee1a97d"> 《Java Vritual Machine Specification _J2SE 7》(Java虚拟机规范 Java SE7 版)(可点击下载)</a></em></p> <p> <em> 《<a href="http://download.csdn.net/detail/u010349169/8168053" rel="nofollow" data-token="da7ca14ca8a1ce88344c21b7af819f85">深刻理解Java虚拟机:JVM高级特性与最佳实践》,周志明(可点击下载)</a></em></p> <p> 这两本书很系统地介绍了class文件的组织形式,若是你以为这两本书中有的部分将的太抽象,很差理解,那么你再回头看看本文,本文能给你一个形象化和直观化的解释。</p> <p><br></p> <p>衷心但愿《Java虚拟机原理图解》这个专栏可以帮助到广大的Java 程序员们!</p> </fieldset><p></p> </blockquote> </div> 本文源自 http://blog.csdn.net/luanlouis/java