Java数组

1.Java 数组的基本概念

数组在 Java 中是用来存储相同类型数据的集合,可以容纳多个元素,并通过索引(位置编号)来访问和管理这些元素。数组的特点是长度固定只能存储相同类型的元素。在 Java 中,数组分为两种类型:

  • 基本类型数组 :用于存储原始数据类型的值(如 intdoublechar 等)。
  • 引用类型数组 :用于存储对象或类实例的引用(如 String、自定义类等)。
1.1.数组的结构和内存分配

在 Java 中,数组是一个对象,所有数组都派生自 java.lang.Object。这意味着数组本身在堆(Heap)中分配内存,数组对象包含一个指向数据的引用。在数组中,数据元素是连续存储的,因此可以通过索引快速访问每个元素。

1.2.数组的声明与初始化

数组的声明、创建和初始化步骤包括以下几种方式:

  1. 声明:指定数组的数据类型和数组名称。
  2. 创建 :通过 new 关键字分配内存并定义数组长度。
  3. 初始化:为数组的各个位置赋初始值,可以使用字面量初始化或通过遍历初始化。

示例代码:

java 复制代码
// 1. 声明和创建基本类型数组
int[] numbers = new int[5];  // 声明并创建一个长度为5的int类型数组

// 2. 直接初始化
int[] numbers = {1, 2, 3, 4, 5};  // 声明并初始化数组元素

// 3. 声明和创建引用类型数组
String[] names = new String[3];   // 声明并创建一个长度为3的String数组
names[0] = "Alice";               // 初始化第一个元素

:数组的大小在创建时确定,并且在 Java 中数组一旦创建,长度就不可更改。如果需要动态增删元素,可以考虑使用 ArrayList 等集合类。

1.3.数组的默认值

在 Java 中,数组在创建后会自动初始化各个元素为类型默认值:

  • 基本数据类型:
    • byteshortintlong 默认值为 0
    • floatdouble 默认值为 0.0
    • char 默认值为 \u0000(空字符)
    • boolean 默认值为 false
  • 引用类型:默认值为 null

示例代码:

java 复制代码
int[] numbers = new int[3];  // 初始化为 {0, 0, 0}
String[] names = new String[3];  // 初始化为 {null, null, null}

2.基本类型数组

基本类型数组用于存储原始数据类型的值,比如 intdoubleboolean 等。Java 中的八种基本数据类型是:byteshortintlongfloatdoublecharboolean。这些类型的数组只能存储与类型一致的元素,并且创建时自动分配内存和默认值。

2.1 基本类型数组的声明、创建和初始化

基本类型数组的定义分为以下几个步骤:

  1. 声明:指定数组的类型和名称。
  2. 创建 :使用 new 关键字分配内存空间并指定数组长度。
  3. 初始化:为数组元素赋值,可以通过直接赋值或遍历赋值。

代码示例

java 复制代码
// 声明一个int类型数组
int[] numbers;

// 创建一个长度为5的int数组
numbers = new int[5];

// 初始化数组元素
numbers[0] = 10;
numbers[1] = 20;
numbers[2] = 30;

// 也可以在声明时直接初始化
int[] numbers = {1, 2, 3, 4, 5};  // 数组字面量初始化
2.2 基本类型数组的默认值

在 Java 中,数组创建后会自动初始化每个元素为对应类型的默认值。这些默认值是:

  • byteshortintlong 类型的默认值为 0
  • floatdouble 的默认值为 0.0
  • char 类型的默认值为 \u0000(空字符)
  • boolean 类型的默认值为 false

代码示例

java 复制代码
// 声明并创建一个int数组,长度为3
int[] numbers = new int[3];  // 默认值为 {0, 0, 0}

// 声明并创建一个boolean数组,长度为2
boolean[] flags = new boolean[2];  // 默认值为 {false, false}
2.3 基本类型数组的访问和修改

可以使用索引来访问和修改数组元素的值。索引从 0 开始到 数组长度 - 1。如果访问超过范围的索引,会抛出 ArrayIndexOutOfBoundsException

代码示例

java 复制代码
int[] numbers = {1, 2, 3, 4, 5};

// 访问数组元素
int firstElement = numbers[0];   // 获取第一个元素,值为1

// 修改数组元素
numbers[0] = 10;                 // 修改第一个元素,值改为10
2.4 基本类型数组的遍历

可以使用 for 循环或增强的 for-each 循环来遍历基本类型数组:

代码示例

java 复制代码
int[] numbers = {1, 2, 3, 4, 5};

// 使用for循环遍历
for (int i = 0; i < numbers.length; i++) {
    System.out.println(numbers[i]);
}

// 使用增强for循环遍历
for (int num : numbers) {
    System.out.println(num);
}
2.5 基本类型数组的特点和适用场景
  • 存储的数据是连续的:基本类型数组在内存中是连续存储的,访问速度较快。
  • 不支持动态大小:基本类型数组的长度固定,无法在运行时更改大小。
  • 直接存储数据:基本类型数组存储的是实际的数值而非引用,访问效率高。
  • 不能与 Arrays.asList() 直接兼容 :由于自动装箱问题,基本类型数组无法直接转换为 List,可以考虑使用包装类数组或集合类如 ArrayList

场景示例

当需要固定长度的数值集合且性能要求较高时,适合使用基本类型数组。例如,存储大量传感器读数、计算分数、简单排序或统计等场景。

3.引用类型数组

引用类型数组用于存储对象或类实例的引用,例如 String、自定义类等。与基本类型数组不同,引用类型数组存储的是对象的引用(地址)而非对象本身。这类数组在存储和访问上稍微复杂一些,因为每个数组元素都是一个对象引用,访问时需要特别注意引用的初始化。

3.1 引用类型数组的声明、创建和初始化

引用类型数组的定义流程与基本类型数组类似,包含声明、创建和初始化步骤。

  1. 声明:指定引用类型和数组名称。
  2. 创建 :通过 new 关键字分配内存并指定数组的长度。
  3. 初始化:为数组的每个位置分配对象引用,可以在声明时直接初始化。

代码示例

java 复制代码
// 声明并创建一个 String 类型的引用数组
String[] names = new String[3];

// 初始化数组元素
names[0] = "Alice";
names[1] = "Bob";
names[2] = "Charlie";

// 声明并初始化数组
String[] names = {"Alice", "Bob", "Charlie"};

可以存储任意类的对象,因此可以定义自定义类的数组:

java 复制代码
// 定义一个自定义类
class Person {
    String name;
    int age;
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

// 创建并初始化自定义类对象的数组
Person[] people = new Person[2];
people[0] = new Person("Alice", 30);
people[1] = new Person("Bob", 25);
3.2 引用类型数组的默认值

引用类型数组在创建时,各元素的默认值为 null,因为引用类型数组存储的是对象的引用,而此时并未创建对象。如果未初始化引用类型数组中的元素,访问时会产生 NullPointerException

代码示例

java 复制代码
// 声明并创建一个 String 类型的引用数组,长度为3
String[] names = new String[3];  // 默认值为 {null, null, null}
3.3 引用类型数组的访问和修改

与基本类型数组一样,可以通过索引访问和修改引用类型数组的元素。需要特别注意的是,引用类型数组的元素是对象的引用,修改数组的某个元素指向新的对象并不会影响其他元素。

代码示例

java 复制代码
String[] names = {"Alice", "Bob", "Charlie"};

// 访问数组元素
System.out.println(names[0]);  // 输出 "Alice"

// 修改数组元素引用
names[0] = "David";            // 将第一个元素的引用更改为新的字符串 "David"
3.4 引用类型数组的遍历

引用类型数组的遍历方式与基本类型数组相同,可以使用 for 循环或增强的 for-each 循环:

代码示例

java 复制代码
String[] names = {"Alice", "Bob", "Charlie"};

// 使用for循环遍历
for (int i = 0; i < names.length; i++) {
    System.out.println(names[i]);
}

// 使用增强for循环遍历
for (String name : names) {
    System.out.println(name);
}
3.5 引用类型数组的特点和适用场景
  • 存储对象的引用:引用类型数组的每个元素存储的是对象的引用而非对象本身。
  • 默认值为 null :创建引用类型数组后,所有元素的默认值均为 null,需谨慎处理。
  • 支持任何类类型 :可以是 Java 自带类如 String 的数组,也可以是自定义类的数组,具有较高的灵活性。
  • 可以与 Arrays.asList() 直接兼容 :引用类型数组可以直接转换为 List,因为它们不是基本数据类型。

场景示例

引用类型数组适用于存储对象的集合,例如保存一组 String 值(如学生名单)或自定义类实例(如学生信息、订单等)。

4.多维数组

Java 支持多维数组,最常用的是二维数组,不过 Java 中理论上可以创建任意维度的数组。多维数组是数组的数组,例如,二维数组中的每个元素也是一个数组。与一维数组不同,多维数组可以用来表示表格、矩阵等结构。

4.1 二维数组的声明、创建和初始化

二维数组的创建步骤与一维数组类似,包含声明、创建和初始化步骤:

  1. 声明:指定数组的类型和名称,同时使用两组方括号表示二维。
  2. 创建 :通过 new 关键字分配内存空间,并定义每个维度的大小。
  3. 初始化:可以在声明时直接初始化,或者通过嵌套循环初始化。

代码示例

java 复制代码
// 声明并创建一个 2行3列 的二维 int 数组
int[][] matrix = new int[2][3];

// 通过初始化设置每个元素的值
matrix[0][0] = 1;
matrix[0][1] = 2;
matrix[0][2] = 3;
matrix[1][0] = 4;
matrix[1][1] = 5;
matrix[1][2] = 6;

// 也可以直接声明并初始化
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};
4.2 不规则(锯齿形)二维数组

在 Java 中,二维数组不要求每一行的列数相同,这种结构称为不规则或锯齿形数组。可以在声明时指定行数,再为每一行分配不同的列数。

代码示例

java 复制代码
// 创建一个 3行 的不规则二维数组
int[][] jaggedArray = new int[3][];

// 为每一行分配不同的列数
jaggedArray[0] = new int[2];  // 第一行有2列
jaggedArray[1] = new int[3];  // 第二行有3列
jaggedArray[2] = new int[1];  // 第三行有1列

// 初始化各个元素
jaggedArray[0][0] = 1;
jaggedArray[0][1] = 2;
// 依此类推
4.3 二维数组的访问和遍历

二维数组的访问需要使用两个索引,第一个索引表示行,第二个索引表示列。可以使用嵌套的 for 循环来遍历二维数组:

代码示例

java 复制代码
int[][] matrix = {
    {1, 2, 3},
    {4, 5, 6}
};

// 使用嵌套的for循环遍历二维数组
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循环遍历二维数组
for (int[] row : matrix) {
    for (int num : row) {
        System.out.print(num + " ");
    }
    System.out.println();
}
4.4 二维数组的默认值

二维数组在声明后,数组元素会自动初始化为默认值:

  • 对于基本类型的二维数组,元素的默认值与一维数组一致(如 0false)。
  • 对于引用类型的二维数组,元素的默认值为 null

代码示例

java 复制代码
int[][] numbers = new int[2][3];  // 默认值为 {{0, 0, 0}, {0, 0, 0}}
String[][] names = new String[2][2];  // 默认值为 {{null, null}, {null, null}}
4.5 二维数组的应用场景
  • 矩阵计算:如数学中的矩阵运算。
  • 表格数据:可以用二维数组来存储表格或图形数据,例如棋盘、电子表格。
  • 图形图像处理:二维数组常用于存储图像像素或图形的点阵信息。
  • 不规则数据结构:通过不规则数组,可以轻松构建不同宽度的"表格"结构。

5.java.util.Arrays 类的常用方法

java.util.Arrays 是 Java 提供的一个数组操作工具类,包含多种静态方法,可以帮助开发者快速地对数组进行排序、查找、转换、复制等操作。以下是 Arrays 类的主要方法及其详细使用说明:


5.1 Arrays.asList()

作用 :将引用类型数组转换为 List
注意asList() 只适用于引用类型数组(如 String[]Integer[]),不适用于基本类型数组(如 int[]double[])。如果传入基本类型数组,则会将整个数组作为 List 的一个元素,而不是逐个元素转换。

代码示例

java 复制代码
// 引用类型数组转换为List
String[] strArray = {"apple", "banana", "orange"};
List<String> list = Arrays.asList(strArray);  // 返回固定大小的 List

// 基本类型数组转换的问题
int[] intArray = {1, 2, 3};
List<int[]> intList = Arrays.asList(intArray); // 错误,整个数组成为单个元素
  • 返回结果Arrays.asList() 返回的是一个固定大小的 List,无法增加或删除元素,若尝试增删操作会抛出 UnsupportedOperationException

5.2 Arrays.sort()

作用 :对数组进行排序。Arrays.sort() 支持对基本类型和引用类型数组进行排序,可以按自然顺序排序,也支持自定义排序规则。

  • 基本类型数组排序:按升序排序。
  • 引用类型数组排序 :需要元素类型实现 Comparable 接口,按自然顺序排序。

代码示例

java 复制代码
// 基本类型数组排序
int[] numbers = {4, 2, 5, 1};
Arrays.sort(numbers);  // 升序排序,结果为 {1, 2, 4, 5}

// 引用类型数组排序(按字母顺序)
String[] names = {"Charlie", "Alice", "Bob"};
Arrays.sort(names);  // 结果为 {"Alice", "Bob", "Charlie"}

// 自定义排序(按降序排序)
Arrays.sort(names, Comparator.reverseOrder());
  • 时间复杂度Arrays.sort() 基于双轴快速排序(Dual-Pivot Quicksort)算法,时间复杂度为 O(n log n)

5.3 Arrays.binarySearch()

作用 :在已排序的数组中查找指定元素的索引。
注意binarySearch() 只能在已排序的数组上使用,若数组未排序,结果可能不正确。

  • 返回值 :如果找到元素,返回其索引;如果找不到,返回负数。返回值为 -(插入点) - 1,其中"插入点"是元素应当插入的位置索引。

代码示例

java 复制代码
int[] numbers = {1, 3, 5, 7, 9};
int index = Arrays.binarySearch(numbers, 5);  // 返回2(元素5的位置)
int notFoundIndex = Arrays.binarySearch(numbers, 6);  // 返回-4,表示元素6应插入在索引3
  • 适用场景:快速查找数组中的元素索引,适合用于频繁查找操作的场景。

5.4 Arrays.copyOf()Arrays.copyOfRange()

作用:创建数组的副本,或复制数组的某个范围。

  • Arrays.copyOf(array, newLength):复制整个数组,或根据指定长度创建截断或扩展的数组。
  • Arrays.copyOfRange(array, from, to):复制数组的某一范围,包括起始索引,不包括终止索引。

代码示例

java 复制代码
int[] original = {1, 2, 3, 4, 5};

// 复制整个数组
int[] copyArray = Arrays.copyOf(original, original.length);  // {1, 2, 3, 4, 5}

// 复制前3个元素
int[] partialCopy = Arrays.copyOf(original, 3);  // {1, 2, 3}

// 复制索引1到3的元素
int[] rangeCopy = Arrays.copyOfRange(original, 1, 4);  // {2, 3, 4}

5.5 Arrays.equals()Arrays.deepEquals()

作用:比较两个数组是否相等。

  • equals():用于比较一维数组是否相等,对比的是每个元素的值。
  • deepEquals():适合用于多维数组,比较的是多维数组中的每个子数组是否相等。

代码示例

java 复制代码
int[] array1 = {1, 2, 3};
int[] array2 = {1, 2, 3};
boolean isEqual = Arrays.equals(array1, array2);  // 返回true

int[][] matrix1 = {{1, 2}, {3, 4}};
int[][] matrix2 = {{1, 2}, {3, 4}};
boolean isDeepEqual = Arrays.deepEquals(matrix1, matrix2);  // 返回true

5.6 Arrays.fill()

作用:将数组的所有元素都填充为指定的值。适用于基本类型数组和引用类型数组。

代码示例

java 复制代码
int[] numbers = new int[5];
Arrays.fill(numbers, 1);  // 将所有元素设置为1,结果为 {1, 1, 1, 1, 1}

String[] names = new String[3];
Arrays.fill(names, "Unknown");  // 将所有元素设置为 "Unknown"
  • 适用场景:用于数组的初始化或重置操作。

5.7 Arrays.toString()Arrays.deepToString()

作用 :将数组转换为字符串形式,一维数组用 toString(),多维数组用 deepToString()

代码示例

java 复制代码
int[] numbers = {1, 2, 3};
System.out.println(Arrays.toString(numbers));  // 输出: [1, 2, 3]

int[][] matrix = {{1, 2}, {3, 4}};
System.out.println(Arrays.deepToString(matrix));  // 输出: [[1, 2], [3, 4]]
  • 适用场景:调试时用于查看数组的内容。

5.8 Arrays.hashCode()Arrays.deepHashCode()

作用:计算数组的哈希码,适用于一维数组和多维数组的哈希计算。

  • hashCode():用于计算一维数组的哈希码。
  • deepHashCode():用于计算多维数组的哈希码。

代码示例

java 复制代码
int[] numbers = {1, 2, 3};
int hash = Arrays.hashCode(numbers);  // 计算一维数组的哈希码

int[][] matrix = {{1, 2}, {3, 4}};
int deepHash = Arrays.deepHashCode(matrix);  // 计算多维数组的哈希码
5.9 Arrays.parallelSort()

作用 :对数组进行并行排序(适用于大数组,提升性能)。与 sort() 不同,parallelSort() 使用了多线程技术,在多核处理器上性能更高。

代码示例

java 复制代码
int[] numbers = {5, 3, 8, 2};
Arrays.parallelSort(numbers);  // 并行排序
  • 适用场景:处理大规模数据时,可以提高排序效率。

5.10 Arrays.stream()

作用 :将数组转换为 Stream 对象,便于使用流式操作。对于对象数组(如 String[]),会转换为 Stream<T>,而基本类型数组(如 int[])会转换为对应的 IntStreamLongStreamDoubleStream

代码示例

java 复制代码
int[] numbers = {1, 2, 3, 4, 5};
IntStream stream = Arrays.stream(numbers);  // 使用stream操作
stream.forEach(System.out::println);
相关推荐
读书点滴几秒前
笨方法学python -练习14
java·前端·python
lingRJ7772 分钟前
微服务架构下的抉择:Consul vs. Eureka,服务发现该如何选型?
java·eureka·springcloud·consul·backend·microservices·servicediscovery
RainbowSea2 分钟前
问题:后端由于字符内容过长,前端展示精度丢失修复
java·spring boot·后端
C182981825755 分钟前
OOM电商系统订单缓存泄漏,这是泄漏还是溢出
java·spring·缓存
风象南19 分钟前
SpringBoot 控制器的动态注册与卸载
java·spring boot·后端
我是一只代码狗1 小时前
springboot中使用线程池
java·spring boot·后端
hello早上好1 小时前
JDK 代理原理
java·spring boot·spring
PanZonghui1 小时前
Centos项目部署之Java安装与配置
java·linux
沉着的码农2 小时前
【设计模式】基于责任链模式的参数校验
java·spring boot·分布式
Mr_Xuhhh2 小时前
信号与槽的总结
java·开发语言·数据库·c++·qt·系统架构