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);
相关推荐
刘大浪10 分钟前
IDEA 2024安装指南(含安装包以及使用说明 cannot collect jvm options 问题 四)
java
Cod_Next16 分钟前
Mac系统下配置 Tomcat 运行环境
java·macos·tomcat
小白不太白95021 分钟前
设计模式之建造者模式
java·设计模式·建造者模式
p-knowledge22 分钟前
建造者模式(Builder Pattern)
java·开发语言·建造者模式
Str_Null32 分钟前
Seatunnel运行时报错Caused by: java.lang.NoClassDefFoundError: com/mysql/cj/MysqlType
java·seatunnel
麻花20131 小时前
WPF里面的C1FlexGrid表格控件添加RadioButton单选
java·服务器·前端
理想不理想v1 小时前
【经典】webpack和vite的区别?
java·前端·javascript·vue.js·面试
请叫我青哥1 小时前
第五十二条:谨慎使用重载
java·spring
疯一样的码农1 小时前
Apache Maven简介
java·maven·apache
小安同学iter2 小时前
Java进阶五 -IO流
java·开发语言·intellij-idea