Java記憶體區域分為五個部分
Heap(堆)
:用於存放所有的物件實例和陣列。堆是所有執行緒共享的記憶體區域,並且是Java記憶體管理(垃圾回收)的主要區域。Stack(堆棧)
:每個執行緒都有一個專屬的Java堆棧,用於存儲局部變量、方法參數和執行緒的調用狀態。當方法執行時會自動創建相應的堆棧幀並進行管理。Method Area(方法區)
:也稱為非堆區或永久代(在Java8之前)。存放類別的結構信息、靜態變數、常量池(常量字串、數字)、方法代碼等。Java8之後引入了元數據區(Metaspace)替代了永久代。Program counter register(程式計數器)
:每個執行緒都有自己的程序計數器,用於記錄當前執行的Java字節碼指令的地址。如果是本地方法(native method),這個計數器則會保持未定義狀態。Native Method Stack(本地方法棧)
:支援本地方法執行(通常是C或C++程式碼),與Java堆棧相似,但專門用來處理執行本地方法時所需的數據。(以上內容取自ChatGPT,如有錯誤請包涵)
會特別講一下記憶體相關的原因在於Array
有一部分會跟記憶體有所關聯,所以特別提了一些。
Heap
和Stack
跟Array
相關的有Heap
和Stack
,舉例宣告一個int[] arr = new int[]{1,2,3};
。
Heap
:存放array
的元素:1, 2, 3
。stack
:存放array
聲明的局部變量:arr
。還記得前幾天在terminal
中印出Hello World
的程式碼嗎?
class HelloWorld {
public static void main(String[] args){
long num1 = 20L;
int num2 = (int) num1;
System.out.println(num2);
}
}
HelloWorld
:類(class)
是Java中的核心概念。main()
:程式的入口點。num1
:局部變量。num2
:局部變量。if
、for
所宣告的變量。Array
in the 記憶體先來看陣列在記憶體存放的方式:
int[] arr = new int[]{1,2,3};
int[] arr1 = new int[5];
先來張圖片
靜態
宣告了一個新的array
時,會在stack
中放入宣告的變數名稱arr
。heap
中找了一個位置將所宣告的值
(上面的範例是1,2,3
)放入,並得到一個16進制的位址(I@16b98e56
),stack
中的arr
紀錄的也是這個16進制的位址。index
會從0開始也是由於計算的偏移量從0開始較好計算。動態
宣告了一個新的array
時,會在stack
中放入宣告的變數名稱arr
。heap
中找了一個位置將所宣告的長度
(上面的範例是5
)放入,並得到一個16進制的位址(I@16b12f91
),stack
中的arr
紀錄的也是這個16進制的位址。動態
宣告array
時,所有的值都會先賦值
為初始值
。array
了你的array
(array
in array
)二維array
,可以把它看成是嵌套的的感覺,但是在記憶體中是沒有二維
的概念,指向的依舊是記憶體位址
(16進制的位址)。
宣告的方式
// 靜態宣告
int[][] arr = new int[][] {{1,2,3},{4,5},{6,7,8,9}};
// 動態宣告:這樣宣告時,每一個元素內的長度都固定為5
int[][] arr1 = new int[3][5];
// 動態宣告:這樣宣告時,可以動態設定每一個元素內的長度
String[][] arr2 = new String[5][];
arr2[1] = new String[2];
arr2[1][0] = "helloooooo";
arr2[2] = new String[]{"abc","def","ghi"};
調用
int[][] arr = new int[][] {{1,2,3},{4,5},{6,7,8,9}};
System.out.println(arr[0]); // [I@16b98e56,這是存放在記憶體中arr第一個元素的位址
System.out.println(arr[0][1]); // 2
String[][] arr2 = new String[5][];
System.out.println(arr2[0]); // null,因為未將第一層的陣列給定長度,記憶體中無法得知應該提供多少長度存放,所以不會事先保留空間
System.out.println(arr2[0][0]); // 會報錯,因為第一層已經是null了,表示並沒有這個地方
來個圖片
要小心不可以直接使用=
進行,因為只是指向相同記憶體的位置,改動時會兩個都一起更改。
int[] arr = new int[]{1,2,3};
int[] arr1 = new int[arr.length];
for(int i = 0; i < arr.length; i++) {
arr1[i] = arr[i];
};
這樣才可以完全複製
Java SE API
中也有寫好可以使用的Arrays類
可以使用,位置在java.util.Arrays
異常:
ArrayIndxOutOfBoundsException
:邊界錯誤,當一個array
長度為5時,卻調用了第6個元素,會出現邊界錯誤。
int[] arr = new arr[5];
System.out.println(arr[5]); //ArrayIndxOutOfBoundsException
還記得調用array時是從0開始嗎?所以arr第五個元素是length - 1,會是4
NullPointerException
:空指標例外
或空指針異常
,當二維array
(方便稱呼)的元素未給定長度時,調用會出現空指針異常
的錯誤,因為第二層未給定長度,所以第一層只會紀錄為null
,所以它並沒有再指向記憶體中的任何位址。
int[][] arr = new arr[5][];
System.out.println(arr[0][2]); //NullPointerException