浅拷贝只复制对象第一层属性,对引用类型仅复制内存地址而非实际内容,导致新旧对象嵌套结构共享同一堆内存,修改一方会同步影响另一方。

因为浅拷贝只复制对象第一层的属性值,对引用类型(如对象、数组)复制的是内存地址,不是实际内容。新旧对象的嵌套结构指向同一块堆内存,改其中一方,另一方自然跟着变。
内存中引用类型的存储方式
JavaScript 和 Java 中,对象、数组等引用类型都存在堆内存里,变量本身只保存一个指向该内存的地址。比如 let obj = { a: 1, b: { c: 2 } },obj 存的是地址,obj.b 存的也是另一个地址——它指向堆里那个 { c: 2 } 的位置。
浅拷贝(如 Object.assign()、展开运算符、slice()、BeanUtils.copyProperties())不关心“里面还有没有对象”,它只做一件事:把第一层每个属性的值原样抄过去。基本类型抄值,引用类型抄地址。
浅拷贝操作的本质是“地址复用”
- 原始对象
original的address字段存着地址0xabc - 浅拷贝后得到
copy,它的address字段也存着0xabc - 此时
original.address === copy.address为 true - 你调用
copy.address.city = "Shanghai",等于直接去0xabc这个地址改数据 - 所以
original.address.city读出来的也是 "Shanghai"
哪些操作属于典型浅拷贝
- JavaScript:
{...obj}、Object.assign({}, obj)、arr.slice()、[...arr]、arr.concat() - Java:
Object.clone()(未重写时)、BeanUtils.copyProperties()、构造器中仅字段赋值(this.list = original.list) - 共性:都不递归处理嵌套的引用字段,也不新建子对象
如何验证是否发生了地址共享
关键看两个对象中同一个嵌套引用字段是否指向同一内存:
- JS 中可用
Object.is(obj1.nested, obj2.nested)或直接用===比较 - Java 中推荐用
System.identityHashCode(obj),比hashCode()更可靠(避免被重写干扰) - 如果结果一致,说明是同一对象实例,浅拷贝已生效,修改必互相影响











