• 按一定顺序排列的同类型数据的集合称为数组,本身是一种引用类型

声明

  1. int[] arr; // 数组元素类型[] 数组名;
  2. int arr[]; // 数组元素类型 数组名[]; // 不推荐

初始化

  1. // 静态初始化
  2. // 数组名 = new 数组元素类型[] {元素 1, 元素 2, ...};
  3. // 在堆空间开辟一块内存区域来存储数组的元素(new)
  4. // 将 该内存区域的地址值 赋值给 该数组的引用变量 arr(引用)
  5. int[] arr = new int[] {1, 2, 3};
  6. // 简单写法,必须声明的同时作初始化
  7. // 数组元素类型[] 数组名 = {元素 1, 元素 2, ...};
  8. int[] arr = {1, 2, 3};
  9. // 动态初始化,系统自动为数组元素分配初始值
  10. // 数组名 = new 数组元素类型[length];
  11. int[] arr = new int[3]; // [0, 0, 0]
  • 变量必须初始化后才能使用

  • 数组是定长的:数组一旦初始化完成,数组的长度就固定了,不能更改,除非重新做初始化

  • 数组是引用数据类型,可以赋值为 null,表示没有引用任何内存空间

  • new 关键字:在堆空间开辟一块内存区域,用来存储数据

  • 操作数组常见异常:NullPointerException:空指针异常(没有引用地址值)ArrayIndexOutOfBoundsException:数组的索引越界异常

基本操作

  1. int[] arr = new int[] {1, 2, 3};
  2. // 访问数组元素 数组变量[索引值]
  3. int len = arr.length; // 数组长度,length 是属性,索引范围 [0, arr.length - 1]
  4. int num = arr[0];
  5. arr[0] = 11;
  6. // 遍历
  7. // 普通 for 循环
  8. for (int i = 0; i < arr.length; i++) {
  9. System.out.println(arr[i]);
  10. }
  11. // 增强 for 循环(for-each)
  12. // 只能访问数组元素,不能赋值,不关心数组的索引时使用
  13. // 当数组元素是引用类型时,不建议使用(需要先知道值不为 null 的元素个数)
  14. for (int ele : arr) {
  15. System.out.println(ele);
  16. }
  17. // 反编译后
  18. int ai[] = arr;
  19. int k = ai.length;
  20. for (int j = 0; j < k; j++) {
  21. int i = ai[j]; // 使用循环迭代出数组中的每一个元素并赋值给 i
  22. System.out.println(i); // 操作 i
  23. }
  24. // 打印数组元素
  25. // 直接打印数组名时,打印出来是数组对应的 hashCode 值,如 [I@15db9742, [D@15db9742, [Ljava.lang.String;@15db9742
  26. static String toString(int[] arr) {
  27. // 判断数组是否为空
  28. if (arr == null) {
  29. return "null"; // 结束方法
  30. }
  31. if (arr.length == 0) {
  32. return "[]";
  33. }
  34. String ret = "["; // 先拼接"["
  35. for (int index = 0; index < arr.length; index++) {
  36. // 如果不是最后一个元素,拼接 元素 + ", ",否则拼接 元素 + "]"
  37. ret = (index != arr.length - 1)
  38. ? ret + arr[index] + ", "
  39. : ret + arr[index] + "]";
  40. }
  41. return ret;
  42. }

常见的数组算法操作

  1. // 冒泡排序,平均时间复杂度 O(n^2),空间复杂度 O(1)
  2. // 对未排序的各元素从头到尾依次比较相邻的两个元素 arr[i]、arr[i + 1]
  3. // 共要进行 arr.length -1 轮
  4. // 第 times 轮还剩 arr.length - (time - 1) 个元素
  5. // times [1, arr.length -1] i [0, arr.length- (time - 1) - 2]
  6. static void bubbleSort(int[] arr) {
  7. for (int times = 1; times <= arr.length - 1; times++) {
  8. for (int i = 0; i <= arr.length - times - 1; i++) {
  9. if (arr[i] > arr[i + 1]) {
  10. // 交换
  11. arr[i] = arr[i] ^ arr[i + 1];
  12. arr[i + 1] = arr[i] ^ arr[i + 1];
  13. arr[i] = arr[i] ^ arr[i + 1];
  14. }
  15. }
  16. }
  17. }
  1. // 选择排序,平均时间复杂度 O(n^2),空间复杂度 O(1)
  2. // 假定未排序序列的起始位置的元素 arr[i] 为最小值,依次去比较剩下的元素 arr[j]
  3. // i [0, arr.length - 2] j [i + 1, arr.length - 1]
  4. static void selectionSort(int[] arr) {
  5. for (int i = 0; i <= arr.length - 2; i++) {
  6. for (int j = i + 1; j <= arr.length - 1; j++) {
  7. if (arr[i] > arr[j]) {
  8. // 交换
  9. arr[i] = arr[i] ^ arr[j];
  10. arr[j] = arr[i] ^ arr[j];
  11. arr[i] = arr[i] ^ arr[j];
  12. }
  13. }
  14. }
  15. }
  1. // 从有序数组中查找 key 第一次出现的位置
  2. // 二分搜索法/二分查找法/折半查找
  3. // 前提:数组的元素是有序排列的
  4. // 区间位置:如果 arr[mid] != key,下一次是以 mid + 1 作为下一个起始位置,或者 mid - 1 作为下一个结束位置
  5. // 退出循环的条件:low > high
  6. static int binarySearch(int[] arr, int key) {
  7. int low = 0;
  8. int high = arr.length - 1;
  9. while (low <= high) {
  10. int mid = (low + high) >> 1;
  11. if (arr[mid] < key) {
  12. low = mid + 1;
  13. } else if (arr[mid] > key) {
  14. high = mid - 1;
  15. } else {
  16. while (mid - 1 >= 0 && arr[mid -1] == key) {
  17. mid--;
  18. }
  19. return mid;
  20. }
  21. }
  22. return -1;
  23. }

二维数组

  • 实质还是一维数组, 其数组元素是引用类型( 数组类型), 数组元素里保存的引用指向一维数组

    同时初始化二维数组的两个维数后的存储示意图
    图 1 同时初始化二维数组的两个维数后的存储示意图

  • 定义格式
  1. // 静态初始化
  2. int[][] arr = new int[][] { {1, 2, 3}, {4, 5}, {6} };
  3. int[][] arr = { {1, 2, 3}, {4, 5}, {6} };
  4. // 动态初始化
  5. int[][] arr = new int[3][]; // 等同于 int[][] arr = {null, null, null};
  6. int[][] arr = new int[3][4];
  7. // arr.length 为外层数组的长度,arr[i].length 为内层每个数组的长度
  8. // 遍历
  9. // 普通 for 循环
  10. for (int i = 0; i < nums.length; i++) {
  11. for (int j = 0; j < nums[i].length; j++) {
  12. System.out.println(nums[i][j]);
  13. }
  14. }
  15. // 增强 for 循环(for-each)
  16. int totalLength = 0; // 元素的总个数
  17. for (int[] outerArr : arr) {
  18. for (int ele : outerArr)
  19. System.out.println(ele);
  20. totalLength ++;
  21. }
  22. }

操作数组的工具类

  • java.lang.System 类中数组拷贝的类方法void arraycopy(Object src, int srcPos, Object dest, int destPos, int length):从 源数组 src 的 srcPos 位置 复制元素到 目标数组 dest 的 destPos 位置,复制的数组元素的个数为 length

Arrays

java.util.Arrays 中的类方法:

  • String toString(Object[] arr):将 a 数组转换成一个字符串,括在方括号("[]")中,相邻元素用字符 ", "(逗号加空格)分隔
  • void sort(Object[] a):根据元素的自然顺序对指定对象数组按升序进行排序,数组中的所有元素都必须实现 Comparable 接口(对于原始数据类型,使用所谓双轴快速排序(Dual-Pivot QuickSort),对于对象数据类型,使用 TimSort)
  • void sort(T[] a, Comparator<? super T> c):根据指定比较器产生的顺序对指定对象数组进行排序
  • void parallelSort(Object[] a):以并发的方式对 a 数组的数组元素进行排序
  • void setAll(T[] array, IntFunction<T> generator):使用提供的函数计算每一个元素的值,对指定数组中的所有元素进行设置
  • void parallelSetAll(T[] array, IntFunction<T> generator):以并发的方式,使用提供的函数计算每一个元素的值,对指定数组中的所有元素进行设置
  • type binarySearch(Object[] a, type key):使用二分法査询 key 元素值在 a 数组中出现的索引,如果 a 数组不包含 key 元素值,则返回 -(low + 1)(调用该方法时要求数组中元素已经按升序排列)
  • boolean equals(Object[] a, Object[] a2):如果 a 数组和 a2 数组的长度相等,且 a 数组和 a2 数组的数组元素也一一相同,该方法将返回 true
  • Object[] copyOf(Object[] original, int newLength):复制 original 数组,截取或用 0(数值类型)、false(布尔类型)或者 null(引用类型)填充,以使新数组的长度为 newLength
  • List<T> asList(T… a):把一个引用类型的数组指定个数的对象转换成固定长度的 List(Arrays.ArrayList),只能遍历访问该集合里的元素,不可增加、删除该集合里的元素,否则会引发 UnsupportedOperationException 异常
  1. Integer[] integers = list.toArray(new Integer[0]); // List<Integer> 转 Integer[]
  2. List<Integer> list = Arrays.asList(integers); // Integer[] 转 List<Integer>
  3. Integer[] integers = Arrays.stream(ints).boxed().toArray(Integer[]::new); // int[] 转 Integer[]
  4. int[] ints = Arrays.stream(integers).mapToInt(Integer::valueOf).toArray(); // Integer[] 转 int[]
  5. List<Integer> list = Arrays.stream(ints).boxed().collect(Collectors.toList()); // int[] 转 List<Integer>
  6. int[] ints = list.stream().mapToInt(Integer::valueOf).toArray(); // List<Integer> 转 int[]