Java支持兩種語法格式定義數組: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 參數,這個參數指定了數組的長度.
執行動態初始化時,程序員只指定數組的長度,數組元素的初始值由系統按照以下自動分配函數
數組最經常使用的方法就是訪問數組元素,包括對數組元素進行賦值和取出數組元素.3d
int[] arr = {1,2,3}; // 數組取值 經過 arr[index] 訪問 int a = arr[0]; // arr 爲{1,3,3} arr[1] = 3
若是訪問數組元素時指定的索引值小於0,或者大於等於數組的長度,編譯程序時不會出現任何錯誤,但運行時出現異常java.lang.ArrayIndexOutOfBoundsException:N
(數組越界異常), N
就是試圖訪問的數組索引.code
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.對象
foreach
循環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 循環
.
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 type[length1][length2]
length2
可動態建立.
二維數組本質就是一位數組中的每一個元素都是一個一維數組. 如上length2
給出了值,則初始化了一維數組中的每一個元素都是一個長度爲length2
的一維數組.其內存模型爲: