今天要繼續講到參考類型的資料
如果忘記基本型態的部分可以回前一天看喔!那我們就開始吧!
Human tina;
tina = new Human();
記憶體配置圖:
讓我們來了解一下上面兩段程式碼做了什麼事
程式剛開始執行,記憶體沒有變數,
Human tina;
宣告了一個變數tina,會在stack區切一個參考(reference)大小的空間出來,這個參考(reference)預期會指向Human物件,Java會初始化內容為 null (指到沒有地方)。
tina = new Human();
這個敘述分兩部份看:
第一部份: 關鍵字 new 透過建構子來建構物件,建構出來的物件會放在 Heap 區。
第二部份: 透過指定運算子「=」,把剛剛創造出來的物件在Heap區的起始地址,指定給變數tina。
這就是為什麼,參考型態的類別需要 new 才能使用,如果沒有在Heap區佔有真實物件的資料,那它在Stack區就只是一個參考(reference)而已,而且預設為 null,若存取到 null 的物件變數,會出現NullPointerException 的例外,這也是常見的程式錯誤。
Java並沒有指標(pointer)的概念,在Java稱為『參考(reference)』,為了改善c/c++指標理解、操作不易的問題,全盤捨棄指標改用參考。
字串String可以代表字元的串列,例如 "abc" 就是一個字串類別的實體。
初始化字串:
String類別身為參考資料型態,一樣必須實體化才有資料,而String的實體化方式非常自由。
String str = "abc";
利用兩個雙引號『" "』夾起來的字元就會在Heap初始化物件產生空間,回傳reference給String變數。
字串有一個重要特性:「Immutable」,意即當「字串」 一經生成,便不能改變。
String str = "A";
str += "B";
System.out.println(str); // AB
打印的結果是字串:「AB」,而「AB」就像是由原本的字串:「A」再加上字串:「B」後產生的結果。
但實際上在記憶體中並不是這樣運作的,由於「Java」的字串具有「不可改變」的特性,因此,上述程式片段的執行方式是先產生字串:「A」,然後再產生字串:「B」,經運算後,再產生字串:「AB」,並將「str」指向了「AB」。
換句話說,在上述代碼片段的運算過程中,有三個「字串」被產生,但僅有「AB」被指向,而另外兩字串理論上會被「GC」機制所回收。
所以Java 為了降低「當字串重覆使用」時所消耗的資源成本,「JVM」實作了「字串池」的機制,其會在「Heap」中設置一塊「字串池」的區域,其專門用於存放「字串」,而在字串池裏的這些字串是允許被「重覆取用的」,如下圖
// Literal String
String s1 = "ABC";
String s2 = "ABC";
System.out.println(s1 == s2); // true
但要注意的是,並不是所有被產生的字串都一定會進入「字串池」,實際上只有以「Literal」形式,也就是藉由「雙引號」所產生的字串會被放在「字串池」中
// New String
String s1 = "ABC";
String s3 = new String("ABC");
System.out.println(s1 == s3); // false
字串如果用「new」的方式就不會所儲存的位置就不會在字串池中
所以不建議產生字串的時候用「new」,而是以「Literal」的形式。
上面都是用 == 來比較變數1 與 變數2 的『值』有沒有相等,字串是參考資料型態,變數1及變數1只是存放在Stack區的變數,他們的內容值是真實物件的reference,並不是物件內容
需要比對字串內容值的話,需要的是字串方法: equals()
String a = new String("hello");
String b = new String("hello");
System.out.println(a.equals(b));//true
再幫大家整理一下:
==
基本類型:比較內容值
物件資料類型:物件位址值
equals()
一般物件資料類型:物件位址值
String :比較內容值
今天先到這邊囉~明天再來說明基本型態的包裝類別!