ThinkChat🤖让你学习和工作更高效,注册即送10W Token,即刻开启你的AI之旅 广告
## 数组拷贝 与使用for循环手工执行复制相比,**copyOf()** 和 **copyOfRange()** 复制数组要快得多。这些方法被重载以处理所有类型。 我们从复制 **int** 和 **Integer** 数组开始: ```JAVA // arrays/ArrayCopying.java // Demonstrate Arrays.copy() and Arrays.copyOf() import onjava.*; import java.util.Arrays; import static onjava.ArrayShow.*; class Sup { // Superclass private int id; Sup(int n) { id = n; } @Override public String toString() { return getClass().getSimpleName() + id; } } class Sub extends Sup { // Subclass Sub(int n) { super(n); } } public class ArrayCopying { public static final int SZ = 15; public static void main(String[] args) { int[] a1 = new int[SZ]; Arrays.setAll(a1, new Count.Integer()::get); show("a1", a1); int[] a2 = Arrays.copyOf(a1, a1.length); // [1] // Prove they are distinct arrays: Arrays.fill(a1, 1); show("a1", a1); show("a2", a2); // Create a shorter result: a2 = Arrays.copyOf(a2, a2.length / 2); // [2] show("a2", a2); // Allocate more space: a2 = Arrays.copyOf(a2, a2.length + 5); show("a2", a2); // Also copies wrapped arrays: Integer[] a3 = new Integer[SZ]; // [3] Arrays.setAll(a3, new Count.Integer()::get); Integer[] a4 = Arrays.copyOfRange(a3, 4, 12); show("a4", a4); Sub[] d = new Sub[SZ / 2]; Arrays.setAll(d, Sub::new); // Produce Sup[] from Sub[]: Sup[] b = Arrays.copyOf(d, d.length, Sup[].class); // [4] show(b); // This "downcast" works fine: Sub[] d2 = Arrays.copyOf(b, b.length, Sub[].class); // [5] show(d2); // Bad "downcast" compiles but throws exception: Sup[] b2 = new Sup[SZ / 2]; Arrays.setAll(b2, Sup::new); try { Sub[] d3 = Arrays.copyOf(b2, b2.length, Sub[].class); // [6] } catch (Exception e) { System.out.println(e); } } } /* Output: a1: [0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14] a1: [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] a2:[0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14]a2:[0, 1, 2, 3, 4, 5, 6]a2:[ 0, 1, 2, 3, 4, 5, 6, 0, 0, 0, 0, 0]a4:[4, 5, 6, 7, 8, 9, 10, 11][Sub0, Sub1, Sub2, Sub3, Sub4, Sub5, Sub6][ Sub0, Sub1, Sub2, Sub3, Sub4, Sub5, Sub6]java.lang.ArrayStoreException */ ``` [1] 这是复制的基本方法;只需给出返回的复制数组的大小。这对于编写需要调整存储大小的算法很有帮助。复制之后,我们把a1的所有元素都设为1,以证明a1的变化不会影响a2中的任何东西。 [2] 通过更改最后一个参数,我们可以缩短或延长返回的复制数组。 [3] **copyOf()** 和 **copyOfRange()** 也可以使用包装类型。**copyOfRange()** 需要一个开始和结束索引。 [4] **copyOf()** 和 **copyOfRange()** 都有一个版本,该版本通过在方法调用的末尾添加目标类型来创建不同类型的数组。我首先想到的是,这可能是一种从原生数组生成包装数组的方法,反之亦然。 但这没用。它的实际用途是“向上转换”和“向下转换”数组。也就是说,如果您有一个子类型(派生类型)的数组,而您想要一个基类型的数组,那么这些方法将生成所需的数组。 [5] 您甚至可以成功地“向下强制转换”,并从超类型的数组生成子类型的数组。这个版本运行良好,因为我们只是“upcast”。 [6] 这个“数组转换”将编译,但是如果类型不兼容,您将得到一个运行时异常。在这里,强制将基类型转换为派生类型是非法的,因为派生对象中可能有基对象中没有的属性和方法。 实例表明,原生数组和对象数组都可以被复制。但是,如果复制对象的数组,那么只复制引用—不复制对象本身。这称为浅拷贝(有关更多细节,请参阅附录:传递和返回对象)。 还有一个方法 **System.arraycopy()** ,它将一个数组复制到另一个已经分配的数组中。这将不会执行自动装箱或自动卸载—两个数组必须是完全相同的类型。