前言 数组是Java编程中最基本也是最重要的数据结构之一。它提供了一种存储同类型多个元素的有效方式,是学习Java集合框架的基础。无论是简单的数据存储,还是复杂的算法实现,数组都扮演着重要角色。本文将全面介绍Java数组的各个方面,从基础概念到高级应用,帮助您掌握数组的所有核心知识点。
数组基础概念 什么是数组 数组是一种容器对象,用于存储相同类型的多个值。在Java中,数组是引用类型,它具有以下特点:
同质性 :数组中的所有元素必须是相同类型
连续性 :数组元素在内存中是连续存储的
索引访问 :通过索引(下标)访问数组元素,索引从0开始
固定长度 :一旦创建,数组的长度就不能改变
graph TD
A[数组的特点] --> B[同质性]
A --> C[连续性]
A --> D[索引访问]
A --> E[固定长度]
B --> B1[所有元素相同类型]
C --> C1[内存连续存储]
D --> D1[下标从0开始]
E --> E1[长度不可变]
F[数组优势] --> F1[访问效率高O1]
F --> F2[内存使用效率高]
F --> F3[缓存友好]
G[数组劣势] --> G1[插入删除成本高]
G --> G2[长度固定]
G --> G3[空间浪费]
数组的内存结构 graph LR
subgraph "堆内存"
A[数组对象]
B[0: element1]
C[1: element2]
D[2: element3]
E[3: element4]
F[length: 4]
A --> B
B --> C
C --> D
D --> E
A --> F
end
subgraph "栈内存"
G[数组引用变量]
end
G --> A
subgraph "内存地址"
H[0x1000]
I[0x1004]
J[0x1008]
K[0x100C]
end
B --> H
C --> I
D --> J
E --> K
一维数组 数组的声明 Java中有两种声明数组的语法格式:
1 2 3 4 5 6 7 8 9 10 数据类型[] 数组名; 数据类型 数组名[]; int [] numbers; String[] names; double [] scores;
数组的创建 声明数组后,需要使用new
关键字创建数组对象:
1 2 3 4 5 6 7 8 9 10 11 int [] arr1 = {1 , 2 , 3 , 4 , 5 };String[] arr2 = {"Java" , "Python" , "C++" }; int [] arr3 = new int [5 ];arr3[0 ] = 10 ; arr3[1 ] = 20 ; int [] arr4 = new int []{1 , 2 , 3 , 4 , 5 };
数组的访问和遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ArrayDemo { public static void main (String[] args) { int [] numbers = {10 , 20 , 30 , 40 , 50 }; System.out.println("第一个元素: " + numbers[0 ]); System.out.println("数组长度: " + numbers.length); System.out.println("普通for循环:" ); for (int i = 0 ; i < numbers.length; i++) { System.out.println("numbers[" + i + "] = " + numbers[i]); } System.out.println("增强for循环:" ); for (int num : numbers) { System.out.println("元素值: " + num); } } }
多维数组 二维数组 二维数组可以看作是”数组的数组”,常用于表示表格、矩阵等二维结构。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 int [][] matrix = new int [3 ][4 ]; int [][] arr = { {1 , 2 , 3 }, {4 , 5 , 6 }, {7 , 8 , 9 } }; int [][] dynamicArr = new int [3 ][];dynamicArr[0 ] = new int [2 ]; dynamicArr[1 ] = new int [3 ]; dynamicArr[2 ] = new int [4 ];
多维数组遍历 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 public class MultiArrayDemo { public static void main (String[] args) { int [][] matrix = { {1 , 2 , 3 , 4 }, {5 , 6 , 7 , 8 }, {9 , 10 , 11 , 12 } }; for (int i = 0 ; i < matrix.length; i++) { for (int j = 0 ; j < matrix[i].length; j++) { System.out.print(matrix[i][j] + "\t" ); } System.out.println(); } for (int [] row : matrix) { for (int element : row) { System.out.print(element + "\t" ); } System.out.println(); } } }
数组的常见操作 数组的查找 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 public class ArraySearch { public static int linearSearch (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 - left) / 2 ; if (arr[mid] == target) { return mid; } else if (arr[mid] < target) { left = mid + 1 ; } else { right = mid - 1 ; } } return -1 ; } }
数组的排序 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public class ArraySort { public static void bubbleSort (int [] arr) { int n = arr.length; for (int i = 0 ; i < n - 1 ; i++) { for (int j = 0 ; j < n - 1 - i; j++) { if (arr[j] > arr[j + 1 ]) { int temp = arr[j]; arr[j] = arr[j + 1 ]; arr[j + 1 ] = temp; } } } } public static void selectionSort (int [] arr) { int n = arr.length; for (int i = 0 ; i < n - 1 ; i++) { int minIndex = i; for (int j = i + 1 ; j < n; j++) { if (arr[j] < arr[minIndex]) { minIndex = j; } } int temp = arr[i]; arr[i] = arr[minIndex]; arr[minIndex] = temp; } } }
数组的复制 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class ArrayCopy { public static void main (String[] args) { int [] original = {1 , 2 , 3 , 4 , 5 }; int [] copy1 = new int [original.length]; for (int i = 0 ; i < original.length; i++) { copy1[i] = original[i]; } int [] copy2 = new int [original.length]; System.arraycopy(original, 0 , copy2, 0 , original.length); int [] copy3 = Arrays.copyOf(original, original.length); int [] copy4 = original.clone(); } }
Arrays工具类 Java提供了java.util.Arrays
工具类,包含了许多操作数组的静态方法:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 import java.util.Arrays;public class ArraysDemo { public static void main (String[] args) { int [] arr = {5 , 2 , 8 , 1 , 9 , 3 }; Arrays.sort(arr); System.out.println("排序后: " + Arrays.toString(arr)); int index = Arrays.binarySearch(arr, 5 ); System.out.println("元素5的位置: " + index); System.out.println("数组内容: " + Arrays.toString(arr)); int [] arr2 = {1 , 2 , 3 , 5 , 8 , 9 }; boolean equal = Arrays.equals(arr, arr2); System.out.println("数组是否相等: " + equal); int [] fillArr = new int [5 ]; Arrays.fill(fillArr, 100 ); System.out.println("填充数组: " + Arrays.toString(fillArr)); Arrays.fill(fillArr, 1 , 4 , 200 ); System.out.println("部分填充: " + Arrays.toString(fillArr)); } }
graph TD
A[Arrays工具类] --> B[排序操作]
A --> C[查找操作]
A --> D[比较操作]
A --> E[复制操作]
A --> F[填充操作]
A --> G[转换操作]
B --> B1[sort - 排序]
B --> B2[parallelSort - 并行排序]
C --> C1[binarySearch - 二分查找]
D --> D1[equals - 内容比较]
D --> D2[deepEquals - 深度比较]
E --> E1[copyOf - 复制指定长度]
E --> E2[copyOfRange - 复制指定范围]
F --> F1[fill - 全部填充]
F --> F2[fill range - 部分填充]
G --> G1[toString - 转字符串]
G --> G2[deepToString - 深度转换]
数组的高级应用 动态数组实现 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class DynamicArray { private int [] array; private int size; private int capacity; public DynamicArray () { this .capacity = 10 ; this .array = new int [capacity]; this .size = 0 ; } public void add (int element) { if (size >= capacity) { resize(); } array[size++] = element; } private void resize () { capacity *= 2 ; int [] newArray = new int [capacity]; System.arraycopy(array, 0 , newArray, 0 , size); array = newArray; } public int get (int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException ("索引越界" ); } return array[index]; } public void remove (int index) { if (index < 0 || index >= size) { throw new IndexOutOfBoundsException ("索引越界" ); } for (int i = index; i < size - 1 ; i++) { array[i] = array[i + 1 ]; } size--; } public int size () { return size; } }
数组算法应用示例 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 public class ArrayAlgorithms { public static int [] findMinMax(int [] arr) { if (arr == null || arr.length == 0 ) { return null ; } int min = arr[0 ], max = arr[0 ]; for (int i = 1 ; i < arr.length; i++) { if (arr[i] < min) min = arr[i]; if (arr[i] > max) max = arr[i]; } return new int []{min, max}; } public static int [] removeDuplicates(int [] arr) { Arrays.sort(arr); int [] temp = new int [arr.length]; int j = 0 ; for (int i = 0 ; i < arr.length - 1 ; i++) { if (arr[i] != arr[i + 1 ]) { temp[j++] = arr[i]; } } temp[j++] = arr[arr.length - 1 ]; return Arrays.copyOf(temp, j); } public static void rotateArray (int [] arr, int k) { int n = arr.length; k = k % n; reverse(arr, 0 , n - 1 ); reverse(arr, 0 , k - 1 ); reverse(arr, k, n - 1 ); } private static void reverse (int [] arr, int start, int end) { while (start < end) { int temp = arr[start]; arr[start] = arr[end]; arr[end] = temp; start++; end--; } } }
数组的性能考虑 时间复杂度分析
访问元素 :O(1) - 直接通过索引访问
查找元素 :O(n) - 线性查找,O(log n) - 二分查找(有序)
插入元素 :O(n) - 需要移动后续元素
删除元素 :O(n) - 需要移动后续元素
空间复杂度 数组的空间复杂度为O(n),其中n是数组的长度。
性能优化建议
预估数组大小 :避免频繁扩容
使用合适的数据类型 :节省内存空间
考虑使用集合类 :当需要频繁插入删除时
缓存友好的访问模式 :按顺序访问数组元素
常见错误和注意事项 数组越界异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 public class ArrayBounds { public static void main (String[] args) { int [] arr = new int [5 ]; try { arr[5 ] = 10 ; } catch (ArrayIndexOutOfBoundsException e) { System.out.println("数组越界: " + e.getMessage()); } int index = 5 ; if (index >= 0 && index < arr.length) { arr[index] = 10 ; } else { System.out.println("索引越界,数组长度为: " + arr.length); } } }
空指针异常 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 public class NullPointer { public static void main (String[] args) { int [] arr = null ; try { System.out.println(arr.length); } catch (NullPointerException e) { System.out.println("空指针异常" ); } if (arr != null ) { System.out.println("数组长度: " + arr.length); } else { System.out.println("数组为空" ); } } }
总结 数组是Java编程的基础数据结构,掌握数组的使用对于Java开发至关重要。本文全面介绍了Java数组的各个方面:
基础概念 :理解数组的特点和内存结构
声明和创建 :掌握多种数组初始化方式
访问和遍历 :学会使用不同的遍历方法
多维数组 :理解和应用二维数组及更高维度
常见操作 :掌握查找、排序、复制等基本操作
Arrays工具类 :熟练使用Java提供的数组工具方法
高级应用 :了解动态数组实现和算法应用
性能考虑 :理解数组操作的时间空间复杂度
数组虽然简单,但在实际开发中应用广泛。理解数组的特点和限制,能够帮助我们在合适的场景选择合适的数据结构,为后续学习集合框架打下坚实基础。
参考资料
Oracle Java Documentation - Arrays
Effective Java by Joshua Bloch
Java核心技术卷I - 基础知识
算法导论 - 数组和基本数据结构