简单看ArrayList中clone的深浅克隆

本文探讨了ArrayList在Java中的深浅克隆原理。浅克隆时,新集合元素引用指向原对象的栈空间地址,导致两者操作相互影响。而深克隆通过在堆内存中创建新对象,确保新旧集合独立。文中提供了测试代码以展示不同克隆方式的效果。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

 浅克隆:将新集合每个元素的引用指向原集合对应对象在栈空间的内存地址,所以,原集合修改或删除,克隆的集合随之改变;新集合修改添加会改变引用重新指向其他堆内存地址,删除就直接删除引用。

深克隆:将新集合的元素对象复制,在堆内存中重新开辟空间存一样的内容,一般要对集合中的对象重写clone(),在clone()中返回new的新对象,再add到新集合中,所以新旧集合操作互不影响。

以下为测试代码:

方法多测试看效果,每次只是用部分方法,注释部分方法看起更清晰

        ArrayList<Integer> easyList = new ArrayList<Integer>();
		easyList.add(new Integer(1));
		easyList.add(new Integer(2));
		easyList.add(new Integer(3));
		
		//浅克隆,移除克隆集合原集合不变
		ArrayList<Integer> clonelist = (ArrayList<Integer>) easyList.clone();
		//移除现集合,原集合不变
		//clonelist.remove(easyList.size()-1);
		//移除原集合,现集合改变
		easyList.remove(1);
        //新集合修改不影响原集合
		//clonelist.set(0, 99);
		sop("浅克隆原集合"+easyList);
		sop("浅克隆现集合"+clonelist);
		
		//深克隆,克隆集合中对象,对象要重写clone()
		ArrayList<listCloneDemo> deepList = new ArrayList<listCloneDemo>();
		deepList.add(new listCloneDemo("java1",1));
		deepList.add(new listCloneDemo("java3",3));
		deepList.add(new listCloneDe
<think>好的,我现在需要帮助用户理解Java中的Cloneable接口和clone方法,以及深复制的相关概念。首先,我得回顾用户提供的引用内容,确保回答准确。用户引用了五个资料,其中引用1提到Cloneable接口是一个标记接口,必须实现它才能使用clone方法,否则会抛出异常。引用2展示了如何使用clone方法进行深复制的例子,并检查对象地址是否不同。引用3讨论了深拷贝和浅拷贝的区别,以及不可变对象的应用。引用4涉及JVM在克隆时的处理,判断是否实现了Cloneable接口。引用5是Object类clone方法的官方说明,指出默认是浅拷贝。用户的问题集中在Cloneable接口和clone方法的作用,以及它们在深复制中的应用。我需要结合这些引用,分步骤解释概念,确保覆盖以下几点: 1. **Cloneable接口的作用**:作为标记接口,没有方法,只是告诉JVM该类允许克隆。如果没有实现,调用clone会抛出异常,如引用1和引用4所述。 2. **clone方法的使用**:必须重写Object的clone方法,并将其访问权限改为public,如引用2的示例所示。默认实现是浅拷贝,如引用5所述,复制字段引用而非对象本身。 3. **深复制的实现**:需要递归克隆所有可变对象字段,如引用2中的例子,克隆内部Test对象。引用3提到深拷贝的重要性,尤其是在创建不可变对象时,避免外部修改影响内部状态。4.**深浅拷贝的区别**:引用3和引用5都强调浅拷贝只复制引用,深拷贝复制整个对象图。需要举例说明,比如对象包含其他对象或集合时的处理。5.**注意事项**:循环引用问题,如何处理,以及不可变对象(如String)在深复制中的优化,直接引用而无需克隆,如引用3所述。 接下来,我需要组织回答结构,先解释Cloneable接口和clone方法的基本用法,再讨论深复制的实现,最后结合示例代码和注意事项。确保引用正确,比如在提到CloneNotSupportedException时引用1,示例代码参考引用2,深拷贝与不可变对象时引用3和5。可能还需要指出,默认的clone方法是浅拷贝,如引用5所述,而深拷贝需要手动实现,递归调用clone方法。同时,提到反射和序列化作为替代方案,但用户提供的引用中没有提到这些,所以可能简要提及。最后生成相关问题,确保覆盖用户可能感兴趣的方面,如深拷贝的实现方法、Cloneable接口的设计原因、深浅拷贝的选择依据等。</think>### 一、Cloneable接口与clone方法的核心机制 1. **Cloneable接口的标记作用** - 作为空接口(标记接口),仅用于标识类允许克隆操作[^1] - JVM在运行时检查类是否实现该接口,未实现则抛出`CloneNotSupportedException`[^4] - 示例代码: ```java class MyClass implements Cloneable { //必须声明实现Cloneable @Override public Object clone() throws CloneNotSupportedException { return super.clone(); //调用Object的native方法 } } ``` 2. **clone方法的实现规范** - 必须重写`Object.clone()`并提升访问权限至`public`(Object类中该方法为protected)[^2] - 默认实现是浅拷贝,仅复制字段的引用值[^5] - 深拷贝需要显式处理引用类型字段: ```java class DeepCloneDemo implements Cloneable { private Date timestamp; //可变对象字段 @Override public Object clone() { DeepCloneDemo cloned = (DeepCloneDemo)super.clone(); cloned.timestamp = (Date)this.timestamp.clone(); //递归克隆 return cloned; } } ``` ### 二、深复制的实现原理与场景 1. **深浅拷贝的本质区别** | **特征** | 浅拷贝 | 深拷贝 | |---------------|---------------------------|----------------------------| | 内存消耗 | 仅增加指针存储空间($32/64$位) | 创建新对象及其所有依赖对象 | | 对象独立性 | 共享可变对象状态 | 完全独立的对象图 | | 实现复杂度 | 自动完成 | 需递归处理所有引用类型字段[^3] | 2. **深复制的典型实现模式** - 递归克隆:对每个引用类型字段调用`clone()`方法 - 序列化方案:通过对象流实现完全独立拷贝(不依赖Cloneable接口) - 示例场景: ```java class Department implements Cloneable { List<Employee> staff; //需要深拷贝的集合 @Override public Object clone() { Department cloned = (Department)super.clone(); cloned.staff = new ArrayList<>(); for(Employee e : staff) { cloned.staff.add((Employee)e.clone()); //递归处理集合元素 } return cloned; } } ``` ### 三、关键技术细节解析 1. **不可变对象的特殊处理** - 对`String`、包装类等不可变对象可直接复用引用[^3] - 示例优化: ```java class SafeClone implements Cloneable { private String id; //不可变字段无需克隆 @Override public Object clone() { try { SafeClone cloned = (SafeClone)super.clone(); //id字段无需处理,直接复用引用 return cloned; } catch (CloneNotSupportedException e) { throw new AssertionError(); //已实现Cloneable不会发生 } } } ``` 2. **JVM层面的实现机制** - 通过`Cloneable_klass_loaded`方法检查接口实现状态[^4] - 对象头中的`_access_flags`标志位记录克隆能力 - 内存布局示意图: ``` +-------------------+ | 对象头 (Cloneable标记) | +-------------------+ | 基本类型字段值 | +-------------------+ | 引用类型指针 (浅拷贝) | --> 原对象 +-------------------+ ``` ### 四、应用实践建议 1. **设计选择标准** - 优先使用深拷贝的场景: - 包含可变对象引用的值对象 - 需要保持状态隔离的并发对象 - 需要生成历史快照的业务对象[^3] - 可选用浅拷贝的场景: - 仅包含基本类型和不可变对象的类 - 明确需要共享状态的设计(如享元模式) 2. **替代方案对比** | **方法** | 优点 | 缺点 | |---------------|-------------------------|------------------------| | clone() | 原生支持、性能高 | 需处理引用链、破坏封装性 | | 序列化 | 自动处理复杂对象图 | 性能开销大、需实现Serializable | | 构造器复制 | 完全控制复制过程 | 代码冗余度高 |
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值