本篇文章為大家展示了利用Java 如何訪問(wèn)class文件格式的標(biāo)志信息,內(nèi)容簡(jiǎn)明扼要并且容易理解,絕對(duì)能使你眼前一亮,通過(guò)這篇文章的詳細(xì)介紹希望你能有所收獲。
在商南等地區(qū),都構(gòu)建了全面的區(qū)域性戰(zhàn)略布局,加強(qiáng)發(fā)展的系統(tǒng)性、市場(chǎng)前瞻性、產(chǎn)品創(chuàng)新能力,以專注、極致的服務(wù)理念,為客戶提供網(wǎng)站設(shè)計(jì)、成都網(wǎng)站建設(shè) 網(wǎng)站設(shè)計(jì)制作按需策劃設(shè)計(jì),公司網(wǎng)站建設(shè),企業(yè)網(wǎng)站建設(shè),品牌網(wǎng)站設(shè)計(jì),成都營(yíng)銷網(wǎng)站建設(shè),外貿(mào)網(wǎng)站建設(shè),商南網(wǎng)站建設(shè)費(fèi)用合理。
class文件中的訪問(wèn)標(biāo)志信息
位于常量池下面的2個(gè)字節(jié)是access_flags 。 access_flags 描述的是當(dāng)前類(或者接口)的訪問(wèn)修飾符, 如public, private等, 此外, 這里面還存在一個(gè)標(biāo)志位, 標(biāo)志當(dāng)前的額這個(gè)class描述的是類, 還是接口。access_flags 的信息比較簡(jiǎn)單, 下面列出access_flags 中的各個(gè)標(biāo)志位的信息。本來(lái)寫(xiě)這個(gè)系列博客參考的是《深入java虛擬機(jī)》, 但是這本書(shū)比較老了, 關(guān)于java 5以后的新特性沒(méi)有進(jìn)行解釋,這本書(shū)中指列出了5個(gè)標(biāo)志值, 而最新的JVM規(guī)范是針對(duì)java 7 的, 其中加入了額外的三個(gè)標(biāo)志位。 分別是ACC_SYNTHETIC, ACC_ANNOTATION 和 ACC_ENUM 。
標(biāo)志名 | 標(biāo)志值 | 標(biāo)志含義 | 針對(duì)的對(duì)像 |
ACC_PUBLIC | 0x0001 | public類型 | 所有類型 |
ACC_FINAL | 0x0010 | final類型 | 類 |
ACC_SUPER | 0x0020 | 使用新的invokespecial語(yǔ)義 | 類和接口 |
ACC_INTERFACE | 0x0200 | 接口類型 | 接口 |
ACC_ABSTRACT | 0x0400 | 抽象類型 | 類和接口 |
ACC_SYNTHETIC | 0x1000 | 該類不由用戶代碼生成 | 所有類型 |
ACC_ANNOTATION | 0x2000 | 注解類型 | 注解 |
ACC_ENUM | 0x4000 | 枚舉類型 | 枚舉 |
其他標(biāo)志就不做介紹了, 這些標(biāo)志都很簡(jiǎn)單。 讀者感覺(jué)比較陌生的可能是ACC_SUPER這個(gè)標(biāo)志。 讀者會(huì)想, 類型不能被super關(guān)鍵字修飾啊, 那這個(gè)ACC_SUPER是做什么的呢?表中可以看出, 它的含義是:使用新的invokespecial語(yǔ)義 。 invokespecial是一個(gè)字節(jié)碼指令, 用于調(diào)用一個(gè)方法, 一般情況下, 調(diào)用構(gòu)造方法或者使用super關(guān)鍵字顯示調(diào)用父類的方法時(shí), 會(huì)使用這條字節(jié)碼指令。 這正是ACC_SUPER這個(gè)名字的由來(lái)。 在java 1.2之前, invokespecial對(duì)方法的調(diào)用都是靜態(tài)綁定的, 而ACC_SUPER這個(gè)標(biāo)志位在java 1.2的時(shí)候加入到class文件中, 它為invokespecial這條指令增加了動(dòng)態(tài)綁定的功能。 這里可能有幾個(gè)概念讀者不是很明白, 如靜態(tài)綁定, 動(dòng)態(tài)綁定等, 這些概念會(huì)在以后的博客中詳細(xì)介紹。
還有一點(diǎn)需要說(shuō)明, 既然access_flags 出現(xiàn)在class文件中的類的層面上, 那么它只能描述類型的修飾符, 而不能描述字段或方法的修飾符, 希望讀者不要將這里的access_flags 和后面要介紹的方法表和字段表中的訪問(wèn)修飾符相混淆。
此外, 在Java 5 的中, 引入和注解和枚舉的新特性, 那么可以推測(cè), ACC_ANNOTATION 和 ACC_ENUM是在Java 5版本中加入的。 class文件雖然總體上保持前后一致性, 但他也不是一成不變的, 也會(huì)跟著Java版本的提升而有所改變, 但是總體來(lái)說(shuō), class文件格式還是相對(duì)穩(wěn)定的, 變動(dòng)的地方不是很多。
class文件中的this_class
訪問(wèn)標(biāo)志access_flags 下面的兩個(gè)字節(jié)叫做this_class, 它是對(duì)當(dāng)前類的描述。 它的兩個(gè)字節(jié)的數(shù)據(jù)是對(duì)常量池中的一個(gè)CONSTANT_Class_info數(shù)據(jù)項(xiàng)的一個(gè)索引。 CONSTANT_Class_info在上面的文章中已經(jīng)介紹過(guò)了。 CONSTANT_Class_info中有一個(gè)字段叫做name_index , 指向一個(gè)CONSTANT_Utf8_info , 在這個(gè)CONSTANT_Utf8_info 中存放著當(dāng)前類的全限定名。
如果當(dāng)前類為Person:
package combjpowernodetest; public class Person { int age; int getAge(){ return age; } }
將Person.class反編譯后, 可以在常量池中看到如下兩項(xiàng):
Constant pool: #1 = Class #2 // com/bjpowernode/test/Person #2 = Utf8 com/bjpowernode/test/Person ......... .........
這兩項(xiàng)就是當(dāng)前類的信息。 其中索引為1的CONSTANT_Class_info會(huì)被class文件中的this_class所引用。 下面給出示例圖(其中虛線范圍內(nèi)表示常量池的區(qū)域):
class文件中的super_class
super_class緊跟在this_class之后。 它和this_class一樣是一個(gè)指向常量池?cái)?shù)據(jù)項(xiàng)的索引。 它指向一個(gè)CONSTANT_Class_info, 這個(gè)CONSTANT_Class_info數(shù)據(jù)項(xiàng)描述的是當(dāng)前類的超類的信息。CONSTANT_Class_info中的name_index指向常量池中的一個(gè)CONSTANT_Utf8_info ,CONSTANT_Utf8_info 中存放的是當(dāng)前類的超類的全限定名。 如果沒(méi)有顯式的繼承一個(gè),也就是說(shuō)如果當(dāng)前類是直接繼承Object的, 那么super_class值為0 。 我們?cè)谇懊娴奈恼轮刑岬竭^(guò), 如果一個(gè)索引值為0, 那么就說(shuō)明這個(gè)索引不引用任何常量池中的數(shù)據(jù)項(xiàng), 因?yàn)槌A砍刂械臄?shù)據(jù)項(xiàng)是從1開(kāi)始的。 也就是說(shuō), 如果一個(gè)類的class文件中的super_class為0 , 那么就代表該類直接繼承Object類。
下面以代碼來(lái)說(shuō)明:
package combjpowernodetest; public class Programer extends Person{ Computer computer; public Programer(Computer computer){ thiscomputer = computer; } public void doWork(){ computercalculate(); } }
上面的Programer類繼承自Person類。 那么反編譯Programer .class , 它的常量池中會(huì)存在如下信息:
Constant pool: ......... ......... #3 = Class #4 // com/bjpowernode/test/Person #4 = Utf8 com/bjpowernode/test/Person
這兩項(xiàng)就是當(dāng)前類的父類的信息。 其中索引為3的CONSTANT_Class_info會(huì)被class文件中的super_class引用。 下面給出示例圖(其中虛線范圍內(nèi)表示常量池的區(qū)域):
class文件中的interfaces_count和interfaces
緊接著super_class的是interfaces_count, 表示當(dāng)前類所實(shí)現(xiàn)的接口的數(shù)量或者當(dāng)前接口所繼承的超接口的數(shù)量。 注意, 只有當(dāng)前類直接實(shí)現(xiàn)的接口才會(huì)被統(tǒng)計(jì), 如果當(dāng)前類繼承了另一個(gè)類, 而另一個(gè)類又實(shí)現(xiàn)了一個(gè)接口, 那么這個(gè)接口不會(huì)統(tǒng)計(jì)在當(dāng)前類的interfaces_count中。 在interfaces_count后面是interfaces, 他可以看做是一個(gè)數(shù)組, 其中的每個(gè)數(shù)組項(xiàng)是一個(gè)索引, 指向常量池中的一個(gè)CONSTANT_Class_info, 這個(gè)CONSTANT_Class_info又會(huì)引用常量池中的一個(gè)CONSTANT_Utf8_info , 這個(gè)CONSTANT_Utf8_info 中存放著有當(dāng)前類型直接實(shí)現(xiàn)或繼承的接口的全限定名。 當(dāng)前類型實(shí)現(xiàn)或繼承了幾個(gè)接口, 在interfaces數(shù)組中就會(huì)有幾個(gè)數(shù)項(xiàng)與之相對(duì)應(yīng)。
下面看代碼示例:
package combjpowernodetest; public class Plane implements IFlyable, Cloneable{ @Override public void fly() { } }
Plane類實(shí)現(xiàn)了一個(gè)自定義的IFlyable接口, 還實(shí)現(xiàn)了一個(gè)JDK中的Cloneable接口, 那么它的常量池中會(huì)有如下信息:
Constant pool: ......... ......... #5 = Class #6 // com/bjpowernode/test/IFlyable #6 = Utf8 com/bjpowernode/test/IFlyable #7 = Class #8 // java/lang/Cloneable #8 = Utf8 java/lang/Cloneable ......... .........
這四項(xiàng)數(shù)據(jù)就是當(dāng)前的Plane類所實(shí)現(xiàn)的接口的信息。 第五項(xiàng)和第六項(xiàng)描述了Plane所實(shí)現(xiàn)的IFlyable接口, 第七項(xiàng)和第八項(xiàng)描述了Plane所實(shí)現(xiàn)的接口Cloneable接口。 下面是示意圖(其中虛線范圍內(nèi)表示常量池的區(qū)域):
上述內(nèi)容就是利用Java 如何訪問(wèn)class文件格式的標(biāo)志信息,你們學(xué)到知識(shí)或技能了嗎?如果還想學(xué)到更多技能或者豐富自己的知識(shí)儲(chǔ)備,歡迎關(guān)注創(chuàng)新互聯(lián)行業(yè)資訊頻道。