天天看點

Java 基礎 - 數組

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