數組
數組的定義
- 數組:相同類型數據的集合 內存是連續的
- 定義方法:
(1)int[] arr={1,2,3,4};
靜態初始化
(2)int[] arr=new int[]{1,2,3,4};
動態初始化
這兩種定義的時候[]
內是不能出現數組長度的
=== 》所以如果要知道數組長度 用數組名.length
求數組長度,其中length
不是方法 是一個屬性
(3)int[] arr=new int[5];
未初始化 只是產生了一段空間
注意: - 數組名裏放的是數組首元素地址 ===》所以arr叫做引用(用來存放數組的地址)
- 下標訪問操作不能超出有效範圍 [0, length - 1] , 如果超出有效範圍, 會出現下標越界異常
java.lang.ArrayIndexOutOfBoundsException
- 當定義好數組之後沒有初始化,數組當中如果是簡單類型默認值爲0 如果是引用類型那麼默認值就是null
數組的遍歷
- for循環
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
- foreach循環
for(表達式1(數組中的變量):表達式2(數組名)){
System.out.print(x+" ");
}
例如
for(int x : arr){
System.out.print(x+" ");
}
數組作爲方法的參數
Java中數組的內存分析
public static void main(String[] args) {
int num = 0;
func(num);
System.out.println("num = " + num);
}
public static void func(int x) {
x = 10;
System.out.println("x = " + x);
}
// 執行結果
x = 10
num = 0
==》形參的改變並不影響實參的值 此時是按值傳參
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println("arr[0] = " + arr[0]);
}
public static void func(int[] a) {
a[0] = 10;
System.out.println("a[0] = " + a[0]);
}
// 執行結果
a[0] = 10
arr[0] = 10
==》此處可發現在函數內部改變參數的值,函數外面也發生了改變
因爲此時的函數名arr是一個引用,此時傳參是按引用傳參
所謂的 “引用” 本質上只是存了一個地址. Java 將數組設定成引用類型, 這樣的話後續進行數組參數傳參, 其實只是將數組的地址傳入到函數形參中. 這樣可以避免對整個數組的拷貝(數組可能比較長, 那麼拷貝開銷就會很大).
Java中數組的存儲
Java中數組在堆上存儲而不在棧上
JVM區域劃分
-
Java虛擬機棧:存放局部變量
-
本地方法棧:存放native方法 底層由C語言或C++實現 速度快
-
程序計數器(PC register):存放下一條要執行的指令
-
堆:放的是對象 通過new關鍵字new出來的
-
方法區: 靜態變量 類的信息
-
常量池:用來存放字符串常量 String str=“hello”;
在JDK1.7之前 常量池在方法區當中
在JDK1.7開始,被挪到堆當中 -
每一個線程都有程序計數器 jvm虛擬機棧和本地方法棧
null 是所有引用類型的初始值 -
數組名.length 字符串名.length()
點號之前如果是null 大概率情況下肯定會出現空指針異常
空指針異常 java.lang.NullPointerException -
System.out.println(Arrays.toString(array)); 將數組以字符串類型輸出 要導入包alt+enter
數組作爲方法的返回值
/** 將數組中每個元素都乘以2* */
public class com {
public static int[] fun(int[] arr){
for (int i = 0; i <4 ; i++) {
arr[i]=arr[i]*2;
}
return arr;
}
public static void main(String[] args) {
int[] arr={1,2,3,4};
int[] arr2=fun(arr);
for (int x:arr2) {
System.out.print(x+" ");
}
}
}
由於數組是引用類型, 返回的時候只是將這個數組的首地址返回給函數調用者, 沒有拷貝數組內容, 從而比較高效.
- 可以通過javap -c進行反彙編
數組的應用
數組拷貝
int[] arr={2,3,4};
int[] arr2=new int[arr.length];
- 拷貝方式1
arraycopy(Object src, int srcPos, Object dest, int destPos, int length)
//將指定源數組中的數組從指定位置複製到目標數組的指定位置。 (原數組,從原數組第幾號下標開始拷,目標數組,放到目標數組第幾號下標,拷貝多長)
需要new才能使用 - 拷貝方式2
arr2=Arrays..copyOf(arr,arr.length);
不需要new 深拷貝 深拷貝的定義見下 - 拷貝方式3
利用for循環拷貝 - 拷貝方式4
原數組名.clone()
用的較少
System.arraycopy
和Arrays..copyOf
的區別和聯繫
查原碼發現
System.arraycopy
是被native底層使用C語言寫的 所以拷貝速度快
Arrays..copyOf
方法內部調用了System.arraycopy()
所以相較於System.arraycopy
速度慢
以上四種拷貝方式對存放簡單類型的數組來講是深拷貝
對存放引用類型的數組來講是淺拷貝
- 深拷貝和淺拷貝
- 深拷貝
修改原有變量不會改變新拷貝的變量 - 淺拷貝
如果是兩個引用同時指向一個對象 那麼通過一個引用修改當前對象的值後 那麼另一個引用也會受到影響 這種拷貝就叫做淺拷貝
- 深拷貝
- 注意
int[] arr={1,2,3};
int[] arr2=arr; 這個不是拷貝
二維數組
int[][] arr={{1,2},{3,4},{5,6}};
int[][] arr=new int[][]{{1,2},{3,4},{5,6}};
int[][] arr=new int[3][2];
不規則的二維數組
int[][] arr=new int[3][];
int[][] arr={{1},{3,4},{5,6}};
-
打印二維數組除了遍歷還可以
System.out.println(Arrays.toString(array));
返回指定數組的內容的字符串表示形式將其打印 -
不規則數組的打印如果用尋常遍歷方式會出現數組越界 所以應將條件改爲
i<arr.length
j<arr[i].length
Arrays工具類的使用
Arrays.equals(arr,arr2);//判斷兩數組是否相同
Arrays.fill(arr,9);//將arr中全部填充爲9
Arrays.fill(arr,2,6,9) ;//將arr中從下標2到5全部填充爲9
Arrays. sort(arr); //對數組中的元素排序,底層是用雙軸快速排序
Arrays.toString(arr);//返回指定數組的內容的字符串表示形式。
Arrays.deepToString(arr);//返回指定數組的“深度內容”的字符串表示形式。
Arrays.copyOfRange(int[] original, int from, int to);//將指定數組的指定範圍複製到新數組中。