一、数组概述数组Array是相同类型数据的有序集合。数组描述的是相同类型的若干个数据按照一定的先后次序排列组合而成。1.1 数组的特点长度固定数组一旦创建大小不可改变类型相同所有元素必须是相同数据类型有序性元素在内存中连续存储通过下标索引访问可以存储基本类型和引用类型数组本身是对象在堆内存中分配空间1.2 数组的分类按维度一维数组、二维数组、多维数组按数据类型基本数据类型数组、引用数据类型数组二、一维数组2.1 数组的声明语法格式数据类型[] 数组名; // 推荐方式数据类型 数组名[]; // C语言风格不推荐示例int[] scores; // 推荐double[] prices;String[] names;int scores[]; // 不推荐C语言风格2.2 数组的创建内存分配语法格式数组名 new 数据类型[数组长度];示例scores new int[5]; // 创建长度为5的int数组prices new double[10]; // 创建长度为10的double数组声明并创建合并写法int[] scores new int[5];String[] names new String[3];2.3 数组的初始化静态初始化指定内容长度由系统决定// 完整格式 int[] scores new int[]{100, 98, 95, 88, 90};// 简化格式推荐int[] scores {100, 98, 95, 88, 90};String[] names {张三, 李四, 王五};动态初始化指定长度元素为默认值int[] scores new int[5]; // 元素默认值0double[] prices new double[3]; // 元素默认值0.0boolean[] flags new boolean[2]; // 元素默认值falseString[] names new String[4]; // 元素默认值null注意不能同时指定长度和内容错误示例int[] arr new int[3]{1,2,3};2.4 数组元素的访问通过下标/索引访问下标从0开始到长度-1结束int[] arr {10, 20, 30, 40, 50};// 获取元素System.out.println(arr[0]); // 输出10System.out.println(arr[2]); // 输出30// 修改元素arr[1] 200; System.out.println(arr[1]); // 输出200// 获取数组长度System.out.println(arr.length); // 输出52.5 数组的遍历方式一普通for循环int[] arr {10, 20, 30, 40, 50};for (int i 0; i arr.length; i){ System.out.println(第 i 个元素 arr[i]); }方式二增强for循环foreachint[] arr {10, 20, 30, 40, 50};// 只能读取不能修改for (int num : arr) { System.out.println(num); }foreach特点代码简洁但无法获取索引只能遍历读取不能修改元素三、二维数组与多维数组.1 二维数组的声明与创建二维数组本质上是数组的数组可以理解为一个表格有行和列两个维度。创建二维数组时可以同时指定行数和列数也可以只指定行数不指定列数这样就形成了不规则数组。不规则数组是Java的特色功能每行可以有不同的列数这在某些特殊场景下非常有用可以节省内存空间。3.2 二维数组的初始化静态初始化静态初始化二维数组时使用嵌套的大括号表示每行的元素。既可以创建规则的矩阵形式也可以创建不规则的形式每行的元素个数可以不同。动态初始化动态初始化二维数组时指定行数和列数所有元素自动初始化为对应类型的默认值。3.3 二维数组的访问与遍历二维数组需要两个下标来访问元素第一个下标表示行号第二个下标表示列号。遍历二维数组需要使用双层循环外层循环遍历行内层循环遍历列。既可以使用普通for循环的嵌套也可以使用增强for循环的嵌套。使用增强for循环时外层循环的变量是一维数组类型。四、数组常用操作4.1 求最大值与最小值求数组最大值的算法思路将第一个元素作为初始最大值然后依次与后面的每个元素比较如果遇到更大的元素就更新最大值。求最小值的算法完全相同只是比较方向相反。4.2 数组求和与平均值数组求和初始化一个累加变量为0遍历数组将每个元素累加到累加变量中。平均值就是总和除以数组长度注意要进行类型转换避免整数除法的精度丢失问题。4.3 数组反转数组反转的高效算法使用对称交换的方式只需要遍历数组的前半部分将第i个元素与倒数第i个元素交换。这种方式的时间复杂度是O(n/2)空间复杂度是O(1)不需要额外数组空间。4.4 数组查找线性查找遍历数组逐个比较找到目标元素则返回下标遍历完仍未找到则返回-1。线性查找的优点是数组不需要有序缺点是平均查找效率较低。二分查找要求数组必须有序每次将查找范围缩小一半效率很高。JDK的Arrays工具类已经提供了二分查找的实现。4.5 数组复制数组复制有三种常用方式手动复制使用循环逐个元素复制最基础但代码繁琐System.arraycopy()JDK提供的本地方法效率最高可以指定源位置和目标位置Arrays.copyOf()基于System.arraycopy()封装使用更方便会创建新数组注意直接进行引用赋值arr1 arr2不是数组复制两个引用会指向同一个数组对象修改其中一个会影响另一个。五、Arrays 工具类java.util.Arrays是JDK提供的专门用于操作数组的工具类包含大量静态方法是数组操作的首选工具。使用前需要导入该类。5.1 常用方法详解toString()将数组转换为字符串形式方便打印输出是调试时最常用的方法sort()对数组进行升序排序底层使用优化的快速排序算法效率很高binarySearch()二分查找要求数组必须有序找到返回下标找不到返回负数fill()用指定值填充数组的全部或部分元素copyOf() / copyOfRange()复制数组可以指定新数组长度或复制范围equals()比较两个数组的内容是否完全相同deepToString() / deepEquals()针对多维数组的字符串转换和比较六、数组内存分析6.1 JVM内存区域划分内存区域主要作用存储内容栈Stack方法执行的内存模型基本数据类型变量、对象引用变量、方法参数堆Heap对象存储区域所有new出来的对象和数组是垃圾回收的主要区域方法区存储类的元信息类信息、静态变量、常量池、方法代码6.2 数组内存机制数组变量存储在栈内存中保存的是数组对象在堆内存中的地址值而不是数组内容本身。使用new创建数组时会在堆内存中分配连续空间并将首地址赋值给栈中的引用变量。当进行引用赋值时只是将地址值复制给另一个引用变量两个引用指向同一个堆内存中的数组对象。通过任意一个引用修改数组内容另一个引用也会看到修改后的结果。七、常见问题与注意事项7.1 数组下标越界异常这是数组操作中最常见的运行时异常。当下标小于0或者大于等于数组长度时就会抛出此异常。编写代码时一定要注意下标的有效范围是0到length-1。7.2 空指针异常当数组引用变量为null时尝试访问数组元素就会抛出空指针异常。使用数组前一定要确保数组已经正确初始化。7.3 数组长度不可变性数组一旦创建长度就固定了不能修改。length属性是只读的。如果需要改变数组大小只能创建一个新的更大的数组然后将原数组内容复制过去。这也是ArrayList等集合类的底层实现原理。7.4 数组作为方法参数和返回值数组作为方法参数时传递的是数组的引用地址方法内部对数组的修改会影响到原数组。数组也可以作为方法的返回值返回的同样是数组引用。八、数组排序算法8.1 冒泡排序冒泡排序是最基础的交换排序算法核心思想是通过相邻元素的比较和交换使较大的元素逐渐冒泡到数组末尾。每一轮排序都会确定一个最大元素的最终位置。冒泡排序可以优化如果某一轮比较中没有发生任何交换说明数组已经有序可以提前结束排序。8.2 选择排序选择排序的思路是每一轮从未排序部分选择最小的元素放到已排序部分的末尾。选择排序的交换次数比冒泡排序少但时间复杂度相同。8.3 插入排序插入排序将数组分为已排序和未排序两部分每次从未排序部分取出第一个元素插入到已排序部分的合适位置。插入排序在数据基本有序时效率很高。学习总结数组是Java中最基础也是最重要的数据结构是学习集合框架、算法和数据结构的基础。重点掌握数组的内存机制、常用操作和Arrays工具类的使用这些都是实际开发中每天都会用到的知识。