2014年3月25日 星期二

Java 複習筆記 : 變數與記憶體

一個 Java 程式中宣告的變數有四種, 配置於記憶體中的位置與時機不同, 存活時間也不同. 一般作業系統將程式載入記憶體準備執行時, 通常為此程式配置三種不同的儲存區域, 即程式碼區, Global 區 (儲存靜態變數與函式), 與動態區 (儲存程式碼執行時的動態資料). Java 的記憶體配置區域如下圖所示 :

 

靜態變數與方法在編譯完成後即存在 global 區 (靜態區), stack 區存放一般方法, 以及執行時期方法所用到之參數與區域變數; 而 heap 區則存放執行時期的實體物件與實體變數.

Java 的變數依照其存活時間長短分成下列四種 :

1. 類別變數 : 

又稱為靜態變數, 因為它必須在類別成員區宣告為 static (也只能在類別成員區有 static), 例如 :

static int count=0;

其特性如下 :
  1. 存活時間最長, 編譯時即配置記憶體存放於 global 區 (即靜態區, 靜態方法也在此區), 程式執行期間均可存取. 
  2. 直接用類別名稱存取, 即 : 類別名稱.變數名稱, 且為該類別全部實體所共用 (即共同變數).
  3. 可以加存取修飾子 : public, protected, private.
  4. 有預設值, 如果沒有初始化, 編譯器也會給予預設值如下 :



2. 實體變數 :

又稱為物件變數, 或物件的屬性, 係類別成員中沒有 static宣告之變數. 其特性如下 :

  1. 存活時間第二長, 於物件建立時產生, 存放於 heap 區, 只要物件未消滅皆可存取.
  2. 必須以物件實體名稱存取, 即 : 物件名稱.變數名稱, 同類別之不同實體有各自屬性 (不共用).
  3. 可以加存取修飾子 : public, protected, private.
  4. 有預設值, 如果沒有初始化, 編譯器也會給予預設值, 與類別變數相同.
3. 方法變數 :

此為方法中的小括弧 (參數) 以及大括弧 (內容) 中所用到的變數, 是兩種區域變數之一 (另一種為區塊變數). 其特性如下 :
  1. 存活期間最短, 僅在該方法被呼叫時存在, 配置於 statck 區 (LIFO), 方法執行完畢即消滅, 還給作業系統. 
  2. 只能在方法內部直接存取, 故不可以加任何存取修飾子 (即外部無法存取).
  3. 無預設值, 存取前必須先初始化 (賦值), 否則會編譯失敗. 方法之參數因為是外部傳入 Literal (相當於初始化), 因此可以直接使用.

4. 區塊變數 :

即 if, switch, for, while, do-while 等流程控制語法大括弧內所定義之變數, 是兩種區域變數之一, 其特性如下 :
  1. 存活期間最短, 僅在進入該區塊執行時才存在, 配置於 statck 區 (FILO), 離開該區塊時即消滅, 還給作業系統.
  2. 只能在區塊內部存取, 故不可以加任何存取修飾子 (區塊外部無法存取).
  3. 無預設值, 存取前必須先初始化 (賦值), 否則會編譯失敗. 

總之, 區域變數 (方法變數, 區塊變數) 是放在 stack 區, 執行時期動態生滅; 靜態變數放在 global 區, 編譯成功時即存在, 程式結束時消滅; 實體變數放在 heap 區, 隨實體存亡而生滅.

4 則留言 :

Matt 提到...

Stack 區應該是 LIFO 喔,您應該是筆誤了。

小狐狸事務所 提到...

感謝您, 我已更正了.

匿名 提到...

請問區塊變數的部份,除了流程控制語法大括弧內所定義之變數之外,如果是{}內所產生的變數,也是屬於區塊變數嗎?

小狐狸事務所 提到...

嗨, 是的, 在 Java 9 之後, 除了分支與迴圈的大括號外, 單純的 {} 內之變數也是區域變數.