跳到主要内容Java 数组全面解析:定义、内存与工具类 | 极客日志Javajava
Java 数组全面解析:定义、内存与工具类
综述由AI生成详细解析了 Java 数组的基础知识,涵盖数组的定义、特点、分类(基本类型与引用类型、一维与多维)。深入探讨了数组的内存结构(栈与堆)、下标从 0 开始的原因。此外,还介绍了二维数组的声明与遍历,以及 java.util.Arrays 工具类的常用方法,如排序、查找、复制和流操作等。
SecGuard32 浏览 一、数组的概述
1、什么是数组?
在 Java 中,数组(Array)是一种容器,用于存储固定大小的同一种数据类型的多个元素。
数组在内存中是连续存储的,每个元素通过索引(从 0 开始)来访问。
2、数组的特点
固定长度:数组长度在创建时确定,不可动态改变
同类型元素:所有元素必须是相同数据类型(基本类型或引用类型)
连续内存分配:元素在内存中连续存储,支持高效随机访问
索引访问:通过索引(从 0 开始)访问元素,如 arr[0]
数组是对象:继承自 Object 类,可用 Object 类方法(如 toString()),有 length 属性,而不是方法
默认值初始化:创建时自动初始化默认值(如 int 为 0,boolean 为 false,引用为 null)
3、数组分类
按元素类型分类
| 类型 | 示例 | 特点 |
|---|
| 基本类型数组 | int[], char[], double[]等 | 存储基本数据类型值 |
| 对象引用数组 | String[], Object[], User[]等 | 存储对象引用(内存地址) |
按维度分类
| 类型 | 声明方式 | 示例 | 特点 |
|---|
| 一维数组 (常用) | 数据类型 [] 变量名 | int[] arr = new int[3]; | 线性结构,单行元素 |
| 二维数组 | 数据类型 [][] 变量名 | int[][] matrix = new int[2][3]; | 表格结构(数组的数组) |
| 多维数组 | 数据类型 [][][]... | |
int[][][] cube = new int[3][3][3];
二、一维数组
1、声明数组
int[] numbers;
int numbers[];
可以替换 int 为任意基本数据类型(如 double, char, boolean)或引用类型(如 String, Student)
2、分配内存空间
3、声明 + 初始化
int[] numbers = new int[5];
4、静态初始化(声明时直接赋值)
String[] names = new String[]{"Alice", "Bob", "Charlie"};
String[] names;
names = new String[]{"Alice", "Bob", "Charlie"};
int[] primes = {2, 3, 5, 7, 11};
5、动态初始化(先分配长度,后赋值)
int[] arr = new int[3];
arr[0] = 10;
错误写法:int[] arr = new int[5]{1,2,3,4,5}; // 错误的,后面有 {} 指定元素列表,就不能在 [] 中指定元素个数了
6、内存结构分析
- 声明引用变量
int[] arr; 在 栈 中创建引用变量 arr,初始值为 null(未指向任何对象)
- 实例化数组对象
arr = new int[3]; 在 堆 中开辟连续内存空间
- 分配空间 = 24 字节(对象头) + 元素占用空间(如 int[3] 为 24 + 3×4 = 36 字节)
- 元素按索引依次紧密排列(如地址 0x001 存 arr[0],0x005 存 arr[1],偏移量由
元素类型 决定)
- 地址赋值
- 堆中数组的
首地址 被赋给栈中的引用变量 arr(如输出 arr 显示 [I@5f150435,[表示一维数组,I 表示 int 类型,@后为地址的哈希值)
- 结果:arr[1] 输出 9,因 arr 和 arr2 指向同一堆对象
int[] arr = new int[3];
arr[0] = 5;
int[] arr2 = arr;
arr2[1] = 9;
7、数组下标为什么从 0 开始?
- 物理内存的连续性
- 数组在内存中以连续地址存储,
首地址 是第一个元素的起始位置
- 元素地址计算公式为:
元素地址 = 首地址 + 下标 × 数据类型字节大小
- 例如:int[](4 字节)的首地址为 1000 时:
- a[0] 地址 = 1000 + 0×4 = 1000
- a[1] 地址 = 1000 + 1×4 = 1004
- 若下标从 1 开始,公式需改为:
首地址 + (下标 -1)×字节大小,多出一次 减法 运算
- 减少 CPU 指令开销
- 加减法运算在 CPU 中属于基础指令但仍有耗时
- 数组访问是高频操作,从 0 开始可避免额外的
i-1 计算,提升寻址效率
三、多维数组(二维数组)
二维数组可以看成是 数组的数组,也可以理解为一个 矩阵结构。每个元素都是一个 一维数组。
1、固定大小的二维数组
int[][] matrix = new int[2][3];
2、静态初始化(直接赋值)
int[][] matrix1 = new int[][]{{1,2,3},{4,5,6}};
int[][] matrix = {{1,2,3},{4,5,6}};
3、动态初始化(每行不同长度 - 不规则数组)
int[][] jagged = new int[3][];
jagged[0] = new int[2];
jagged[1] = new int[4];
jagged[2] = new int[3];
注:int[][]arr = new int[][3]; // 错误写法
4、遍历二维数组
for(int i = 0; i < matrix.length; i++){
for(int j = 0; j < matrix[i].length; j++){
System.out.print(matrix[i][j] + " ");
}
System.out.println();
}
for(int[] row : matrix){
for(int value : row){
System.out.print(value + " ");
}
System.out.println();
}
5、内存结构分析
- 外层数组(行数组)
- 存储对每个
内层一维数组的引用(指针)
- 内存连续:外层数组本身是
连续存储 的
- 示例:
int[][] arr = new int[3][4] 会创建一个 长度为 3 的数组(每个元素是 int[] 类型)
- 内层数组(列数组)
- 存储实际数据
- 内存连续:每个内层数组在堆中是
独立分配 的连续内存块
- 不同内层数组之间
内存地址不连续(可能分散在堆中)
int[][] arr = new int[3][4];
栈 (Stack) ┌──────┐
| arr │ → 指向堆中的外层数组
└──────┘
堆 (Heap)
外层数组 (连续)
内层数组 (独立连续块)
┌──────────┐ ┌───────────┐
│ arr[0] │ ─────→│ [0][0] = 0│
├──────────┤ │ [0][1] = 0│
│ arr[1] │ ──┐ │ [0][2] = 0│
├──────────┤ │ │ [0][3] = 0│
│ arr[2] │ ──┼──→└───────────┘
└──────────┘ │ │
┌───────────┐
└──→│ [1][0] = 0│
│ [1][1] = 0│
│ [1][2] = 0│
│ [1][3] = 0│
└───────────┘
┌───────────┐
│ [2][0] = 0│
│ [2][1] = 0│
│ [2][2] = 0│
│ [2][3] = 0│
└───────────┘
四、java.util.Arrays 工具类详解
1、数组转字符串
int[][] matrix = {{1,2},{3,4}};
System.out.println(Arrays.deepToString(matrix));
int[] arr = {1,2,3};
System.out.println(Arrays.toString(arr));
2、数组转集合
asList():将数组转为 固定大小 的 List(不可增删,可修改元素)
String[] array = {"A","B","C"};
List<String> list = Arrays.asList(array);
list.set(0,"X");
List<String> list2 = new ArrayList<>(Arrays.asList(array));
3、数组排序
int[] arr = {5,9,1,3};
Arrays.sort(arr, 1, 3);
Arrays.sort(names, (a, b) -> b.compareTo(a));
对象数组:使用归并排序(稳定排序),需实现 Comparable 接口
String[] names = {"John","Alice","Bob"};
Arrays.sort(names);
int[] arr = {5,2,9,1};
Arrays.sort(arr);
4、二分查找
binarySearch():找到返回索引;未找到返回 -(插入点) - 1,前提必须 已排序
int[] sorted = {1,3,5,7};
int index1 = Arrays.binarySearch(sorted, 5);
int index2 = Arrays.binarySearch(sorted, 4);
5、数组比较
deepEquals():用于 多维数组 的深度比较
int[][] matrix1 = {{1,2},{3,4}};
int[][] matrix2 = {{1,2},{3,4}};
boolean deepEqual = Arrays.deepEquals(matrix1, matrix2);
equals():比较两个数组内容是否相等(长度和对应元素相同)
int[] a = {1,2};
int[] b = {1,2};
boolean isEqual = Arrays.equals(a, b);
6、数组填充
fill():将数组所有元素(或指定范围)设为指定值
int[] arr = new int[3];
Arrays.fill(arr, 10);
Arrays.fill(arr, 1, 3, 5);
7、数组复制
copyOfRange():复制指定范围,还是 左闭右开
int[] rangeCopy = Arrays.copyOfRange(original, 1, 3);
int[] original = {1,2,3};
int[] copy = Arrays.copyOf(original, 2);
int[] extended = Arrays.copyOf(original, 5);
8、流与并行操作(Java 8+)
stream(T[] array):将数组转换为流(Stream),可配合流式操作
int[] arr = {1,2,3};
IntStream stream = Arrays.stream(arr);
stream.forEach(System.out::println);
long count = Arrays.stream(new int[]{1,2,3}).filter(x -> x > 1).count();
int[] array = {1,2,3};
List<Integer> list = Arrays.stream(array)
.boxed()
.collect(Collectors.toList());
parallelSort():利用多核处理器并行排序,适合大数据量(大于 10000 时性能优势明显)
int[] largeArray = ...;
Arrays.parallelSort(largeArray);
相关免费在线工具
- Keycode 信息
查找任何按下的键的javascript键代码、代码、位置和修饰符。 在线工具,Keycode 信息在线工具,online
- Escape 与 Native 编解码
JavaScript 字符串转义/反转义;Java 风格 \uXXXX(Native2Ascii)编码与解码。 在线工具,Escape 与 Native 编解码在线工具,online
- JavaScript / HTML 格式化
使用 Prettier 在浏览器内格式化 JavaScript 或 HTML 片段。 在线工具,JavaScript / HTML 格式化在线工具,online
- JavaScript 压缩与混淆
Terser 压缩、变量名混淆,或 javascript-obfuscator 高强度混淆(体积会增大)。 在线工具,JavaScript 压缩与混淆在线工具,online
- Base64 字符串编码/解码
将字符串编码和解码为其 Base64 格式表示形式即可。 在线工具,Base64 字符串编码/解码在线工具,online
- Base64 文件转换器
将字符串、文件或图像转换为其 Base64 表示形式。 在线工具,Base64 文件转换器在线工具,online