1. 程式人生 > >Java基本資料型別以及由不可變類帶來的值傳遞和引用傳遞的難點分析

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引用地址的值沒有變化,故執行結果如結果所示。