Java数组
·
一、数组的定义与内存模型
1. 数组的三种定义方式
// 1. 静态初始化(定义时直接赋值)
int[] array1 = {1,2,3,4};
// 2. 动态初始化(指定长度,默认值填充)
int[] array2 = new int[10];
// 3. 动态初始化(指定初始值)
int[] array3 = new int[]{1,2,3,4,5,6,7};
- 内存核心概念
基本数据类型:变量直接存储值(如 int 默认 0 , char 默认 \u0000 , double 默认 0.0 , boolean 默认 false )。
引用数据类型:变量存储的是对象的内存地址(数组、类、接口等都属于引用类型)。
Java虚拟机运行时的数据区
虚拟机栈:存储局部变量(如 array 引用变量)。
堆:存储真正的数组对象(数据存在堆上)。
方法区:存储类信息、常量等。
int[] array = {1,2,3,4};
int[] array2 = array; // 两个引用指向同一个堆上的数组对象
array[0] = 99;
System.out.println(array2[0]); // 输出99,因为共享同一块内存
这里的array和array2指向堆中同一个对象
二、数组的核心操作
1. 遍历与打印
普通for循环:可以获取下标,适合需要操作索引的场景。
增强for循环(for-each):只能遍历元素,拿不到下标,适合单纯遍历。
for(int x:array){
System.out.println(x+" ");
}
工具类打印: Arrays.toString() 快速打印一维数组, Arrays.deepToString() 打印二维数组。
| 方法分类 | 方法名 | 方法用途 | 注意点 |
|---|---|---|---|
| 排序 | sort() | 对一维数组进行升序排序 | 对象数组需实现Comparable接口(后续文章中会讲到) |
| 查找 | binarySearch() | 在已排序的数组中查找指定元素,返回索引(未找到返回-(插入点)-1 | 必须先排序 |
| 填充 | fill() | 将数组全部 / 指定范围元素填充为指定值 | |
| 比较 | equals() | 比较两个一维数组的长度 + 对应位置元素是否完全相同 | 仅适用于一维数组,多维数组需用deepEquals() |
| deepEquals() | 比较多维数组的内容是否完全相同 | ||
| 字符串转换 | toString() | 将一维数组转为[元素1, 元素2, …]格式的易读字符串 | 多维数组需用deepToString(),否则输出数组内存地址 |
| deepToString() | 将多维数组转为易读的字符串形式 | ||
| 数组复制 | copyIOf() | 复制数组前 N 个元素(N > 原长度时补默认值:int 补 0,对象补 null) | |
| copyOfRange() | 复制数组指定范围 | 范围超出原数组长度时,补对应类型默认值 | |
| 各个方法名的用法示例 |
sort()方法
// 1. 基本类型数组排序(int数组)
int[] intArr = {3, 1, 4, 2};
Arrays.sort(intArr);
System.out.println("排序后int数组:" + Arrays.toString(intArr)); // 输出 [1, 2, 3, 4]
// 2. 局部排序
int[] partialArr = {5, 2, 9, 1, 7};
Arrays.sort(partialArr, 1, 4); // 排序索引1-3的元素,java中前闭后开
System.out.println("局部排序后:" + Arrays.toString(partialArr)); // 输出 [5, 1, 2, 9, 7]
binarySearch()方法
int[] arr = {1, 2, 3, 4, 5};
// 查找存在的元素
int index1 = Arrays.binarySearch(arr, 3);
System.out.println("元素3的索引:" + index1); // 输出 2
// 查找不存在的元素
int index2 = Arrays.binarySearch(arr, 6);
System.out.println("元素6的查找结果:" + index2); // 输出 -6(插入点是5,-(5)-1=-6)
看插入点的方法:1.遍历已排序数组,找到第一个大于目标值的元素的索引,这个索引就是插入点;
2.如果目标值大于所有元素,插入点 = 数组长度(如上例中 10 的插入点是 5,数组长度正好是 5);
3.如果目标值小于所有元素,插入点 = 0。
fill()
// 1. 填充所有元素
int[] arr1 = new int[5];
Arrays.fill(arr1, 8);
System.out.println("填充所有元素:" + Arrays.toString(arr1)); // 输出 [8, 8, 8, 8, 8]
// 2. 填充指定范围元素
int[] arr2 = new int[5];
Arrays.fill(arr2, 1, 4, 9); // 填充索引1-3的元素为9
System.out.println("填充指定范围:" + Arrays.toString(arr2)); // 输出 [0, 9, 9, 9, 0]
数组比较:equals () 和 deepEquals ()
// 1. 一维数组比较
int[] arr1 = {1, 2, 3};
int[] arr2 = {1, 2, 3};
int[] arr3 = {1, 3, 2};
System.out.println("arr1和arr2是否相等:" + Arrays.equals(arr1, arr2)); // 输出 true
System.out.println("arr1和arr3是否相等:" + Arrays.equals(arr1, arr3)); // 输出 false
// 2. 多维数组比较(必须用deepEquals)
int[][] multiArr1 = {{1,2}, {3,4}};
int[][] multiArr2 = {{1,2}, {3,4}};
System.out.println("多维数组比较(equals):" + Arrays.equals(multiArr1, multiArr2)); // 输出 false(比较的是数组引用)
System.out.println("多维数组比较(deepEquals):" + Arrays.deepEquals(multiArr1, multiArr2)); // 输出 true
数组转字符串:toString () 和 deepToString ()
// 1. 一维数组转字符串
int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // 输出 [1, 2, 3]
// 2. 多维数组转字符串
int[][] multiArr = {{1,2}, {3,4}};
System.out.println(Arrays.deepToString(multiArr)); // 输出 [[1, 2], [3, 4]]
数组复制:copyOf () 和 copyOfRange ()
int[] original = {1, 2, 3, 4, 5};
// 1. 复制前3个元素
int[] copy1 = Arrays.copyOf(original, 3);
System.out.println("copyOf前3个:" + Arrays.toString(copy1)); // 输出 [1, 2, 3]
// 2. 复制超出原长度(补0)
int[] copy2 = Arrays.copyOf(original, 7);
System.out.println("copyOf超出长度:" + Arrays.toString(copy2)); // 输出 [1, 2, 3, 4, 5, 0, 0]
// 3. 复制指定范围(索引1到4)
int[] copy3 = Arrays.copyOfRange(original, 1, 4);
System.out.println("copyOfRange:" + Arrays.toString(copy3)); // 输出 [2, 3, 4]
打印数组的各个方法
int[] array = {1,2,3,4,5};
// 普通for循环
for (int i = 0; i < array.length; i++) {
System.out.print(array[i] + " ");
}
// for-each循环
for (int x : array) {
System.out.print(x + " ");
}
// 工具类打印
System.out.println(Arrays.toString(array)); // 输出[1, 2, 3, 4, 5]
2.自定义二分查找:
public static int binarySearch(int[] array, int key) {
int left = 0;
int right = array.length - 1;
while (left <= right) {
int mid = (left + right) / 2;
if (array[mid] < key) {
left = mid + 1;
} else if (array[mid] > key) {
right = mid - 1;
} else {
return mid; // 找到目标
}
}
return -1; // 未找到
}
三、数组常见异常
- 数组越界异常: ArrayIndexOutOfBoundsException
原因:访问了数组不存在的下标(如 array[-1] 或 array[array.length] )。 - 空指针异常: NullPointerException
原因:引用变量为 null 时,尝试访问其指向的对象(如 int[] arr = null; arr[0] = 1; )。 - 算术异常: ArithmeticException
原因:数学运算错误(如除零操作)。
四、二维数组与特殊算法
1. 二维数组定义
定义示例
// 静态初始化
int[][] array1 = {{1,2,3}, {4,5,6}};
// 动态初始化
int[][] array2 = new int[2][3];
// 不规则二维数组
int[][] array3 = new int[2][];
array3[0] = new int[]{1,2,3};
array3[1] = new int[]{4,5,6,7,8,9};
2. 经典算法题:只出现一次的数字
利用异或运算(相同为0,不同为1)的性质:
任何数和0异或等于它本身: a ^ 0 = a
任何数和自身异或等于0: a ^ a = 0
异或满足交换律和结合律
// 数组中只有一个数字出现一次,其余都出现两次
public static int findSingleNumber(int[] array) {
int ret = array[0];
for (int i = 1; i < array.length; i++) {
ret ^= array[i];
}
return ret;
}
五、总结与学习建议
- 数组核心:理解引用类型的内存模型,掌握遍历、拷贝、排序、查找等基础操作。
- 异常处理:重点关注数组越界和空指针异常,养成良好的编码习惯。
- 实践优先:多写代码练习,比如实现冒泡排序、二分查找、二维数组遍历等。
后续继续学习:构造方法、封装、继承、多态等面向对象核心特性.
AtomGit 是由开放原子开源基金会联合 CSDN 等生态伙伴共同推出的新一代开源与人工智能协作平台。平台坚持“开放、中立、公益”的理念,把代码托管、模型共享、数据集托管、智能体开发体验和算力服务整合在一起,为开发者提供从开发、训练到部署的一站式体验。
更多推荐



所有评论(0)