目錄結構:
1,一維數組
1.1 什么是一維數組
一維數組就是在內存連續分配的一段存儲空間。
1.2 聲明一維數組的三種方式
第一種:在聲明的時候賦值
數據類型 [] 數組變量名稱 ={初始值1,初始值2,初始值3,.......};
第二種:直接聲明不賦值
數據類型 [] 數據變量名 = new 數據類型[數組長度];
第三種:由第二種演變而來,(不推薦使用這種方式,推薦使用第二種方式)
數據類型 數據變量名 [] =new 數據類型[數組長度];
2,二維數組
2.1 什么是二維數組
二維數據就是使用一維數組組成的數據,其元素是一維數組。
2.2 聲明二維數組的三種方式
第一種:聲明的時候直接賦值
數據類型 [][] 數據變量名 = {{初始值11,初始值12,初始值13,......},{初始值21,初始值22,初始值23,......},{初始值31,初始值32,初始值33,......},......};
第二種:直接聲明不賦值
數據類型 [][] 數據變量名 =new 數據類型 [行數][列數];
例如:int [][] arr=new int [3][2];//創建一個3行,2列的二維數組
第三種:先聲明行,再聲明列
數據類型 [][]數據變量名= new 數據類型 [行數][];
數據變量名 [行數] = new 數據類型[列數];
例如:
int [][] arr= new int[3][];//創建一個二維數組,指定為3行
arr[0]=new int[2];//第一行指定為2列
arr[1]=new int[3];//第二行指定為3列
arr[2]=new int[4];//第三行指定為4列
2.3 二維數組的使用示例
接下來我們來看一個遍歷二維數組的代碼:
int [][] arr=new int[4][];//聲明一個二維數組,指定為4行 arr[0]=new int[2];//第1行,聲明為2列 arr[1]=new int[3];//第2行,聲明為3列 arr[2]=new int[4];//第3行,聲明為4列 arr[3]=new int[5];//第4行,聲明為5列 for(int row=0;row<arr.length;row++){//arr.length 代表總的行數 for(int column=0;column<arr[row].length;column++){// arr[row]代表第row+1行,因此 arr[row].length代表第row行的列數 System.out.print(arr[row][column]); } System.out.println(); }
從中我們可以看出其中:
arr -- 代表arr二維數組
arr[n] -- 代表二維數組的第n+1行,也就是1個一維數組
arr[n][m] -- 代表二維數組中某一個具體的元素
3,數組在內存空間中的分配情況
一位數組就是在內存中連續分配的一段內存空間,數組名稱代表這個容器的地址。
二維數組就是一維數組組成的一維數組,所以二維數組的在內存中的表示方式應該是和一維數組類似:
上面圖形的表示的二維數組可以聲明為以下格式:
int [][] Arrays={{11,12,13},{14,15},{16}};
也就是一共三行,第一行三個數據,第二行兩個數據,第三行一個數據。
4,各種數據類型在聲明完畢后的默認初始值
我在Java中使用數組聲明完畢后(如:int [] arr=new int[3];),會自動賦上默認值。數據類型一共分為兩大類,基本數據類型和引用數據類型。
其中基本數據類型:
byte/short/int/long 的默認數組是0
float/double 的默認值是0.0
char 的默認值\u0000
boolean 的默認值是false
這里需要注意char數組的默認值是空格而不是0,因為十進制0在ASCII中恰好對應空字符。
5,解析數組中的length屬性
不知道讀者有沒有注意到,java中的數組獲取長度是采用length屬性,而並非是用length()函數。首先讀者需要明白,一個對象里的內容只包括了屬性,並沒有方法。換句話說,在堆區中只會為屬性分配內存空間,並不會為方法分配空間,那么方法是怎么和對象聯系起來的呢?其實方法就是一個盒子,這個盒子在棧區中起作用,也就是通常所說的壓棧和出棧過程。在編譯類文件的時候,類加載器加載類文件的時候就把對象和方法聯系起來了!通過下面的閱讀,讀者將會知道數組的長度屬性是由JVM執行的,這也恰好符合了數組length屬性的叫法!
5.1 java中的數組是對象嗎
首先可以肯定java中的數組是對象,詳見java中的數組是對象嗎
5.2 創建的數組對象的類在哪里
我們通過以下程序找出數組對象的類:
int a[] = new int[10]; Class clazz = a.getClass(); System.out.println(clazz.getDeclaredFields().length); System.out.println(clazz.getDeclaredMethods().length); System.out.println(clazz.getDeclaredConstructors().length); System.out.println(clazz.getDeclaredAnnotations().length); System.out.println(clazz.getDeclaredClasses().length); System.out.println(clazz.getSuperclass());
System.out.println(clazz.getName());
以上代碼的輸出為:
0 0 0 0 0 class java.lang.Object
[I
從以上的代碼我們可以看出,一維數組的數組類沒有屬性、沒有方法、沒有構造方法、沒有注釋,一維數組直接繼承於java.lang.Object,一維數組的類名是[I(其實一個[字符代表一維數組的名稱,兩個[代表二維數組的名稱,三個[字符代表三維數組的名稱,.............)。
5.3 java數組中.length屬性的來源
這就比較奇怪了,既然數組類沒有屬性和方法,那么為什么可以調用.length而不報錯,在查閱了JVM技術文檔后在5.3.3. Creating Array Classes得出了數據類的創建來源:
“The Java Virtual Machine creates a new array class with the indicated component type and number of dimensions”,大致意思就是“Java虛擬機會據元素類型和維度,創建相應的數組類。”。
JVM不把數組類放到任何包中,也不給他們起個合法的標識符名稱,估計是為了避免和JDK、第三方及用戶自定義的類發生沖突吧。
現在我們知道了數組類的來源,但是為什么數組類沒有任何屬性和方法,但是卻可以調用.length卻可以不報錯,然后我們來看一看一個簡單文件的字節碼文件:
public class Main { public static void main(String[] args) { int a[] = new int[2]; int i = a.length; } }
用jclasslib打開我們可以得出:
0 iconst_2 //將int型常量2壓入操作數棧 1 newarray 10 (int) //將2彈出操作數棧,作為長度,創建一個元素類型為int, 維度為1的數組,並將數組的引用壓入操作數棧 3 astore_1 //將數組的引用從操作數棧中彈出,保存在索引為1的局部變量(即a)中 4 aload_1 //將索引為1的局部變量(即a)壓入操作數棧 5 arraylength //從操作數棧彈出數組引用(即a),並獲取其長度(JVM負責實現如何獲取),並將長度壓入操作數棧 6 istore_2 //將數組長度從操作數棧彈出,保存在索引為2的局部變量(即i)中 7 return //main方法返回
可見,在這段字節碼中,根本就沒有看見length這個成員變量,獲取數組長度是由一條特定的指令arraylength實現。編譯器對Array.length這樣的語法做了特殊處理,直接編譯成了arraylength指令。另外,JVM創建數組類,應該就是由newarray這條指令觸發的了。相關字節碼命令可以查看:java bytecode instrcution listings
6,參考文章