Java基本資料型別以及由不可變類帶來的值傳遞和引用傳遞的難點分析
一、Java提供的資料型別
Java提供了8中原始的資料型別(byte,short,int,long,float,double,char,boolean),這些資料型別不是物件,相應的變數被定義後會立刻在棧上被分配記憶體空間。除此之外的資料型別,都是引用型別,引用型別在變數被宣告時不會被分配記憶體空間,只是儲存了一個記憶體地址而已。其實嚴格意義上講,Java在8中資料型別外還提供了一種基本資料型別void,也有對應的封裝類java.lang.void,只是無法直接對它進行操作。
1位元組 |
2位元組 |
4位元組 |
8位元組 |
---|---|---|---|
byte |
short |
int |
long |
boolean |
char |
float |
double |
引申:Java中的null是什麼?
null不是一個合法的Object例項,它僅僅表明該引用型別目前沒有指向任何物件,所以編輯器沒有分配記憶體。與C語言一樣,null是將引用變數的值置為0。
二、有關不可變類的理解
不可變類(immutable class)是指當建立了這個類的例項後,就不允許修改它的值了,也就是說一個物件被建立以後,在整個生命週期內,它的成員變數就不能被修改了。有點類似與常量(const)不允許別的程式進行修改。
Java類庫中,所有基本型別的包裝類都是不可變類(Byte、Boolean、Short、Char、Integer、Float、Long、Double),此外String也是不可變類。
那麼疑問來了,如下程式碼如何解釋:
String s = "Hello";
s += " World";
System.out.println(s);
執行結果是:Hello World
其實程式是在執行 s += " World" 時建立了一個新的物件"Hello World",s指向了這個新建的物件。原來的"Hello"字串常量在記憶體中並沒有被改變。
如此一來,下面的程式也就容易解釋了。
public class Test{ public static void changeStringBuffer(StringBuffer ssb1,StringBuffer ssb2){ ssb1.append("world"); ssb2 = ssb1; } public static void main(String[] args) { Integer a = 1; Integer b = a; b++; System.out.println(a); System.out.println(b); StringBuffer sb1 = new StringBuffer("Hello sb1"); StringBuffer sb2 = new StringBuffer("hello sb2"); changeStringBuffer(sb1, sb2); System.out.println(sb1); System.out.println(sb2); } }
執行結果:
結果分析:
上面程式執行完 b++後,由於Integer是不可變類,因此會建立一個新值為2的Integer賦值給b,此時b和a已經沒有任何關係。
對比理解StringBuffer型別的sb1、sb2以及引用傳遞入口的ssb1、ssb2,四者之間的引用關係變化。
呼叫函式前sb1和ssb1同時指向"Hello sb1",sb2和ssb2同時指向"Hello sb2"。呼叫完成後,ssb1改動了二者共同引用的地址空間的值,變為"Hello sb1word",同時ssb2指向了ssb1的引用地址空間,而外部的sb2的引用未受影響,以及sb2引用地址的值沒有變化,故執行結果如結果所示。