第4篇:秒懂数组拷贝,感知新境界

📌 系列导航《Java 100 天进阶之路》完整目录 |
⬅️ 上一篇:第3篇:为何要配置环境变量? |
➡️ 下一篇:第5篇:装箱和拆箱

一、核心知识点

  • 数组拷贝的传统方式(循环赋值)及其低效问题
  • System.arraycopy() 底层性能优势(JVM底层C/C++实现)
  • Arrays.copyOf() 便捷用法
  • 浅拷贝机制:引用复制 vs 对象新建
  • 深拷贝的简单实现

二、通俗讲解(1分钟开心学)

1. 什么是数组拷贝?

假设你有一个装着5个球的箱子A(数组),你想把球全部复制到一个新箱子B(另一个数组)里。这就是数组拷贝。

2. 新手做法(循环逐个搬运)

for (int i = 0; i < src.length; i++) {
    dest[i] = src[i];
}

没什么大问题,但如果箱子巨大(比如100万个球),每次搬一个,效率就低了。

3. 高手做法(直接撬动整排货架)

System.arraycopy() 是JVM底层用C/C++实现的,可以直接从内存中批量复制,就像用叉车一次性搬走整排货架,比手工搬快得多。

4. 浅拷贝是什么?

如果数组里放的不是基本类型(如int),而是对象(比如Person),那么拷贝的结果是:新数组里的元素和原数组里的元素指向内存中的同一批对象。你通过新数组修改了对象的属性,原数组对应对象的属性也会变。

生活类比
你有一张同学录(原数组),上面写着张三家的地址。你复印了一份同学录(新数组),两份同学录上写的是同一个地址。你通过新同学录去张三家里涂鸦,原同学录上对应的张三也会被涂鸦覆盖。

三、实操代码案例 + 场景说明

场景:你需要将一个数组的部分元素复制到另一个数组的指定位置,例如在游戏开发中动态合并怪物列表。

1. 使用System.arraycopy()

// 源数组
int[] src = {10, 20, 30, 40, 50};
// 目标数组,长度比源数组大一点
int[] dest = new int[10];

// 参数:源数组,源起始索引,目标数组,目标起始索引,复制长度
System.arraycopy(src, 1, dest, 2, 3);

// dest变成: [0, 0, 20, 30, 40, 0, 0, 0, 0, 0]

2. 使用Arrays.copyOf()(更简洁)

int[] src = {1,2,3};
int[] newArr = Arrays.copyOf(src, 5);  // 新数组长度5,多余元素补0
// newArr = [1,2,3,0,0]

3. 浅拷贝演示(引用类型数组)

class Person { String name; Person(String n) { name = n; } }

Person[] original = { new Person("张三"), new Person("李四") };
Person[] copy = Arrays.copyOf(original, original.length);

copy[0].name = "王五";
System.out.println(original[0].name); // 输出"王五" —— 原数组也被改了!

四、避坑要点

错误/误区 后果 正确做法
使用循环逐个拷贝对象数组后,以为修改副本不影响原数组 意外修改了原对象 理解浅拷贝,需要深拷贝时手动new新对象
System.arraycopy 源范围超出边界 IndexOutOfBoundsException 确保源起始+长度 ≤ 源长度;目标起始+长度 ≤ 目标长度
认为Arrays.copyOf()能自动深拷贝 同上,还是浅拷贝 内存地址复制,不是对象复制
直接 int[] copy = original 两个引用指向同一个数组,修改一个两个都变 使用copyOfarraycopy创建新数组

五、面试高频考点

Q1:System.arraycopy()Arrays.copyOf() 有什么区别?

System.arraycopy() 需要提前创建好目标数组,可以指定起始位置;Arrays.copyOf() 内部自动创建新数组(最终也调用了arraycopy),代码更简洁但灵活性稍弱。

Q2:什么是浅拷贝?什么情况下会出问题?

浅拷贝只复制对象的引用(地址),不复制对象本身。当通过副本修改对象内部状态时,原数组也会受影响。需要深拷贝时应遍历数组并逐个new新对象或使用序列化。

Q3:如何实现一维对象数组的深拷贝?

简单方法:遍历原数组,对每个元素调用clone()(如果对象实现了Cloneable)或手动new。更通用的方法:使用序列化(实现Serializable)后反序列化。

六、练习题

  1. 代码填空System.arraycopy(______, 0, ______, 0, 3); 将源数组前3个元素复制到目标数组的前3个位置。
  2. 简答:浅拷贝在实际项目中可能导致什么bug?举例说明。
  3. 动手:写一个工具方法 public static <T> T[] deepCopy(T[] original),实现通用深拷贝(提示:利用序列化或new实例)。

📊 你的学习进度

  • 当前:第4篇 / 共44篇 · 第一阶段:Java基础语法与环境
  • ✅ 已完成:第1~3篇
  • 📖 正在学:第4篇
  • ⏳ 待学习:第5~44篇

👉 📚 完整目录 & 学习指南 | 🔥 订阅本专栏,不错过每一篇

💡 本专栏每篇都包含:避坑表 + 面试高频考点 + 练习题。每天30分钟,100天拿offer!


👉 下一篇文章预告

《装箱和拆箱》

内容简介:int 和 Integer 有什么区别?为什么 Integer 比较要用 equals?缓存池陷阱是怎么回事?

💡 学完这篇,你将彻底搞懂自动装箱拆箱的底层原理,面试再也不会被“128 == 128”绕晕。

📌 《Java 100 天进阶之路 | 从入门到上岗就业》 每天一篇,建议收藏 + 关注,一起100天拿offer!
👉 点击关注我,更新后第一时间收到推送!

更多推荐