一Java字節代碼的組織形式
類文件{
OxCAFEBABE小版本號大版本號常量池大小常量池數組訪問控制標記當前類信息父類信息實現的接口個數實現的接口信息數組域個數域信息數組方法個數方法信息數組屬性個數屬性信息數組
}
二查看方法 javap命令
例子有一個Java類Demojava
public class Demo {
private String str;
private String str;
private int num;
private int num;
public static final String STATIC_DATA = hello world;
private void sayHello(){
Systemoutprintln(this is method);
}
private void sayHello(){
Systemoutprintln(this is method);
}
public void sayHello(){
Systemoutprintln(this is method);
}
}
通過jdk自帶的反編譯工具命令 javap 可以查看class文件的字節碼信息
D:\>javap verbose Demo >> Demotxt
Demotxt
Compiled from Demojava
public class Demo extends javalangObject
SourceFile: Demojava
minor version:
major version:
Constant pool:
const # = class #; // Demo
const # = Asciz Demo;
const # = class #; // java/lang/Object
const # = Asciz java/lang/Object;
const # = Asciz str;
const # = Asciz Ljava/lang/String;;
const # = Asciz str;
const # = Asciz num;
const # = Asciz I;
const # = Asciz num;
const # = Asciz STATIC_DATA;
const # = Asciz ConstantValue;
const # = String #; // hello world
const # = Asciz hello world;
const # = Asciz <init>;
const # = Asciz ()V;
const # = Asciz Code;
const # = Method ##; // java/lang/Object<init>:()V
const # = NameAndType #:#;// <init>:()V
const # = Asciz LineNumberTable;
const # = Asciz LocalVariableTable;
const # = Asciz this;
const # = Asciz LDemo;;
const # = Asciz sayHello;
const # = Field ##; // java/lang/Systemout:Ljava/io/PrintStream;
const # = class #; // java/lang/System
const # = Asciz java/lang/System;
const # = NameAndType #:#;// out:Ljava/io/PrintStream;
const # = Asciz out;
const # = Asciz Ljava/io/PrintStream;;
const # = String #; // this is method
const # = Asciz this is method;
const # = Method ##; // java/io/PrintStreamprintln:(Ljava/lang/String;)V
const # = class #; // java/io/PrintStream
const # = Asciz java/io/PrintStream;
const # = NameAndType #:#;// println:(Ljava/lang/String;)V
const # = Asciz println;
const # = Asciz (Ljava/lang/String;)V;
const # = Asciz sayHello;
const # = String #; // this is method
const # = Asciz this is method;
const # = Asciz sayHello;
const # = String #; // this is method
const # = Asciz this is method;
const # = Asciz SourceFile;
const # = Asciz Demojava;
{
public static final javalangString STATIC_DATA;
Constant value: String hello world
public Demo();
Code:
Stack= Locals= Args_size=
: aload_
: invokespecial #; //Method java/lang/Object<init>:()V
: return
LineNumberTable:
line :
LocalVariableTable:
Start Length Slot Name Signature
this LDemo;
public void sayHello();
Code:
Stack= Locals= Args_size=
: getstatic #; //Field java/lang/Systemout:Ljava/io/PrintStream;
: ldc #; //String this is method
: invokevirtual #; //Method java/io/PrintStreamprintln:(Ljava/lang/String;)V
: return
LineNumberTable:
line :
line :
LocalVariableTable:
Start Length Slot Name Signature
this LDemo;
}
解析
版本號 major version //java版本 jdk顯示的是 jdk顯示的是jdk顯示的是 高版本能執行低版本的class文件
常量池Constant pool
Method方法
Field字段
String字符串
Asciz簽名如<init>由jvm調用其他是不能夠去調用它的
NameAndType變量名的類型
Class類
通過字節碼我們可以看到Demo類 繼承於javalangObject如果類中沒有顯式聲明構造函數的話編譯器會插入一個缺省無參的構造函數(構造函數在JVM級別是顯示成<init>的普通函數)
三檢測代碼的效率問題
學習Java的過程中都會了解到字符串合並時要用到StringBuffer 來代替String那下面就來通過Java字節碼來驗證兩種方式的效率性
例子一個Java類 TestStringjava
<strong>public class TestString {
public String testString(String str String str){
return str + str;
}
public String testStringBuffer(StringBuffer sb String str){
return sbappend(str)toString();
}
}
</strong>
javap –c TestString 後字節碼信息
Compiled from TestStringjava
public class TestString extends javalangObject{
public TestString();
Code:
: aload_
: invokespecial #; //Method java/lang/Object<init>:()V
: return
public javalangString testString(javalangString javalangString);
Code:
: new #; //class java/lang/StringBuilder
: dup
: aload_
: invokestatic #; //Method java/lang/StringvalueOf:(Ljava/lang/Object;)Ljava/lang/String;
: invokespecial #; //Method java/lang/StringBuilder<init>:(Ljava/lang/String;)V
: aload_
: invokevirtual #; //Method java/lang/StringBuilderappend:(Ljava/lang/String;)Ljava/lang/StringBuilder;
: invokevirtual #; //Method java/lang/StringBuildertoString:()Ljava/lang/String;
: areturn
public javalangString testStringBuffer(javalangStringBuffer javalangString);
Code:
: aload_
: aload_
: invokevirtual #; //Method java/lang/StringBufferappend:(Ljava/lang/String;)Ljava/lang/StringBuffer;
: invokevirtual #; //Method java/lang/StringBuffertoString:()Ljava/lang/String;
: areturn
}
從上面編譯後的字節碼信息可以看出來方法testString 調用了五個方法new invokestatic invokespecial 和兩個invokevirtual 而testStringBuffer 方法只調用了兩個invokevirtual 方法第一個方法比第二個方法多做了好多工作其效率當然是要低的而且我們從java/lang/StringBuilderappend(Ljava/lang/String)Ljava/lang/StringBuilder
可以看出來其實對於String字符串合並內部還是轉化為StringBuilder的方法調用這是因為String是長度不可變的所以不如直接采用StringBuilder(與StringBuffer 長度都是可變的只不過前者是非線程安全後者是線程安全)進行字符串合並
From:http://tw.wingwit.com/Article/program/Java/hx/201311/26098.html