iT邦幫忙

2024 iThome 鐵人賽

DAY 10
0

Java記憶體區域分為五個部分

  1. Heap(堆):用於存放所有的物件實例和陣列。堆是所有執行緒共享的記憶體區域,並且是Java記憶體管理(垃圾回收)的主要區域。
  2. Stack(堆棧):每個執行緒都有一個專屬的Java堆棧,用於存儲局部變量、方法參數和執行緒的調用狀態。當方法執行時會自動創建相應的堆棧幀並進行管理。
  3. Method Area(方法區):也稱為非堆區或永久代(在Java8之前)。存放類別的結構信息、靜態變數、常量池(常量字串、數字)、方法代碼等。Java8之後引入了元數據區(Metaspace)替代了永久代。
  4. Program counter register(程式計數器):每個執行緒都有自己的程序計數器,用於記錄當前執行的Java字節碼指令的地址。如果是本地方法(native method),這個計數器則會保持未定義狀態。
  5. Native Method Stack(本地方法棧):支援本地方法執行(通常是C或C++程式碼),與Java堆棧相似,但專門用來處理執行本地方法時所需的數據。

(以上內容取自ChatGPT,如有錯誤請包涵)
會特別講一下記憶體相關的原因在於Array有一部分會跟記憶體有所關聯,所以特別提了一些。


正片開始

HeapStack

Array相關的有HeapStack,舉例宣告一個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:局部變量。
  • 在作用域內所宣告的變量(變數),也屬於局部變量的一種。如在iffor所宣告的變量。

Array in the 記憶體

先來看陣列在記憶體存放的方式:

int[] arr = new int[]{1,2,3};
int[] arr1 = new int[5];

先來張圖片

https://ithelp.ithome.com.tw/upload/images/20240924/20139160QxsRNfDuWQ.jpg

靜態宣告:

  1. 靜態宣告了一個新的array 時,會在stack 中放入宣告的變數名稱arr
  2. heap 中找了一個位置將所宣告的(上面的範例是1,2,3)放入,並得到一個16進制的位址(I@16b98e56),stack中的arr 紀錄的也是這個16進制的位址。
  3. 而昨天提到的陣列index 會從0開始也是由於計算的偏移量從0開始較好計算。

動態宣告:

  1. 動態宣告了一個新的array 時,會在stack 中放入宣告的變數名稱arr
  2. heap 中找了一個位置將所宣告的長度(上面的範例是5)放入,並得到一個16進制的位址(I@16b12f91),stack中的arr 紀錄的也是這個16進制的位址。
  3. 而昨天提到的動態宣告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了,表示並沒有這個地方

來個圖片

https://ithelp.ithome.com.tw/upload/images/20240924/20139160r5PQ4zc6mu.jpg

https://ithelp.ithome.com.tw/upload/images/20240924/20139160zGnOBswQWa.jpg

https://ithelp.ithome.com.tw/upload/images/20240924/20139160IblaqkPzfe.jpg


陣列複製

要小心不可以直接使用=進行,因為只是指向相同記憶體的位置,改動時會兩個都一起更改。

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

上一篇
Day9-陣列(一)
下一篇
Day11-類(class)
系列文
前端工程師的java學習紀錄13
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言