課程鏈接:黑馬程序員java零基礎[上]
1.二維數組的內存分布
在 Java 中,二維數組并不是一整塊連續的二維空間,而是數組的數組。具體而言,在聲明一個二維數組:如int[][] arr = new int[2][3];
時,內存中會發生如下:
1.1 棧上的引用變量
首先,在棧內存中,JVM(java虛擬機) 會創建一個名為 arr 的引用變量。它不存實際數據,只是指向堆上的數組對象。
1.2 堆上的頂層數組
在 Java 中,所有通過 new
創建的對象,包括數組,都是在堆內存中分配的。對于二維數組,JVM 會先在堆上創建一個長度為 2 的一維數組:
- 這個數組的特殊之處在于,它的元素類型是 int[],也就是“一維整型數組的引用”。
- 棧上的 arr 就指向這個一維數組的首地址。
1.3 行數組與元素
接下來,JVM 會為每一行分別創建一個長度為 3 的 一維數組對象:
-
arr[0] 指向第一行數組,內部存放 arr[0][0]、arr[0][1]、arr[0][2]的值(默認初始化為 0)。
-
arr[1] 指向第二行數組,內部存放第二行的數據,依此類推。
注意: -
每一行數組內部的元素是連續存放的。
-
不同的行在堆上可能不連續。
1.4 訪問數組元素
訪問數組時遵循“先行后列”的邏輯:
-
arr[i] → 找到第 i 行數組的引用。
-
arr[i][j] → 在該行數組里找到第 j 個元素。
所以,二維數組本質上是數組的數組:外層數組管理“行”,內層數組存數據。
2.二維數組的特殊寫法
二維數組除了標準寫法和簡化寫法外還存在更靈活的用法。
2.1交錯數組:
標準的二維數組每一行的列數都是相同的,但在實際應用中,每一行的元素個數可以不同。
實現方式:
在初始化二維數組時,只指定其“行數”(即頂層數組的長度),而暫時不指定“列數”。
// 1. 只定義行數,此時 arr[0], arr[1] 都還是 null
int[][] arr = new int[2][]; // 需要定義數組后再手動創建該二位數組下的2個一維數組
int[] arr0 = {11, 22};
int[] arr1 = {11, 22, 33};
// 2. 手動為每一行分別創建不同長度的一維數組
arr[0] = arr0;
arr[1] = arr1;
此時堆內存和棧內存中的分布為:
優點:
這種寫法的最大優點是高度的靈活性。它允許我們根據實際需求精確控制每一行數組的長度,從而有效節約內存空間,避免為不存在的元素分配內存。
2.2行引用的重新賦值:
既然二維數組的每一行本身就是一個獨立的數組引用,那么我們就可以將這個引用指向任何其他兼容的一維數組對象。
實現方式:
先創建一個標準的二維數組,然后再用其他已經存在的一維數組引用來“覆蓋”或“替換”它的某幾行。
int[][] arr = new int[2][3];
int[] arr1 = {11, 22};
int[] arr2 = {33, 44, 55};arr[0] = arr1;
arr[1] = arr[2];
此時堆內存和棧內存中的分布為:
優點:
這種寫法展示了 Java 引用的強大之處。它不是用新數組的“值”去覆蓋原數組,而是直接替換“行”的引用,將二維數組的某一行與一個獨立的一維數組關聯起來。原本不再被引用的行數組會由 GC 自動回收,無需手動管理內存。