You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何在Getter中使用Arrays.copyOf()实现的是防御性拷贝而非浅拷贝?

关于Arrays.copyOf()浅拷贝与防御性拷贝的困惑

我是Java编程初学者,对在Getter方法中使用Arrays.copyOf()的结果感到困惑。我知道该方法通常会生成传入参数的浅拷贝,但在Getter中用它实现数组的防御性拷贝时,返回的结果似乎并非浅拷贝。

PersonRecord类代码

import java.util.Arrays;

public class PersonRecord{
    private final String name;
    private final String dob;
    private final PersonRecord[] kids;
    
    // 构造方法
    public PersonRecord(String name, String dob, PersonRecord[] kids) {
        this.name = name;
        this.dob = dob;
        this.kids = kids;
    }
    
    // 字段"kids"的Getter方法
    // 对第三个字段使用防御性拷贝
    public PersonRecord[] getKids() {
        return Arrays.copyOf(kids, kids.length);
    }
    
    // toString()方法(仅打印"kids"字段的内容)
    @Override
    public String toString(){
        String kidString = "n/a";
        String[] names = new String[kids.length];
        Arrays.setAll(names, i -> names[i] = kids[i].name);
        kidString = String.join(",", names);
        return kidString;
   }
}

测试代码

// 创建第三个字段"johnKids"的内容
PersonRecord jane = new PersonRecord("Jane", "01/01/1930", null);
PersonRecord jim = new PersonRecord("Jim", "02/02/1932", null);
PersonRecord joe = new PersonRecord("Joe", "03/03/1934", null);

// 为第三个字段创建数组
PersonRecord[] johnsKids = {jane, jim, joe}; 

// 创建类的实例"john"
PersonRecord john = new PersonRecord("John", "05/05/1900", johnsKids);

// 打印对象john
System.out.println(john); 
// 结果:第三个字段 => {Jane, Jim, Joe}

// 将Getter方法返回的结果赋值给新数组
PersonRecord[] newArray = john.getKids();

// 对新数组做一些修改
newArray[0] = jim;
newArray[1] = new PersonRecord("Ann", "04/04/1936", null);

// 再次打印对象john
System.out.println(john); 
// 结果(未被修改):第三个字段 => {Jane, Jim, Joe}

测试结果表明newArray与原对象的kids字段指向不同内存对象。我疑惑的是:既然Arrays.copyOf()应返回浅拷贝,为何修改newArray不会影响原kids字段?


解答

首先得明确浅拷贝的定义:Arrays.copyOf()做的浅拷贝,是创建一个新的数组对象,然后把原数组中每个元素的引用,复制到新数组对应的位置里。也就是说,新数组和原数组是两个独立的数组对象,但它们里面的元素指向的是同一个堆内存中的对象。

你测试里修改的是newArray的元素引用(比如newArray[0] = jim),这只是改变了新数组里某个位置存储的引用值,和原数组没有任何关系——原数组的kids还是保留着原来的引用集合,所以打印john时内容不变。

如果要体现浅拷贝的特性,你可以试试修改newArray中某个元素的内部状态(前提是这个元素的字段不是final)。比如假设PersonRecord的name不是final,你执行newArray[0].name = "ModifiedJane",这时候再打印john,就会发现原kids数组里对应的元素名称也变成了"ModifiedJane"——因为新数组和原数组里的元素指向的是同一个PersonRecord对象。

而你现在用Arrays.copyOf()实现的防御性拷贝,目的就是防止外部直接修改原数组本身(比如替换数组里的元素、改变数组长度),这正是防御性拷贝想要达到的效果,和浅拷贝的定义并不冲突。

内容的提问来源于stack exchange,提问作者Bert Horimx

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.22 03:03:19