欢迎光临
我们一直在努力

Java数组详细知识点说明

数组是Java中一种非常重要的数据结构,用于存储固定大小的同类型元素。掌握数组是学习Java的基础。下面从定义、声明、创建、初始化、操作、内存模型等方面进行详细说明。

一、数组的定义

数组是一个容器对象,它能够在内存中连续存储固定数量的相同类型的数据。

  • 特点:

    • 长度一旦确定,不可改变。

    • 所有元素必须是同一数据类型(可以是基本类型或引用类型)。

    • 通过索引访问元素,索引从 0 开始。

    • 数组本身是对象,存储在堆内存中。

二、数组的声明

声明数组只是定义了一个引用变量,并不创建数组对象。

// 推荐方式(类型[] 数组名)
int[] arr1; // 声明一个int数组
String[] arr2; // 声明一个String数组

// 另一种方式(类型 数组名[]),为了与C/C++兼容,不推荐
int arr3[];

  • 声明时不能指定数组长度(如 int[5] arr; 是错误的)。

  • 数组变量存储的是指向数组对象的引用(地址)。

三、数组的创建

使用 new 关键字分配内存空间,并指定长度。

int[] arr = new int[5]; // 创建长度为5的int数组,每个元素默认值为0
String[] names = new String[3]; // 创建长度为3的String数组,默认值为null

  • 长度可以是变量或常量,但必须是非负整数。

  • 数组创建后,每个元素会自动赋予默认值:

    • 整数类型(byte, short, int, long):0

    • 浮点类型(float, double):0.0

    • 字符类型(char):'\\u0000'(空字符)

    • 布尔类型(boolean):false

    • 引用类型:null

四、数组的初始化

为数组元素赋初始值。有两种方式:

4.1 静态初始化

在创建数组的同时直接指定元素值,由编译器推断长度。

int[] arr = {1, 2, 3, 4, 5}; // 简化语法
String[] names = new String[]{"Alice", "Bob", "Charlie"}; // 完整语法

4.2 动态初始化

先创建数组(指定长度),然后通过循环或其他方式逐一赋值。

int[] arr = new int[3];
for (int i = 0; i < arr.length; i++) {
arr[i] = i * 10;
}

五、数组的访问

通过索引访问元素,索引范围:0 到 length-1。

int[] arr = {10, 20, 30};
System.out.println(arr[0]); // 输出10
arr[1] = 25; // 修改第二个元素为25

  • 每个数组都有一个 length 属性,表示数组的长度(元素个数)。

  • 访问越界会抛出 ArrayIndexOutOfBoundsException。

六、数组的遍历

6.1 普通for循环

for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}

6.2 增强for循环(for-each)

for (int num : arr) {
System.out.println(num);
}

  • 增强for循环不能修改数组元素(不能通过迭代变量赋值),也无法获取索引。

6.3 Java 8 Stream方式

import java.util.Arrays;
Arrays.stream(arr).forEach(System.out::println);

确保arr是一个已初始化的数组变量。例如:

int[] arr = {1, 2, 3, 4, 5};

七、数组的内存结构

  • 数组变量存储在栈内存中,存储的是数组对象的引用(地址)。

  • 数组对象本身存储在堆内存中,包含:类型信息、长度标识、以及连续的元素数据。

  • 基本类型数组直接存储值;引用类型数组存储的是对象的引用(地址)。

int[] a = new int[3]; // a指向堆中的数组对象

八、多维数组

Java中多维数组本质上是“数组的数组”,可以是不规则的(每个子数组长度可以不同)。

8.1 声明和创建

int[][] matrix = new int[3][4]; // 3行4列的二维数组(每个子数组长度4)
int[][] triangle = new int[3][]; // 只指定行数,列数未定
triangle[0] = new int[1]; // 每一行可以单独创建不同长度的数组
triangle[1] = new int[2];
triangle[2] = new int[3];

8.2 静态初始化及遍历

int[][] arr = {
{1, 2, 3},
{4, 5},
{6, 7, 8, 9}
};

for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}

1 2 3
4 5
6 7 8 9

8.3 访问

int value = arr[1][0]; // 获取第二行第一列的元素(值为4)
arr[2][2] = 10;

代码说明

  • int value = arr[1][0]; 表示从二维数组 arr 中获取第二行第一列的元素,并将其赋值给变量 value。
  • arr[2][2] = 10; 表示将二维数组 arr 的第三行第三列的元素赋值为 10。

九、数组的常用操作(借助 java.util.Arrays 类)

Arrays 类提供了大量静态方法简化数组操作。

9.1 复制数组
  • System.arraycopy(Object src, int srcPos, Object dest, int destPos, int length):高效复制(native方法)。

    int[] src = {1, 2, 3, 4, 5};
    int[] dest = new int[5];
    System.arraycopy(src, 1, dest, 2, 3); // 从src索引1开始,复制3个元素,放到dest索引2开始
    // dest: [0, 0, 2, 3, 4]

  Arrays.copyOf(original, newLength):返回一个新数组,包含原数组的前newLength个元素(或填充默认值)。

int[] newArr = Arrays.copyOf(src, 3); // [1, 2, 3]
int[] expanded = Arrays.copyOf(src, 10); // [1,2,3,4,5,0,0,0,0,0]

  • Arrays.copyOfRange(original, from, to):复制指定范围。

  • 数组的 clone() 方法:int[] copy = src.clone(); 返回一个完整副本(浅拷贝)。

9.2 排序

int[] nums = {3, 1, 4, 1, 5, 9};
Arrays.sort(nums); // 对整个数组排序
Arrays.sort(nums, 1, 4); // 对索引[1,4)范围内的元素排序

  • 对对象数组排序,要求元素实现了 Comparable 接口,或者提供 Comparator。

9.3 二分查找(数组必须有序)

int index = Arrays.binarySearch(nums, 4); // 返回4的索引,如果不存在返回负插入点

9.4 填充

int[] arr = new int[5];
Arrays.fill(arr, 10); // 所有元素设为10
Arrays.fill(arr, 1, 3, 20); // 索引[1,3)设为20

9.5 比较
  • Arrays.equals(arr1, arr2):比较两个一维数组是否相等(元素个数和对应元素相等)。

  • Arrays.deepEquals(arr1, arr2):比较多维数组

9.6 转换为字符串

int[] arr = {1, 2, 3};
System.out.println(Arrays.toString(arr)); // 输出 "[1, 2, 3]"
int[][] matrix = {{1,2},{3,4}};
System.out.println(Arrays.deepToString(matrix)); // 输出 "[[1, 2], [3, 4]]"

9.7 数组转List

String[] strArr = {"A", "B", "C"};
List<String> list = Arrays.asList(strArr);

十、数组的局限性

  • 长度固定:一旦创建无法扩容,需要扩容时必须新建数组并复制。

  • 类型固定:只能存储同一类型(或其子类型,通过多态可以存子类对象,但声明类型为父类)。

  • 添加/删除不便:没有直接的方法,需要手动移动元素。

  • 缺乏丰富的方法:相比集合框架(如 ArrayList),数组功能有限。

十一、数组与泛型

Java中不能直接创建泛型数组(如 T[] arr = new T[10]; 会编译错误),因为泛型在运行时类型会被擦除。但可以通过 (T[]) new Object[size] 强转,或者使用 ArrayList<T> 替代。

// 泛型数组的正确创建方式(通过反射)
public static <T> T[] newArray(Class<T> type, int length) {
return (T[]) Array.newInstance(type, length);
}

十二、数组的性能

  • 优点:随机访问快(O(1)),内存连续,对CPU缓存友好。

  • 缺点:插入和删除元素慢(需要移动大量元素),长度固定。

十三、常见错误

空指针异常:数组变量未初始化(为 null)就访问元素。

int[] arr = null;
System.out.println(arr[0]); // NullPointerException

  • 索引越界异常:索引超出 [0, length-1] 范围。

十四、最佳实践

  • 除非有明确的性能要求(如大量数据、对性能极致追求)或需要与遗留API交互,否则优先使用 ArrayList 等集合类,它们提供了动态扩容和丰富的方法。

  • 在方法间传递数组时,注意数组是引用传递,方法内部修改会影响原数组。

  • 避免在循环中频繁使用 System.arraycopy 手动扩容,考虑使用 ArrayList。

  • 使用 Arrays 工具类简化操作。

总结

Java数组是基础且重要的数据结构,理解其声明、创建、初始化、访问和常用操作是掌握Java编程的基石。虽然集合框架提供了更多便利,但数组在性能要求和底层实现中仍然不可或缺。希望通过本指南,你能全面掌握Java数组的知识点。

赞(0)
未经允许不得转载:171主机测评 » Java数组详细知识点说明
分享到: 更多 (0)

评论 抢沙发

  • 昵称 (必填)
  • 邮箱 (必填)
  • 网址