作者:IvanCodes
發布時間:2025年5月1日🤓
專欄:Java教程
大家好!👋 咱們在編程時,經常需要處理一批相同類型的數據,比如班級里所有同學的成績 💯、一周每天的最高氣溫 🌡?、或者購物車里的商品列表 🛒。如果為每個數據都聲明一個單獨的變量(score1
, score2
, score3
…),那代碼不得寫“瘋”了?🤯
這時候,就輪到 Java 中的一個基礎且重要的數據結構登場了——數組 (Array)!你可以把它 想象成一排帶編號的儲物柜 或者一個雞蛋托 🥚,專門用來整齊地存放 多個相同類型 的數據。今天,我們就來把數組這個“老朋友”徹底搞明白!
一、 數組到底是個啥?🤔
簡單來說,數組就是一個固定大小的容器 📦,里面存放的元素必須是相同的數據類型。
幾個關鍵特性要記住:
- 類型統一:一個
int
數組里只能放int
,一個String
數組里只能放String
。不能混裝!🚫 - 長度固定 : 數組一旦創建,它的長度(能裝多少個元素)就不能再改變了!這是數組最核心的限制之一 ??。
- 連續存儲 (通常): 在內存中,數組的元素通常是連續存放的,這使得通過索引訪問元素非常快 ??。
- 索引訪問 : 每個元素都有一個唯一的索引(編號),從 0 開始!通過索引可以快速定位和訪問元素。
二、 創建和使用數組 ??
怎么在代碼里用數組呢?主要分兩步:聲明和初始化。
2.1 聲明數組引用
告訴編譯器:“我要一個能指向某種類型數組的變量”。
// 推薦的聲明方式
int[] scores;
String[] names;
double[] prices;// C/C++ 風格的聲明方式 (也能用,但不推薦)
// int scores[];
// String names[];
注意:這只是聲明了一個引用變量,它現在還是 null
,并沒有指向任何實際的數組內存空間。
2.2 初始化數組(分配空間/賦值)
初始化才是真正創建數組對象、分配內存空間的時候。有兩種主要方式:
方式一:使用 new
指定長度
這是最常用的方式,你知道需要多大的數組,但還不確定里面的具體值。
// 創建一個能存放 5 個 int 的數組
scores = new int[5]; // 分配了 5 個 int 的空間// 創建一個能存放 10 個 String 的數組
names = new String[10]; // 分配了 10 個 String 引用的空間// 聲明和初始化可以合并
double[] salaries = new double[50];
重點📌: 使用 new
創建數組后,里面的元素會被自動賦予默認值:
- 數值類型 (int, double etc.):
0
或0.0
- boolean:
false
- char:
\u0000
(空字符) - 引用類型 (String, Object etc.):
null
方式二:靜態初始化 (直接提供元素值)
如果你在創建數組時就已經知道里面要放哪些元素了,可以用這種更簡潔的方式。編譯器會根據你提供的值自動確定數組的長度。
// 直接提供初始值,長度由編譯器確定 (這里是 4)
int[] initialScores = {90, 85, 92, 78};// 聲明和靜態初始化合并
String[] weekdays = {"Monday", "Tuesday", "Wednesday", "Thursday", "Friday"};// 不能分開寫!下面這樣是錯誤的 ?
// int[] numbers;
// numbers = {1, 2, 3}; // 編譯錯誤
// 必須這樣寫:
int[] numbers;
numbers = new int[]{1, 2, 3}; // 或者聲明時就初始化
2.3 訪問數組元素:靠索引 []
👉
數組的核心操作就是通過索引來存取元素。記住:索引從 0 開始! 非常非常重要! 🚨
public class ArrayAccess {public static void main(String[] args) {String[] fruits = {"Apple <🍎>", "Banana <🍌>", "Orange <🍊>"}; // 長度為 3// 訪問元素 (索引 0, 1, 2)System.out.println("First fruit: " + fruits[0]); // Apple <🍎> (索引 0)System.out.println("Second fruit: " + fruits[1]); // Banana <🍌> (索引 1)System.out.println("Third fruit: " + fruits[2]); // Orange <🍊> (索引 2)// 修改元素fruits[1] = "Grape <🍇>"; // 把第 2 個元素 (索引 1) 改成 GrapeSystem.out.println("Second fruit now: " + fruits[1]); // Grape <🍇>// 嘗試訪問不存在的索引?后果很嚴重!// System.out.println(fruits[3]); // 運行時錯誤💥: ArrayIndexOutOfBoundsException}
}
2.4 獲取數組長度:.length
屬性 📏
想知道數組能裝多少東西?用 .length
屬性(注意:是屬性,不是方法,后面沒有括號 ()
,這點和 String
的 length()
方法不同,容易混淆!)。
int[] data = new int[10];
System.out.println("Length of data array: " + data.length); // Output: 10String[] colors = {"Red", "Green", "Blue"};
System.out.println("Number of colors: " + colors.length); // Output: 3
.length
在循環遍歷數組時特別有用。
三、 遍歷數組:挨個“點名” 🚶?♀?🚶?♂?
遍歷數組就是按順序訪問數組中的每一個元素,通常用循環來實現。
3.1 使用傳統 for
循環
最靈活的方式,因為你可以拿到當前的索引 i
。
public class ForLoopArray {public static void main(String[] args) {double[] readings = {12.5, 13.1, 11.8, 12.9};System.out.println("Sensor Readings:");// 循環條件通常是 i < array.lengthfor (int i = 0; i < readings.length; i++) {System.out.println("Reading at index " + i + ": " + readings[i]);}}
}
3.2 使用增強型 for
循環 (for-each)
如果不需要關心索引,只是想依次處理每個元素,這種方式更簡潔、易讀。
import java.util.ArrayList; // 只是為了演示集合遍歷
import java.util.List;public class ForEachArray {public static void main(String[] args) {char[] vowels = {'a', 'e', 'i', 'o', 'u'};System.out.print("Vowels: ");// 依次取出 vowels 數組中的每個 char 賦給變量 vowelfor (char vowel : vowels) {System.out.print(vowel + " ");}System.out.println(); // 輸出: a e i o u// 同樣適用于集合 (比如 ArrayList)// List<String> names = new ArrayList<>(); ...// for (String name : names) { ... }}
}
如何選擇? 如果需要索引(比如要根據索引修改元素,或者需要知道當前是第幾個元素),用傳統 for
。如果只是讀取每個元素的值,增強型 for
通常更好。
四、 數組的“常見煩惱” 😩💥
使用數組時,有幾個經典錯誤你很可能會遇到:
ArrayIndexOutOfBoundsException
<💥>: 這是最常見的數組錯誤!當你試圖訪問一個不存在的索引時(比如索引 < 0,或者索引 >=array.length
),就會拋出這個運行時異常。寫循環時要特別小心邊界條件!NullPointerException
: 如果你的數組引用變量本身是null
(即它沒有指向任何數組對象),而你試圖訪問它的.length
屬性或者通過索引訪問元素(如nullArray[0]
),就會得到這個運行時異常。使用數組前,確保它已經被正確初始化了!- 長度固定不變 <🔒>: 前面強調過,數組長度一旦確定就不能改。如果你的程序需要一個可以動態增刪元素的容器,那么 Java 集合框架中的
ArrayList
等類通常是更好的選擇。
五、 超出基礎:多維數組與 Arrays
工具類 ?🛠?
5.1 多維數組
你可以創建“數組的數組”,最常見的是二維數組,可以把它想象成一個表格或矩陣 ?。
// 創建一個 3行 4列 的 int 二維數組
int[][] matrix = new int[3][4];// 靜態初始化
String[][] board = {{"X", "O", "X"},{"O", "X", "O"},{"X", "O", "X"}
};// 訪問元素需要兩個索引
matrix[0][1] = 5; // 設置第 1 行第 2 列 (索引都是從 0 開始)
System.out.println("Board[1][1]: " + board[1][1]); // Output: X
遍歷二維數組通常需要嵌套循環。
5.2 java.util.Arrays
工具類 <🛠?>
Java 提供了一個非常有用的 Arrays
類(在 java.util
包下),里面包含了很多操作數組的static
方法,能省不少事:
Arrays.toString(array)
: 把數組轉換成易于閱讀的字符串形式,方便打印調試,強烈推薦!👍Arrays.sort(array)
: 對數組進行排序(原地排序)。Arrays.fill(array, value)
: 用指定值填充整個數組。Arrays.copyOf(originalArray, newLength)
: 復制原數組的一部分或全部到一個新的數組(可以用來變相“擴展”數組)。Arrays.equals(array1, array2)
: 比較兩個數組的內容是否相等(注意,不是用==
比地址)。
import java.util.Arrays; // <--- 別忘了導入!public class ArraysUtilDemo {public static void main(String[] args) {int[] nums = {5, 2, 8, 1, 9};// 好看的打印方式System.out.println("Original array: " + Arrays.toString(nums));// 排序Arrays.sort(nums);System.out.println("Sorted array: " + Arrays.toString(nums));// 填充int[] filled = new int[5];Arrays.fill(filled, -1);System.out.println("Filled array: " + Arrays.toString(filled));// 復制 (取前 3 個元素)int[] copied = Arrays.copyOf(nums, 3); // nums 已經是排序后的 {1, 2, 5, 8, 9}System.out.println("Copied first 3: " + Arrays.toString(copied));}
}
六、總結 🏁
數組是 Java 中存儲固定數量、相同類型元素的基礎數據結構。
- 核心特性:類型統一、長度固定、索引訪問 (從 0 開始)。
- 創建方式:
new Type[size]
或靜態初始化{...}
。 - 訪問與長度:使用
array[index]
訪問,.length
獲取長度。 - 遍歷:常用
for
或增強for
循環。 - 常見陷阱 🚨:
ArrayIndexOutOfBoundsException
,NullPointerException
, 長度固定限制。 - 好幫手 <🛠?>:
java.util.Arrays
類提供了很多實用方法。
雖然 ArrayList
等集合類在靈活性上更勝一籌,但數組在性能(尤其是訪問速度)和表示固定大小數據集時仍然有其優勢,并且是理解集合類的基礎。所以,扎實掌握數組非常重要!
七、練練手,檢驗成果!??🧠
來,動手寫寫代碼,鞏固一下!
? 基礎操作 ?
- 聲明一個可以存放 10 個
double
類型數據的數組prices
,并將其所有元素初始化為9.99
(使用循環或Arrays.fill
)。 - 創建一個
String
數組colors
,包含 “Red”, “Green”, “Blue”, “Yellow”。然后,修改第三個元素 (“Blue”) 為 “Purple”,并打印修改后的數組內容 (使用Arrays.toString
)。
? 循環與計算 ?
- 給定一個
int
數組scores = {88, 92, 75, 98, 85}
,計算并打印數組中所有分數的平均值 (注意結果可能是小數)。 - 查找數組
int[] data = {5, -2, 9, 15, -8, 1}
中的最大值,并打印出來。
? 概念辨析 ?
- 嘗試解釋為什么數組的索引是從 0 開始而不是從 1 開始?(提示:可以從內存地址和偏移量角度思考,或說明其歷史淵源和編程習慣)
- 比較數組 (
int[]
) 和ArrayList<Integer>
的主要區別,尤其是在大小和類型方面。
八、參考答案 ?💡
? 基礎操作答案 ?
1.初始化 prices
數組:
import java.util.Arrays;public class InitPrices {public static void main(String[] args) {double[] prices = new double[10];// 方法一:使用循環// for (int i = 0; i < prices.length; i++) {// prices[i] = 9.99;// }// 方法二:使用 Arrays.fill (更推薦)Arrays.fill(prices, 9.99);System.out.println("Initialized prices: " + Arrays.toString(prices));}
}
2.修改 colors
數組:
import java.util.Arrays;public class ModifyColors {public static void main(String[] args) {String[] colors = {"Red", "Green", "Blue", "Yellow"};System.out.println("Original colors: " + Arrays.toString(colors));// 第三個元素索引是 2if (colors.length > 2) { // 做個簡單檢查防止越界colors[2] = "Purple <💜>";}System.out.println("Modified colors: " + Arrays.toString(colors));// 輸出: Modified colors: [Red, Green, Purple <💜>, Yellow]}
}
? 循環與計算答案 ?
3.計算平均分:
import java.util.Arrays;public class AverageScore {public static void main(String[] args) {int[] scores = {88, 92, 75, 98, 85};if (scores.length == 0) {System.out.println("Array is empty, cannot calculate average.");return;}int sum = 0;for (int score : scores) {sum += score;}// 注意:為了得到精確的小數結果,需要將 sum 或 length 轉為 doubledouble average = (double) sum / scores.length;// 或者 double average = sum * 1.0 / scores.length;System.out.println("Scores: " + Arrays.toString(scores));System.out.println("Average score: " + average); // 輸出: Average score: 87.6}
}
4.查找最大值:
import java.util.Arrays;public class FindMaxValue {public static void main(String[] args) {int[] data = {5, -2, 9, 15, -8, 1};if (data.length == 0) {System.out.println("Array is empty.");return;}int max = data[0]; // 假設第一個元素是最大值for (int i = 1; i < data.length; i++) {if (data[i] > max) {max = data[i]; // 如果找到更大的,更新 max}}System.out.println("Data: " + Arrays.toString(data));System.out.println("Maximum value: " + max); // 輸出: Maximum value: 15}
}
? 概念辨析答案 ?
5.為什么索引從 0 開始? 這主要是歷史原因和底層實現效率的考慮。在 C 語言(Java 的重要祖先)及更早的語言中,數組名通常代表數組第一個元素在內存中的起始地址。訪問數組元素 array[i]
,實際上是計算 起始地址 + i * 每個元素的大小
來找到第 i+1
個元素的地址。如果索引從 0 開始,那么訪問第一個元素 array[0]
就是 起始地址 + 0 * size
,即起始地址本身,計算最簡單、最高效。如果從 1 開始,訪問第一個元素 array[1]
就需要計算 起始地址 + (1-1) * size
,多了一步減法。這種從 0 開始的索引(稱為 zero-based indexing)已經成為 C 家族語言(包括 C++, Java, C#, JavaScript 等)的編程慣例。
6.int[]
vs ArrayList<Integer>
區別:
- 大小:
int[]
: 大小固定。一旦創建,長度不能改變。ArrayList<Integer>
: 大小可變。可以動態添加或刪除元素,其內部容量會自動調整(雖然可能涉及性能開銷)。
- 類型:
int[]
: 存儲的是基本數據類型int
的值。ArrayList<Integer>
: 存儲的是包裝類<font color="purple">Integer</font>
的對象引用。它不能直接存儲基本類型int
(但 Java 的自動裝箱/拆箱機制使得使用起來很像在存取int
)。
- 功能:
ArrayList
提供了更多現成的方法(如add
,remove
,contains
,size
等),而數組功能相對基礎(主要靠索引和Arrays
工具類)。 - 性能: 對于固定大小且頻繁訪問的場景,數組通常比
ArrayList
性能稍好(特別是對于基本類型數組,避免了裝箱/拆箱開銷和對象引用的開銷)。
希望這篇關于數組的筆記能幫你打下堅實的基礎!用熟了它,再去看集合框架就會感覺輕松很多!如果覺得有幫助,別忘了 點贊👍、收藏?、關注 哦!感謝!💖