)
昨天把数组一些基本的内容讲完了今天扩展开讲讲如果才接触的同学可以先看看混个眼熟1. 数组复制1.1 为什么需要复制数组长度一旦创建就固定了。要扩容只能新建一个更大的数组把原数据复制过去。1.2 方式一手动 for 循环int[] src {10, 20, 30}; int[] dest new int[5]; for (int i 0; i src.length; i) { dest[i] src[i]; } // dest {10, 20, 30, 0, 0}1.3 方式二System.arraycopySystem.arraycopy是java.lang.System类提供的一个静态方法用来把一个数组的元素快速复制到另一个数组里。它在所有数组复制方式中速度最快因为它是 JVM 内置的原生方法。1.3.1 java.lang是属于jdk核心类库里的为什么又说是在JVM内置的原生方法呢System.arraycopy的说明书方法声明写在 JDK 的System.java里所以它是 JDK 类库的一部分。但它的真功夫实现写在 JVM 的 C 代码里所以它也是 JVM 原生方法。壳在 JDK核在 JVM。1.3.2 什么是原生方法用native关键字修饰的方法它的实现在 JVM 底层用 C/C 写的不在 Java 代码里。1.3.3 什么是native修饰的方法直接调用操作系统底层的内存操作不是一行行 Java 循环JVM 会根据数组类型选择最优策略整型直接一块一块复制比循环一个个赋值快一个数量级内部可能用 CPU 的 SIMD 指令甚至memmove/memcpy来实现这是最底层的内存块复制循环一个个搬砖跟推土机直接推一整块地效率差远了。System.arraycopy就是推土机手动 for 循环就是搬砖。1.3.4 什么是静态方法后面会详细讲现在可以先了解个大概用static修饰的方法属于类本身不属于任何一个对象。直接用类名调用不用创建对象用类名直接调不用 new 对象。静态方法是公共设施属于类本身大家随时直接用。System.arraycopy(源数组, 源起始位置, 目标数组, 目标起始位置, 复制个数); int[] src {10, 20, 30}; int[] dest new int[5]; System.arraycopy(src, 0, dest, 0, src.length); // 参数源数组, 源起始位置, 目标数组, 目标起始位置, 复制个数 // dest {10, 20, 30, 0, 0}1.4 方式三Arrays.copyOfArrays.copyOf是java.util.Arrays里的一个静态方法用来复制数组并指定新数组的长度。它内部会自动创建新数组调用System.arraycopy然后返回新数组。Arrays.copyOf是最方便的数组复制方法自动建新数组、自动调底层快速复制扩容或复制直接用。import java.util.Arrays; //使用时需要导包 Arrays.copyOf(源数组, 新数组长度); int[] src {10, 20, 30}; int[] dest Arrays.copyOf(src, 5); // 参数源数组, 新数组长度 // dest {10, 20, 30, 0, 0}1.5 方式四Arrays.copyOfRange指定范围复制Arrays.copyOfRange是Arrays.copyOf的兄弟方法和copyOf一样底层也是建新数组 调System.arraycopy区别在于它可以指定复制原数组的哪一段范围而不是只能从头开始复制。规则类似于数学的左闭右开 [起始结束)起始下标从哪儿开始复制包含结束下标到哪儿结束不包含int[] src {10, 20, 30, 40, 50}; int[] dest Arrays.copyOfRange(src, 1, 4); // 参数源数组, 起始下标(包含), 结束下标(不包含) // dest {20, 30, 40}1.6 方式五cloneclone()是 Object 类提供的方法用来复制一个对象。对数组来说调用clone()会创建一个新数组里面的元素内容完全相同。使用clone会引出新内容深拷贝浅拷贝先简单了解后面用到了之后细讲1.6.1 浅拷贝 只复制对象本身以及对象里所有字段的「值」基本数据类型int、double、boolean 等直接复制数值新旧对象各自独立。引用数据类型对象、数组等只复制引用的内存地址新旧对象共享同一个子对象。 → 直接结论修改新对象的子对象内部属性原对象会跟着同步变化。1.6.2 深拷贝 不仅复制对象本身还会递归复制所有层级的引用类型成员基本数据类型和浅拷贝一致复制数值各自独立。引用数据类型会重新创建一个一模一样的子对象新旧对象各自持有完全独立的子对象实例。 → 直接结论修改新对象的任意层级属性原对象都不会受到任何影响。4. 数组查找4.1 二分查找数组必须先排序int[] arr {12, 23, 55, 67, 89}; int index Arrays.binarySearch(arr, 55); // index 2找到了返回下标 int index2 Arrays.binarySearch(arr, 100); // index2 -6没找到返回负数 // 负数表示如果插入该元素应该在的位置的负值再减14.2 二分查找的原理每次取中间值和目标比较缩小一半范围比顺序查找快得多但前提是数组已排序。目标55 [12, 23, 55, 67, 89] ↑ 中间55命中 目标67 [12, 23, 55, 67, 89] ↑ 中间556755只看右边 [67, 89] ↑ 中间67命中5. 二维数组数组里面的每个元素也是数组。5.1 声明和创建int[][] arr new int[3][4]; // 3行4列的二维数组 int[][] arr2 { {1, 2, 3}, {4, 5, 6}, {7, 8, 9} };5.2 二维数组遍历for (int i 0; i arr2.length; i) { for (int j 0; j arr2[i].length; j) { System.out.print(arr2[i][j] ); } System.out.println(); // 换行 } // 输出 // 1 2 3 // 4 5 6 // 7 8 9ps:扩展的有些多了先了解反正也不吃亏