一、數組基本概念
1. 什么是數組
數組是Java中用來存儲同類型數據的固定大小的連續內存空間的數據結構。
2. 數組特點
固定長度:一旦創建,長度不可改變
相同類型:所有元素必須是同一數據類型
索引訪問:通過下標(從0開始)訪問元素
內存連續:元素在內存中是連續存儲的
二、數組聲明與初始化
1. 數組聲明
// 方式1:數據類型[] 數組名; int[] arr1;// 方式2:數據類型 數組名[]; int arr2[];
推薦使用第一種方式,更符合Java規范
2. 數組初始化
(1) 靜態初始化
java
int arrB[] = {1,2,3,4,5}
這是?靜態初始化的簡化形式,只能在?聲明數組變量時?直接使用。
編譯器會自動推導數組類型和長度。
示例:
java
int arrB[] = {1, 2, 3, 4, 5}; // 正確
arrA = new int[]{1,2,3,4}
這是?靜態初始化的完整形式,可以在?聲明時或后續賦值時?使用。
需要顯式指定數組類型?
new int[]
,但長度由元素個數決定。示例:
java
int[] arrA; arrA = new int[]{1, 2, 3, 4}; // 正確(先聲明后賦值)
使用場景不同
場景 | int[] arr = {1,2,3} | arr = new int[]{1,2,3} |
---|---|---|
聲明時直接初始化 | ? 可用 | ? 可用 |
先聲明后賦值 | ? 不可用 | ? 可用 |
方法返回值 | ? 不可用 | ? 可用 |
匿名數組傳參 | ? 不可用 | ? 可用 |
示例對比:
java
// 1. 聲明時初始化(兩種方式均可) int[] arr1 = {1, 2, 3}; // 簡化形式 int[] arr2 = new int[]{1, 2, 3}; // 完整形式// 2. 先聲明后賦值(只能用完整形式) int[] arr3; arr3 = new int[]{1, 2, 3}; // 正確 // arr3 = {1, 2, 3}; // 錯誤!簡化形式不能用于后續賦值// 3. 作為方法返回值(只能用完整形式) public int[] getArray() {return new int[]{1, 2, 3}; // 正確// return {1, 2, 3}; // 錯誤! }// 4. 匿名數組傳參(只能用完整形式) someMethod(new int[]{1, 2, 3}); // 正確 // someMethod({1, 2, 3}); // 錯誤!
3. 底層實現相同
兩種方式最終生成的字節碼完全一致,性能無差別。
內存分配方式相同:都在堆內存中創建連續存儲的數組對象。
4. 風格建議
推薦使用?
int[] arr
?聲明風格(而非?int arr[]
),更符合 Java 規范。如果只是?聲明時初始化,優先使用簡化形式?
{1,2,3}
,代碼更簡潔。如果需要?重新賦值或匿名使用,必須用完整形式?
new int[]{1,2,3}
。
特性 | {1,2,3} | new int[]{1,2,3} |
---|---|---|
語法名稱 | 簡化靜態初始化 | 完整靜態初始化 |
是否依賴聲明語句 | 必須與聲明寫在一起 | 可獨立使用 |
靈活性 | 低 | 高 |
推薦使用場景 | 聲明時直接初始化 | 重新賦值、方法返回、匿名傳參 |
(2) 動態初始化
java
// 指定長度但不指定元素值 int[] arr = new int[5]; // 默認值為0 String[] strs = new String[3]; // 默認值為null
賦值即逐個元素 循環 arraycopy scanner輸入賦值都可以
三、數組基本操作
1. 訪問數組元素
int[] arr = {10, 20, 30, 40, 50};// 獲取元素 int num = arr[2]; // 獲取第3個元素(30)// 修改元素 arr[3] = 100; // 將第4個元素改為100
2. 獲取數組長度
int length = arr.length; // 注意不是length()
3. 遍歷數組?
這里補充循環一定要放在方法中,不能直接在類體內
(1) 普通for循環
for(int i = 0; i < arr.length; i++) {System.out.println(arr[i]); }
(2) 增強for循環
for(int num : arr) {System.out.println(num); }
小練習:
//for each 增強for循環 //只是改變了item,沒有改變數組也不可以改變,只能做到使用里面的數 //int a=arrB[0]; a=12; arrB=new int[]{1,2,3,4}; for(int item:arrB){item=(int)(Math.random()*100); } System.out.println(Arrays.toString(arrB));//數組隨機賦值,然后找出數組最大值 arrB=new int[7]; for(int i=0;i<arrB.length;i++){arrB[i]=(int)(Math.random()*100); } System.out.println(Arrays.toString(arrB)); int max=arrB[0]; for(int item:arrB){if(item>max){max=item;} } System.out.println("數組最大值是:"+max);// 數組求和 arrB=new int[7]; for(int i=0;i<arrB.length;i++){arrB[i]=(int)(Math.random()*100); } System.out.println(Arrays.toString(arrB)); int sum=0; for(int item:arrB){sum+=item; } System.out.println(sum);//有10個裁判評分,滿分為10分,使用隨機數模擬,存入數組中 //從中去掉最大分數和最小分數,剩下分數的平均數就是選手得分 //打印出選手得分 //Math.random();//[0,1) *10 0-0.9.9999.. (int)一刀切只能取到9 應該*11 arrB=new int[10]; for(int i=0;i<arrB.length;i++){arrB[i]=(int)(Math.random()*11); } System.out.println(Arrays.toString(arrB)); max=arrB[0]; int min=arrB[0]; sum=0; for(int item:arrB){if(item>max){max=item;}if(item<min){min=item;}sum+=item; }int score=(sum-max-min)/8; System.out.println(score);
(3) 使用Arrays.toString()
System.out.println(Arrays.toString(arr));
四、多維數組
1. 二維數組聲明與初始化
// 靜態初始化 int[][] arr1 = {{1, 2}, {3, 4}, {5, 6}};// 動態初始化 int[][] arr2 = new int[3][2]; // 3行2列
2. 二維數組遍歷
for(int i = 0; i < arr.length; i++) {for(int j = 0; j < arr[i].length; j++) {System.out.print(arr[i][j] + " ");}System.out.println(); }
五、數組常用工具類Arrays
1. 排序
int[] arr = {3, 1, 4, 2, 5}; Arrays.sort(arr); // 升序排序
補充:
1.1 冒泡排序
2. 二分查找
int index = Arrays.binarySearch(arr, 4); // 必須是先排序好的才能用二分
3. 數組比較
boolean isEqual = Arrays.equals(arr1, arr2);
4. 數組填充
Arrays.fill(arr, 0); // 全部填充為0
5. 數組復制
int[] newArr = Arrays.copyOf(arr, arr.length);
6.數組擴容
拷貝數組arraycopy? ?五個參數
源數組 ?源數組的起始位置(開始復制的位置) ? 目標數組 ? 目標數組的起始位置(從哪個位置開始粘貼) ? 拷貝的長度
//數組擴容 聲明一個更大的數組代替舊的數組 int[] arrA=new int[10]; arrA[0]=99;arrA[9]=999; int[] arrTemp=new int[arrA.length<<1]; System.arraycopy(arrA,0,arrTemp,0,arrA.length); //原數組 原數組起始位置(從哪個位置開始粘貼) 目標數組 目標數組起始位置 拷貝的長度 arrA=arrTemp; System.out.println(Arrays.toString(arrA));
六、數組常見問題
1. 數組越界異常
java
int[] arr = new int[3]; System.out.println(arr[3]); // ArrayIndexOutOfBoundsException
2. 空指針異常
java
int[] arr = null; System.out.println(arr[0]); // NullPointerException
3. 數組長度不可變
java
int[] arr = new int[5]; // arr.length = 10; // 錯誤!數組長度不可變
七、數組與內存
1. 內存分配
數組變量存儲在棧內存
數組元素存儲在堆內存
2. 內存示意圖
text
棧內存 堆內存 arr ----> [0][0][0][0][0]
八、數組應用場景
存儲大量同類型數據
實現數據結構(如棧、隊列)
矩陣運算
排序和搜索算法實現
九、數組與集合的區別
特性 | 數組 | 集合(ArrayList等) |
---|---|---|
長度 | 固定 | 動態可變 |
類型 | 單一 | 可泛型指定 |
性能 | 高 | 略低 |
功能 | 基礎 | 豐富的方法 |
十、Java 8+ 數組新特性
1. 并行排序
Arrays.parallelSort(arr);
2. Stream操作
Arrays.stream(arr).filter(n -> n > 2).forEach(System.out::println);
3. 集合轉數組
List<String> list = Arrays.asList("A", "B", "C"); String[] arr = list.toArray(new String[0]);
十一、補:無限循環與死循環的區別:
//死循環 無限循環 //while(true){} 沒有結束條件 死循環 i=-1; for(;i<0;i--){}//有結束條件,邏輯上條件永遠達不到,無限循環
1. 無限循環(Infinite Loop)
定義:
有意創建的、設計上需要永不停止的循環結構
通常有特定的業務用途,是程序邏輯的一部分
特點:
? 是有意設計的循環結構
? 通常包含循環控制機制(如?break
?條件)
? 服務于特定業務邏輯(如服務器監聽、游戲主循環)
典型應用場景:
java
// 服務器主線程循環 while(true) {Socket client = serverSocket.accept(); // 等待客戶端連接new Thread(new ClientHandler(client)).start(); }// 游戲主循環 while(running) { // running是可控的布爾變量updateGame();renderFrame(); }
2. 死循環(Dead Loop)
定義:
意外產生的、本應終止卻無法停止的循環
屬于程序缺陷(bug),會導致程序卡死或資源耗盡
特點:
? 是無意產生的程序錯誤
??缺少正確的終止條件
? 會導致程序異常或系統資源耗盡
常見錯誤示例:
java
// 錯誤1:忘記更新循環變量 int i = 0; while(i < 10) { // i永遠不會改變System.out.println("Stuck..."); }// 錯誤2:錯誤的終止條件 for(int j=1; j!=10; j+=2) { // 當j=9時,j+2=11,永遠不等于10System.out.println(j); }
關鍵對比表
特征 | 無限循環 | 死循環 |
---|---|---|
設計意圖 | 有意設計 | 意外產生 |
是否可控 | 有控制機制(可退出) | 無法控制 |
業務價值 | 實現特定功能 | 純屬程序缺陷 |
典型結構 | while(true) ?+ 內部break | 缺少變量更新/錯誤條件 |
是否應避免 | 按需使用 | 必須修復 |