Java 中的變數 (variable) 有兩種 :
- 基本資料型態 (Primitive Data Types)
- 參考資料型態 (Reference Data Types)
基本資料型態(Primitive Data Types)共有八種
特性是變數值內容直接放在變數內
型態類型 | 關鍵字 | 位元數 | 範圍 |
---|---|---|---|
整數 | byte | 8 | -128 ~ 127 |
整數 | short | 16 | -32768 ~ 32767 |
整數 | int | 32 | -2147483648 ~ 2147483647 |
整數 | long | 64 | -9223372036854775808 ~ 9223372036854775807 |
浮點數 | float | 32 | 依據 IEEE 754 標準 |
浮點數 | double | 64 | 依據 IEEE 754 標準 |
布林值 | boolean | 1 | true, flase |
字元 | char | 16 | '\u0000' - '\uffff' |
* 補充字元型態
由於 Java 支援 Unicode 編碼,因此任何 Unicode 字元都可以當作字元型態的的字面常數。字元型態的字面常數為單引號圍起來的單一字元,或是單引號圍起來,反斜線加上四位的十六位元數字,例如
char a = '\u0061'; // 小寫英文字母 a
char b = '\u0032'; // 阿拉伯數字 2
反斜線加上特定英文小寫字母表示跳脫字元,用來表示一些不可見字元,例如
char c = '\n'; // 換行符號
char d = '\t'; // tab 鍵
參考資料型態(Reference Data Types)
除了 Primitive Data Types 以外都是 Reference Data Types。
- 字串 (String)
- 陣列 (Array)
- 類別物件 (class object)
為什麼叫 Reference ,因為它們都是指向物件的參考,而參考資料型態在執行=
運算式時,並不是複製整個資料,而是複製所指記憶體位置。而記憶體分成為三大區塊 :
Global 全域
主要放 :
- 全域變數(global variable)
- 靜態變數(static variable)。
全域變數(global variable) :
如果一個類別的成員變數有 static 修飾詞時,表示所有此類別的物件可以共享此 static 成員變數,不是每一個類別的物件都有一份各自獨立的成員變數,也因此又稱為全局變數(global variable)
Stack 推疊區
這個區域算是貧民區,必須設初值,另外兩個區 Global 和 Heap 系統會幫你初始化。
Stack 具備全自動化管理區塊,同時又具有存取速度快和管理簡單的特點,但要達到上述特點,代表生命週期可被預期並且按照 LIFO (Last-In-First-Out) 後進先出,也就是越晚產生的越先被回收或銷毀。如果 Stack 區不夠用或是遞回涵式(recursive function)沒寫好,會出現StackOverflowError 。
主要放:
- 基本資料型態(Primitive Data Types)
- 區域變數(local variable)
- 方法的參數(method parameter)
- 方法的回傳位址(method return address)等。
Heap 堆積區
和 Stack 相反, Heap 就放一些生命週期是不可預期,隨著程式執行記憶體越來越少,程式設計師必須自行管理此區的記憶體,但 Java 還是會採用 Garbage Collection (簡稱 GC) 垃圾回收這個機制去清理 Heap 內已經沒有被參考 (Reference) 的資料。若 Heap 區記憶體不夠用,會產生 OutOfMemoryError。
主要放 :
- Objects
- JRE classes
有了記憶體基本觀念後就要來看一下參考資料型態(Reference Data Types)會怎麼放,假設自訂一個類別叫 Animal 。這行 Animal dog = new Animal();
程式要把它拆成兩部分來看,首先是Animal dog
,宣告了一個變數 dog,在 stack 區切一個參考(reference)大小的空間出來,這個參考(reference)預期會指向 Animal 物件,Java 會初始化內容為 null (指到沒有地方)。
再來 dog = new Animal();
,new 透過建構子來建構物件,建構出來的物件放在 Heap 區,並透過指定運算子 =
,把剛剛創造出來的物件在 Heap 區的位置指定給變數 dog。
String
當使用直接初始化創建 String 時,JVM 都會在 Heap 內存中檢查 String。
如果找到具有相同值的 String ,則指向剛剛創建好的新 String,(給它一個 String Pool 比較好理解)。但如果是使用新的構造函數(constructor)創建的(註一),則無論對像是否已經存在於 Heap 中,都將在 Heap 中重新分配新的空間。
由於字串是不可變(immutable)的,因此當你嘗試修改從 String Pool 創建的字串的值時,會從 String Pool 創建新的字串或引用。 String Pool 可幫助 Heap 存得最佳利用,因為在 Heap 上創建的字串越少。越能減少 Garbage Collection 的工作。
註一 : constructor 構造函數,或稱建構子,是一個類別裡用於建立物件的特殊子程式,它能初始化一個新建的物件,並時常會接受參數用以設定實例變數。建構子跟一般的實例方法十分相似;但是與其它方法不同,建構子沒有返回類型,不會被繼承,且不會有範圍修飾詞。建構子的函式名稱一般與它所屬的類別的名稱相同。 它承擔著初始化物件資料成員並建立類不變象的任務;在類不變象無效的時候它會失敗。一個正確編寫的建構子會使它生成的物件保持在一個有效狀態。不可變物件必須在建構子內完成所有初始化。
文章參考 :
String Pool | Java
那些字串二三事
深入理解Java中的不可變物件
基本與參考資料型態差異
Java Heap Space vs Stack