Java字節(jié)碼深入解析
一:Java字節(jié)代碼的組織形式
類文件{
OxCAFEBABE,小版本號,大版本號,常量池大小,常量池數(shù)組,訪問控制標(biāo)記,當(dāng)前類信息,父類信息,實現(xiàn)的接口個數(shù),實現(xiàn)的接口信息數(shù)組,域個數(shù),域信息數(shù)組,方法個數(shù),方法信息數(shù)組,屬性個數(shù),屬性信息數(shù)組
}
二:查看方法 --- javap命令
例子:有一個Java類Demo.java
通過jdk自帶的反編譯工具命令 javap 可以查看class文件的字節(jié)碼信息
D:\>javap -verbose Demo >> Demo.txt |
Demo.txt:
解析:
1、版本號 major version: 49 //java版本 jdk1.6顯示的是50, jdk1.5顯示的是49,jdk1.4顯示的是58 , 高版本能執(zhí)行低版本的class文件
2、常量池Constant pool
Method:方法
Field:字段
String:字符串
Asciz:簽名如<init>由jvm調(diào)用,其他是不能夠去調(diào)用它的
NameAndType:變量名的類型
Class:類
通過字節(jié)碼,我們可以看到Demo類 繼承于java.lang.Object,如果類中沒有顯式聲明構(gòu)造函數(shù)的話,編譯器會插入一個缺省無參的構(gòu)造函數(shù)(構(gòu)造函數(shù)在JVM級別是顯示成<init>的普通函數(shù))。
三:檢測代碼的效率問題
學(xué)習(xí)Java的過程中,都會了解到字符串合并時要用到StringBuffer 來代替String,那下面就來通過Java字節(jié)碼來驗證兩種方式的效率性。
例子:一個Java類 TestString.java
javap –c TestString 后字節(jié)碼信息:
從上面編譯后的字節(jié)碼信息可以看出來,方法testString 調(diào)用了五個方法:new 、invokestatic 、invokespecial 和兩個invokevirtual ; 而testStringBuffer 方法只調(diào)用了兩個invokevirtual 方法。第一個方法比第二個方法多做了好多工作,其效率當(dāng)然是要低的。而且我們從java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
可以看出來其實對于String字符串合并,內(nèi)部還是轉(zhuǎn)化為StringBuilder的方法調(diào)用,這是因為String是長度不可變的,所以不如直接采用StringBuilder(與StringBuffer 長度都是可變的,只不過前者是非線程安全,后者是線程安全)進(jìn)行字符串合并。