Java 基礎 - 數組
目錄
初識數組
數組的初始化
定義數組變量
初始化
靜态初始化
動态初始化
數組的通路
數組元素讀取、指派
數組的周遊
for 循環
foreach循環
深入了解數組
JDK 中的 Array
數組的記憶體分布
多元數組
數組是程式設計語言中最常見的一種資料結構,可以用于儲存多個資料,通常可通過數組元素的索引來通路數組元素,包括數組元素指派和取出數組元素的值.
數組也是一種類型,屬于引用資料類型.
數組元素的類型是唯一的,一個數組裡隻能存儲一種類型的資料.
數組的長度是固定的,即一個數組一單初始化完成,數組在記憶體中所占的空間将被固定下來,長度不在發生改變.即使把某個數組的元素清空,其所占的空間依然被保留.
Java支援兩種文法格式定義數組:
type[] arr; type arr[];
對于這兩種定義而言,通常使用第一種格式來定義數組,因為第一種有更好的語義.第二種容易和變量名混淆
Java 數組隻有初始化之後才能使用,所謂的初始化,就是為數組的元素配置設定記憶體空間.并為每個數組元素賦初始值.
由程式員顯示的指定每個數組原始的初始值.由系統決定數組的長度.
靜态初始化的文法格式為:
type[] arr = new type[]{item1, item2, item3,...};
type 為數組元素的資料類型, 數組元素類型必須為 type 類型,或者其子類的執行個體.
除此之外,靜态初始化還有如下簡化的文法格式:
type[] arr = {item1, item2, item3 ...};
動态初始化隻指定數組的長度,由系統為每個元素指定初始值,動态初始化的文法格式如下:
type[] arr = new type[length];
上面的文法中,需要指定一個 int 類型的 length 參數,這個參數指定了數組的長度.
執行動态初始化時,程式員隻指定數組的長度,數組元素的初始值由系統按照如下自動配置設定
數組元素類型是基本類型中的整數類型(byte, short, int, long),則數組元素的值是 0.
數組元素類型是基本類型中的浮點類型(float, double),則數組元素的值是 0.0.
數組元素類型是基本類型中的字元類型(char),則數組元素的值是'u0000'.
數組元素的類型是基本類型中的布爾類型(boolean),則數組元素的值是 false.
數組元素的類型是引用類型(類,接口,數組),則數組元素的值是 null;
數組最常用的方法就是通路數組元素,包括對數組元素進行指派和取出數組元素.
int[] arr = {1,2,3}; // 數組取值 通過 arr[index] 通路 int a = arr[0]; // arr 為{1,3,3} arr[1] = 3
如果通路數組元素時指定的索引值小于0,或者大于等于數組的長度,編譯程式時不會出現任何錯誤,但運作時出現異常java.lang.ArrayIndexOutOfBoundsException:N(數組越界異常), N 就是試圖通路的數組索引.
for 循環
int[] arr = new int[5]; // 輸出 5 個 0 for(int i = 0; i < arr.length; i++){ System.out.println(arr[i]) } arr[1] = 1; arr[2 = 2; // 輸出 0 1 2 0 0 for(int i = 0; i < arr.length; i++){ System.out.println(arr[i]) }
上面的代碼第一次循環輸出 5 個 0,因為 arr 數組執行的是預設初始化,數組元素是 int 類型,系統為 int 類型的數組元素初始化指派為 0.
Java5 之後,Java 提供了一種更簡單的循環:foreach循環,這種循環周遊數組和集合更加友善.
for (type item : array|collection){ // }
使用foreach循環需要注意:
int[] arr = {1, 2, 3, 4, 5}; for (int item: arr){ System.out.println(item); item = 0; System.out.println(item); } System.out.println(arr[0]);
上例程式将輸出
1 0 2 0 3 0 4 0 5 0 1
由輸出結果可以看出來,在 foreach循環中對數組元素進行指派,結果導緻不能正确的周遊數組元素.同時在循環中為改變的數組元素的值并沒有真正改變數組元素,因為在 foreach中循環變量相當于一個臨時變量,系統會把數組元素一次指派給這個臨時變量,而這個臨時變量并不是數組元素,它隻是儲存了數組元素的值.是以要注意:如果希望改變數組元素的值,則不能使用這種 foreach 循環.
JDK 中的 Array
檢視 Java源碼中的Array類可以發現它是個 final class, 其中方法如下:
Array類中基本都是 getXX 和 setXX 方法,
并且全部都為 native 方法.使用 native關鍵字說明這個方法是原生函數,也就是這個方法是用C/C++語言實作的,并且被編譯成了DLL,由java去調用,是以我們可以将數組了解為是由計算機本地方法去實作的類,并不屬于 Java.
數組是一種引用資料類型,數組的引用變量時存儲在棧記憶體中的,而數組元素是在堆記憶體中,并且是連續存放的.這是為了能快速存取數組元素,因為隻需要移動index(内部計算實體位址:數組起始位址+index * 元素size大小)就可以通路,而這是很快的 O(1)。
在Java 記憶體模型中,數組對象被存儲在堆(heap)記憶體中;如果引用該數組對象的變量是一個局部變量,那麼它被存儲在棧(stack)記憶體中.如下圖所示:
如果需要通路上圖堆記憶體中的數組元素,在程式中隻能通過 p[index]的形式實作.也就是說,數組引用變量時通路堆記憶體中數組元素的根本方式.
現有如下代碼:
// 定義并靜态初始化數組 int[] a = {5, 7, 20}; // 定義數組,使用動态初始化 int[] b = new int[4]; System.out.println("b 數組的長度為: " + b.length); // 循環輸出 a 數組的元素 for (int i = 0, len = a.length; i < len; i++ ){ System.out.println(a[i]); } // 循環輸出 b 數組的元素 for (int i = 0, len = b.length; i < len; i++ ){ System.out.println(b[i]); } // 将 a 的值賦給 b,即将 b 的引用指向 a 引用指向的數組 b = a; // 再次輸出 b 數組的長度 System.out.println("b 數組的長度為: " + b.length);
運作上例代碼,首先會輸出 b 的長度為 4,然後輸出 a,b 的各項元素,接着輸出 b 的長度為 3.看起來數組的長度是可變的,其實這是一個假象.
上例代碼記憶體分析:
初始化 a,b 數組,在記憶體中産生了 4 塊區域,棧中的引用變量 a,b 以及堆中的實際數組對象. 其中 a 引用的數組對象長度為 3, b 引用的數組長度為 4.
程式執行b = a 操作.系統會将 a 的值賦給 b,即将 a 引用的數組對象的記憶體位址賦給 b,此時 b 的值為 a 引用的數組對象的記憶體位址.
從上可以看出,程式執行 b = a 之後,b 之前引用的數組對象長度并沒有發生任何改變,而 b 的值變成了 a 引用的數組對象的位址,此時 b 數組的長度即為 a 數組的長度 3.
需要注意的是數組元素的記憶體空間是連續的,是指
如果數組元素是原始類型,那麼數組元素存放的就是原始類型的值,他們是連續存放的
如果數組元素是對象,那麼數組元素就是存放引用了,數組元素是連續存放的,而引用的對象可能在另外的地方,與數組元素可能相隔很遠,即不連續。
Java 提供了支援多元數組的文法,但是從數組底層的運作機制上來看,并不存在多元數組.
多元數組的定語文法為
type[][] arr = new typelength1
length2可動态建立.
二維數組本質就是一位數組中的每個元素都是一個一維數組. 如上length2給出了值,則初始化了一維數組中的每個元素都是一個長度為length2的一維數組.其記憶體模型為:
EOF
本文作者:陳建源
本文連結:
https://www.cnblogs.com/41uLove/p/12571808.html