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;


相关文章
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的服装商城管理系统
基于Java+Springboot+Vue开发的服装商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的服装商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
32 2
基于Java+Springboot+Vue开发的服装商城管理系统
|
8天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
基于Java+Springboot+Vue开发的大学竞赛报名管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的大学竞赛报名管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
23 3
基于Java+Springboot+Vue开发的大学竞赛报名管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的蛋糕商城管理系统
基于Java+Springboot+Vue开发的蛋糕商城管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的蛋糕商城管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的蛋糕商城管理系统
|
9天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的美容预约管理系统
基于Java+Springboot+Vue开发的美容预约管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的美容预约管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
21 3
基于Java+Springboot+Vue开发的美容预约管理系统
|
10天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的房产销售管理系统
基于Java+Springboot+Vue开发的房产销售管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的房产销售管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
25 3
基于Java+Springboot+Vue开发的房产销售管理系统
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的反诈视频宣传系统
基于Java+Springboot+Vue开发的反诈视频宣传系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的反诈视频宣传管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
41 4
基于Java+Springboot+Vue开发的反诈视频宣传系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的健身房管理系统
基于Java+Springboot+Vue开发的健身房管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的健身房管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
42 5
基于Java+Springboot+Vue开发的健身房管理系统
|
9天前
|
存储 网络协议 Java
Java NIO 开发
本文介绍了Java NIO(New IO)及其主要组件,包括Channel、Buffer和Selector,并对比了NIO与传统IO的优势。文章详细讲解了FileChannel、SocketChannel、ServerSocketChannel、DatagramChannel及Pipe.SinkChannel和Pipe.SourceChannel等Channel实现类,并提供了示例代码。通过这些示例,读者可以了解如何使用不同类型的通道进行数据读写操作。
Java NIO 开发
|
11天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
基于Java+Springboot+Vue开发的医院门诊预约挂号系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的门诊预约挂号管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
31 2
基于Java+Springboot+Vue开发的医院门诊预约挂号系统
|
12天前
|
前端开发 JavaScript Java
基于Java+Springboot+Vue开发的家具管理系统
基于Java+Springboot+Vue开发的家具管理系统(前后端分离),这是一项为大学生课程设计作业而开发的项目。该系统旨在帮助大学生学习并掌握Java编程技能,同时锻炼他们的项目设计与开发能力。通过学习基于Java的家具管理系统项目,大学生可以在实践中学习和提升自己的能力,为以后的职业发展打下坚实基础。
32 2
基于Java+Springboot+Vue开发的家具管理系统
下一篇
无影云桌面