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