Java 浅拷贝和深拷贝|Java 开发实战

简介: Java 浅拷贝和深拷贝

开篇

在开发中你有没有遇到过一些关于集合复制的问题?

普通的集合复制只是将内存中栈的地址块拷贝一份,使得一个新的集合对象指向这个地址块,但是集合中的对象变量却是指向堆中的同一块区域。所以当拷贝的集合修改了自己集合对象内的数据时,源集合对象也随之改变了,这样的效果我们称之为Java集合对象的浅复制(即只是在栈中拷贝了,而堆中的数据并没有拷贝。)

而深复制则是同时将栈中和堆中的数据进行拷贝,这样其拷贝的集合和被拷贝的集合就没有任何关系了。

案例演示

@Data
@AllArgsConstructor
@NoArgsConstructor
public class Demo {  
    private int  demoValue;  
}
复制代码

试验一下浅复制:

@Test  
public void testDemoCopy() {  
    // 这里我创建了一个源集合
    ArrayList<Demo> sourceCollection = new ArrayList<Demo>();  
    // 这里我向sourceCollection添加了一些对象
    sourceCollection.add(new Demo(1));  
    sourceCollection.add(new Demo(2));  
    // 这里我创建了一个新的空集合 
    ArrayList<Demo> newCollection = new ArrayList<Demo>();  
    newCollection.addAll(sourceCollection);  
    // 现在我修改了新集合中的一些对象
    newCollection.get(0).setDemoValue(3);  
    // 现在我们验证它在源集合中是什么  
    for(Demo demo : sourceCollection){  
        System.out.println(demo.getDemoValue());  
    }   
    // 断言验证源Collection是否被修改.  
    Assert.assertEquals(sourceCollection.get(0).getDemoValue(),1);  
}
复制代码
CollectionCopyjava 
@ Test 
 public void 
 testcomonCopyShallow 
// Here I create a source collection .
 ArrayList < Demo > sourceCollection = new ArrayList < Demo >();
// Here I add some objects to sourceCollection .
 sourceCollection . add ( new Demo (1));
 sourceCollection . add ( new Demo (2));
// Here I create a new empty collection .
 ArrayList < Demo > newCollection = new ArrayList < Demo >();
 newCollection . addAll ( sourceCollectiOn );
// Now I modify some objects in new collection .
 newCollection . get (0). setDemoValue (3);
// Now We verify what it is inside the source collection . for ( Demo demo : sourceCollection ){
 System . out . println ( demo . getDemoValue ());
// Now I verify if the source Collection is modified .
 Assert . assertEquals ( sourceCollection . get (0). getDemoValue (),1
@ Test 
 olems Javadoc beclaration C Progress 
 Console 3
 avacollectionCopy . testcommonCopyShallow [ Unit ] D :SDKVRE1.8binjavaw. exe (20t

很明显,newCollection中改变的Demo对象在SourceCollection中也跟着改变了,这说明两个集合中的Demo对象是同一个对象。这也是浅复制所存在的弊端。

那么如何将两个集合独立开来呢,即如何进行深度复制?

试验一下深复制:

首先我们先对Demo类作一下处理,使其实现Cloneable接口,并重写它的clone方法

protected Demo clone() throws CloneNotSupportedException {             
   return (Demo)super.clone();  
}
复制代码

测试类如下

@Test  
public void testCopyDeep() throws Exception{  
    ArrayList<Demo> sourceCollection = new ArrayList<Demo>();  
    sourceCollection.add(new Demo(1));  
    sourceCollection.add(new Demo(2));    
    ArrayList<Demo> newCollection = new ArrayList<Demo>();  
    for(Demo demo : sourceCollection){  
        // 这里是重点
        newCollection.add(demo.clone());  
    }  
    newCollection.get(0).setDemoValue(3);  
    for(Demo demo : sourceCollection){  
        System.out.println(demo.getDemoValue());  
    }  
    Assert.assertEquals(sourceCollection.get(0).getDemoValue(),1);  
}
复制代码

最后我们来观察一下结果:两个集合各自独立,谁修改都不会互相影响对象

collectionCopyjava 
// Now I verify if the source Collection is modified .
 Assert . assertEquals ( sourceCollection . get (0). getDemoValue (),1);
@Te3t
 public void testCopyDeep () throws Exception (
 ArrayList < Demo > sourceCollection = new ArrayList < Demo >(); sourceCollection . add ( new Demo (1));
 sourceCollection . add ( new Demo (2));
 ArrayList < Demo > newCollection = new ArrayList < Demo >(); for ( Demo demo : sourceCollection )(
 newCollection . add ( demo . clone ());
 newCollection . get (0). setDemoValue (3); for ( Demo demo : sourceCollection ){
 System . out . println ( demo . getDemoValue ());
 Assert . assertEquals ( sourceCollection . get (0). getDemoValue (),1);
 Javadoc el 
 Pd Progress 
 acollectionCopy . testCopyDeep [ JUnit ] D :\SDKVRE1.8binjavaw. exe (2015年10月30日下午9:30:34)
 iaration Console 

另一种快速copy集合的写法

现在很多人都用jdk8以上的版本了,那么上面这种复制集合的写法就显得有点臃肿了,可以使用java lambda表达式来进行语义上的优化,如下所示:

@Override
public DebtDetailListDTO clone() throws CloneNotSupportedException {
val cloned = (DebtDetailListDTO)super.clone();
cloned.data=data.stream().map(GwDebtDetail::clone).collect(Collectors.toList()); return cloned;
@Override
public DebtDetailListDTO clone()throws CloneNotSupportedException {
val cloned =(DebtDetailListDTO) super.clone();
cloned.data=data.stream().map(GwDebtDetail::clone).collect(Collectors.toList()) return cloned;


目录
相关文章
|
11天前
|
安全 Java 程序员
《从头开始学java,一天一个知识点》之:控制流程:if-else条件语句实战
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问&quot;`a==b`和`equals()`的区别&quot;,大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列为你打造Java「速效救心丸」!每天1分钟,地铁通勤、午休间隙即可完成学习。直击高频考点和实际开发中的「坑位」,拒绝冗长概念,每篇都有可运行的代码示例。明日预告:《for与while循环的使用场景》。 ---
52 19
|
5天前
|
消息中间件 Java 应用服务中间件
JVM实战—1.Java代码的运行原理
本文介绍了Java代码的运行机制、JVM类加载机制、JVM内存区域及其作用、垃圾回收机制,并汇总了一些常见问题。
JVM实战—1.Java代码的运行原理
|
19天前
|
人工智能 安全 IDE
一天成为Java开发高手:用飞算JavaAI实现十倍提效
“一天成为Java开发高手”曾被视为天方夜谭,但飞算JavaAI的出现改变了这一局面。这款AI开发助手通过智能引导、需求分析、自动化逻辑处理和完整代码工程生成,大幅简化了Java开发流程。它不仅帮助新手快速上手,还让资深开发者提高效率,减少调试时间。现在,参与“飞算JavaAI炫技赛”,展示你的开发实力,赢取丰厚奖品!
|
12天前
|
存储 Java 编译器
课时11:综合实战:简单Java类
本次分享的主题是综合实战:简单 Java 类。主要分为两个部分: 1.简单 Java 类的含义 2.简单 Java 类的开发
|
12天前
|
Oracle Java 关系型数据库
课时37:综合实战:数据表与简单Java类映射转换
今天我分享的是数据表与简单 Java 类映射转换,主要分为以下四部分。 1. 映射关系基础 2. 映射步骤方法 3. 项目对象配置 4. 数据获取与调试
|
1月前
|
JavaScript 安全 Java
智慧产科一体化管理平台源码,基于Java,Vue,ElementUI技术开发,二开快捷
智慧产科一体化管理平台覆盖从备孕到产后42天的全流程管理,构建科室协同、医患沟通及智能设备互联平台。通过移动端扫码建卡、自助报道、智能采集数据等手段优化就诊流程,提升孕妇就诊体验,并实现高危孕产妇五色管理和孕妇学校三位一体化管理,全面提升妇幼健康宣教质量。
49 12
|
10天前
|
搜索推荐 Java Android开发
课时146:使用JDT开发Java程序
在 Eclipse 之中提供有 JDT环境可以实现java 程序的开发,下面就通过一些功能进行演示。 项目开发流程
|
11天前
|
存储 监控 数据可视化
SaaS云计算技术的智慧工地源码,基于Java+Spring Cloud框架开发
智慧工地源码基于微服务+Java+Spring Cloud +UniApp +MySql架构,利用传感器、监控摄像头、AI、大数据等技术,实现施工现场的实时监测、数据分析与智能决策。平台涵盖人员、车辆、视频监控、施工质量、设备、环境和能耗管理七大维度,提供可视化管理、智能化报警、移动智能办公及分布计算存储等功能,全面提升工地的安全性、效率和质量。
|
19天前
|
人工智能 Java 数据处理
Java高级应用开发:基于AI的微服务架构优化与性能调优
在现代企业级应用开发中,微服务架构虽带来灵活性和可扩展性,但也增加了系统复杂性和性能瓶颈。本文探讨如何利用AI技术,特别是像DeepSeek这样的智能工具,优化Java微服务架构。AI通过智能分析系统运行数据,自动识别并解决性能瓶颈,优化服务拆分、通信方式及资源管理,实现高效性能调优,助力开发者设计更合理的微服务架构,迎接未来智能化开发的新时代。
|
2月前
|
存储 缓存 Java
Java中的分布式缓存与Memcached集成实战
通过在Java项目中集成Memcached,可以显著提升系统的性能和响应速度。合理的缓存策略、分布式架构设计和异常处理机制是实现高效缓存的关键。希望本文提供的实战示例和优化建议能够帮助开发者更好地应用Memcached,实现高性能的分布式缓存解决方案。
51 9