深入理解JAVA虛擬機器——JVM的資料型別(以及按引用傳遞法則)
Java虛擬機器是通過某些資料型別來執行計算的,資料型別可以分為兩種:基本型別和引用型別,基本型別的變數持有原始值,而引用型別的變數持有引用值。
Java語言中的所有基本型別同樣也都是Java虛擬機器中的基本型別。但是boolean有點特別,雖然Java虛擬機器也把boolean看做基本型別,但是指令集對boolean只有很有限的支援,當編譯器把Java原始碼編譯為位元組碼時,它會用int或者byte來表示boolean。在Java虛擬機器中,false是由整數零來表示的,所有非零整數都表示true,涉及boolean值的操作則會使用int。另外,boolean陣列是當做byte陣列來訪問的,但是在“堆”區,它也可以被表示為位域
Java虛擬機器還有一個只在內部使用的基本型別:returnAddress,Java程式設計師不能使用這個型別,這個基本型別被用來實現Java程式中的finally子句。該型別是jsr, ret以及jsr_w指令需要使用到的,它的值是JVM指令的操作碼的指標。returnAddress型別不是簡單意義上的數值,不屬於任何一種基本型別,並且它的值是不能被執行中的程式所修改的。
Java虛擬機器的引用型別被統稱為“引用(reference)”,有三種引用型別:類型別、介面型別、以及陣列型別,它們的值都是對動態建立物件的引用。類型別的值是對類例項的引用;陣列型別的值是對陣列物件的引用,在Java虛擬機器中,陣列是個真正的物件
深入理解引用型別在Java中的使用
public class User {
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
public class Test { public void set(User user){ user.setName("hello world"); } public static void main(String[] args) { Test test = new Test(); User user = new User(); test.set(user); System.out.println(user.getName()); } }
上面程式碼的輸出結果是“hello world”,這不必多說,那如果將set方法改為如下,結果會是多少呢?
public void set(User user){
user.setName("hello world");
user = new User();
user.setName("change");
}
答案依然是“hello world”,下面就讓我們來分析一下如上程式碼。
首先
User user = new User();
是在堆中建立了一個物件,並在棧中建立了一個引用,此引用指向該物件,如下圖:test.set(user);
是將引用user作為引數傳遞到set方法,實際上專業操作名稱就是:按引用傳遞,注意:這裡傳遞的並不是引用本身,而是一個引用的拷貝。也就是說這時有兩個引用(引用和引用的拷貝)同時指向堆中的物件,如下圖:
user.setName("hello world");
在set()方法中,“user引用的拷貝”操作堆中的User物件,給name屬性設定字串"hello world"。如下圖:user = new User();
在set()方法中,又建立了一個User物件,並將“user引用的拷貝”指向這個在堆中新建立的物件,如下圖:
user.setName("change");
在set()方法中,“user引用的拷貝”操作的是堆中新建立的User物件。
set()方法執行完畢,目光再回到mian()方法
System.out.println(user.getName());
因為之前,"user引用的拷貝"已經將堆中的User物件的name屬性設定為了"hello world",所以當main()方法中的user呼叫getName()時,列印的結果就是"hello world"。如下圖: