数组是编程中最基础且重要的数据结构之一,尤其在Java语言中,它不仅是存储数据的容器,更是理解引用类型、内存管理的钥匙。本文将带你系统学习Java数组,从基本概念到实际应用,助你打下扎实的基础。
一、为什么要使用数组?
假设我们需要存储5名学生的Java成绩,最直接的做法是创建5个变量:
int score1 = 70;
int score2 = 80;
int score3 = 85;
int score4 = 60;
int score5 = 90;
这种方式在数据量少时可行,但当学生数量增加到20、100甚至更多时,声明大量变量将变得极其繁琐且难以维护。仔细观察这些数据,它们都是同一类型(整型)的集合。数组就是为了解决存储"大量同类型数据"而设计的一种数据结构。
二、什么是数组?
数组可视为相同类型元素的一个集合,在内存中占用一段连续的空间。类比现实中的停车场,数组就像一连串编号的车位:
-
每个车位(元素)类型相同(都停车)
-
车位是连续的(一个挨着一个)
-
每个车位有唯一编号,从0开始(数组下标)
三、数组的创建与初始化
1. 数组的创建
语法:T[] 数组名 = new T[N];
-
T:元素类型 -
N:数组长度
示例:
int[] array1 = new int[10]; // 容纳10个int
double[] array2 = new double[5]; // 容纳5个double
String[] array3 = new String[3]; // 容纳3个String
2. 数组的初始化
分为动态初始化 和静态初始化。
动态初始化:创建时指定元素个数,元素为默认值。
int[] array = new int[10]; // 10个整数,初始值均为0
静态初始化:创建时直接赋值。
int[] array1 = new int[]{0, 1, 2, 3, 4, 5, 6, 7, 8, 9};
double[] array2 = {1.0, 2.0, 3.0, 4.0, 5.0}; // 简写形式
String[] array3 = {"Hello", "Java", "!!!"};
注意事项:
-
静态初始化可简写为
T[] 名称 = {元素1, 元素2, ...},编译器自动推导类型与长度。 -
未初始化时,数组元素有默认值:
-
整型:0
-
浮点型:0.0
-
布尔型:false
-
字符型:'\u0000'
-
引用类型:null
-
四、数组的使用
1. 访问元素:通过下标
数组下标从0开始,连续递增。可通过数组名[下标]访问或修改元素。
int[] array = {10, 20, 30, 40, 50};
System.out.println(array[0]); // 输出 10
array[0] = 100; // 修改为100
谨防下标越界 :有效下标范围是[0, 数组长度-1],越界会抛出ArrayIndexOutOfBoundsException。
2. 遍历数组
推荐使用循环遍历,尤其当数组较长时。
普通for循环:
int[] array = {10, 20, 30, 40, 50};
for (int i = 0; i < array.length; i++) {
System.out.println(array[i]);
}
for-each循环(增强for循环):
for (int x : array) {
System.out.println(x);
}
for-each写法更简洁,适用于只需读取元素值的场景。
五、数组是引用类型
1. JVM内存简单分布
理解数组前,需了解Java内存的几个关键区域:
-
虚拟机栈:存储局部变量等,方法结束即销毁。
-
堆 :存放通过
new创建的对象(包括数组),生命周期较长。 -
方法区:存储类信息、常量等。
2. 基本类型 vs 引用类型
-
基本类型变量 (如
int a = 10;)直接存储值。 -
引用类型变量 (如
int[] arr = new int[]{1,2,3};)存储的是对象在堆中的内存地址。
当执行int[] arr = new int[3];时:
-
在栈中创建引用变量
arr -
在堆中开辟连续空间存放数组
-
arr中保存的是堆中数组的首地址
https://your-image-link.com/array_memory.png
3. 引用赋值与null
多个引用可指向同一数组,修改任意一个会影响原数组:
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 100;
System.out.println(a[0]); // 输出100,a和b指向同一数组
null表示引用不指向任何对象:
int[] arr = null;
System.out.println(arr[0]); // 抛出NullPointerException
六、数组的应用场景
1. 作为函数参数
-
传递基本类型:形参修改不影响实参(值拷贝)。
-
传递数组(引用类型):形参和实参指向同一对象,修改内容会影响原数组。
public static void func(int[] a) {
a[0] = 10; // 修改会影响外部数组
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
func(arr);
System.out.println(arr[0]); // 输出10
}
优势:传递数组只需传递地址,避免了整个数组的拷贝,效率高。
2. 作为函数返回值
典型例子:返回斐波那契数列数组
public static int[] fib(int n) {
int[] f = new int[n];
// ... 计算逻辑
return f;
}
七、数组常见操作(实用代码示例)
1. 数组转字符串
使用Arrays.toString()快速输出数组内容:
import java.util.Arrays;
int[] arr = {1, 2, 3, 4, 5};
System.out.println(Arrays.toString(arr)); // [1, 2, 3, 4, 5]
2. 数组拷贝
-
引用拷贝:多个变量指向同一数组。
-
深拷贝:创建新数组,复制元素。
// 深拷贝方法
int[] newArr = Arrays.copyOf(arr, arr.length);
int[] rangeCopy = Arrays.copyOfRange(arr, 2, 4); // 拷贝下标[2,4)的元素
3. 求平均值
public static double avg(int[] arr) {
int sum = 0;
for (int x : arr) {
sum += x;
}
return (double) sum / arr.length;
}
4. 查找元素
顺序查找:
public static int find(int[] arr, int target) {
for (int i = 0; i < arr.length; i++) {
if (arr[i] == target) {
return i;
}
}
return -1; // 未找到
}
二分查找(仅用于有序数组):
public static int binarySearch(int[] arr, int target) {
int left = 0, right = arr.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (arr[mid] < target) {
left = mid + 1;
} else if (arr[mid] > target) {
right = mid - 1;
} else {
return mid;
}
}
return -1;
}
5. 排序(冒泡排序示例)
public static void bubbleSort(int[] arr) {
for (int i = 0; i < arr.length - 1; i++) {
for (int j = 0; j < arr.length - 1 - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
}
实际开发中建议使用内置的高效排序:Arrays.sort(arr)
6. 数组逆序
public static void reverse(int[] arr) {
int left = 0, right = arr.length - 1;
while (left < right) {
int temp = arr[left];
arr[left] = arr[right];
arr[right] = temp;
left++;
right--;
}
}
八、二维数组
二维数组本质是"数组的数组",即每个元素又是一个一维数组。
int[][] arr = {
{1, 2, 3, 4},
{5, 6, 7, 8},
{9, 10, 11, 12}
};
// 遍历
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + "\t");
}
System.out.println();
}
总结
数组是Java中组织数据的核心工具,掌握其定义、初始化、遍历及内存原理至关重要。关键点总结:
-
数组存储同类型元素 ,内存连续 ,支持随机访问(通过下标)。
-
数组是引用类型 ,变量存储的是堆中对象的地址。
-
作为函数参数传递时,传递的是地址,可修改原数组内容。
-
常用操作:遍历、查找、排序、拷贝等,Java提供了
Arrays工具类简化操作。 -
理解一维数组是学习二维及多维数组的基础。
数组是后续学习集合框架、算法与数据结构的重要基石,建议通过实际编码练习加深理解。