Java List 复制:浅拷贝与深拷贝方法及区别

简介: 我是小假 期待与你的下一次相遇 ~

List浅拷贝

众所周知,list本质上是数组,而数组的是以地址的形式进行存储。

如上图将list A浅拷贝给list B,由于进行的是浅拷贝,所以直接将A的内容复制给了B,java中相同内容的数组指向同一地址,即进行浅拷贝后A与B指向同一地址。造成的后果就是,改变B的同时也会改变A,因为改变B就是改变B所指向地址的内容,由于A也指向同一地址,所以A与B一起改变。

几种浅拷贝

1、遍历循环复制

  1. List<Person> destList=new ArrayList<Person>(srcList.size());  
  2. for(Person p : srcList){  
  3.    destList.add(p);  
  4. }

2、使用List实现类的构造方法

  1. List<Person> destList=new ArrayList<Person>(srcList);

3、使用list.addAll()方法

  1. List<Person> destList=new ArrayList<Person>();  
  2. destList.addAll(srcList);

4、使用System.arraycopy()方法

  1. Person[] srcPersons=srcList.toArray(new Person[0]);  
  2. Person[] destPersons=new Person[srcPersons.length];  
  3. System.arraycopy(srcPersons, 0, destPersons, 0, srcPersons.length);

测试及结果

  1. printList(destList); //打印未改变B之前的A
  2. srcList.get(0).setAge(100);//改变B  
  3. printList(destList); //打印改变B后的A

打印结果

  1. 123-->20  
  2. ABC-->21  
  3. abc-->22  
  4. 123-->100  
  5. ABC-->21  
  6. abc-->22

List深拷贝

如图,深拷贝就是将A复制给B的同时,给B创建新的地址,再将地址A的内容传递到地址B。ListA与ListB内容一致,但是由于所指向的地址不同,所以改变相互不受影响。

深拷贝的方法

1.使用序列化方法

  1. public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException {  
  2.    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();  
  3.    ObjectOutputStream out = new ObjectOutputStream(byteOut);  
  4.    out.writeObject(src);  
  5.    ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());  
  6.    ObjectInputStream in = new ObjectInputStream(byteIn);  
  7.    @SuppressWarnings("unchecked")  
  8.    List<T> dest = (List<T>) in.readObject();  
  9.    return dest;  
  10. }  
  11. List<Person> destList=deepCopy(srcList);  //调用该方法

2.clone方法

  1. public class A implements Cloneable {  
  2.    public String name[];  
  3.    public A(){  
  4.        name=new String[2];  
  5.    }  
  6.    public Object clone() {  
  7.        A o = null;  
  8.        try {  
  9.            o = (A) super.clone();  
  10.        } catch (CloneNotSupportedException e) {  
  11.            e.printStackTrace();  
  12.        }  
  13.        return o;  
  14.    }  
  15. }  
  16. for(int i=0;i<n;i+=){
  17.    copy.add((A)src.get(i).clone());
  18. }

Java对对象和基本的数据类型的处理是不一样的。在Java中用对象的作为入口参数的传递则缺省为”引用传递”,也就是说仅仅传递了对象的一个”引用”,这个”引用”的概念同C语言中的指针引用是一样的。当函数体内部对输入变量改变时,实质上就是在对这个对象的直接操作。

除了在函数传值的时候是”引用传递”,在任何用”=”向对象变量赋值的时候都是”引用传递”。

测试及结果

  1. printList(destList); //打印未改变B之前的A
  2. srcList.get(0).setAge(100);//改变B  
  3. printList(destList); //打印改变B后的A
  4. 123-->20  
  5. ABC-->21  
  6. abc-->22  
  7. 123-->20  
  8. ABC-->21  
  9. abc-->22

在浅复制的情况下,源数据被修改破坏之后,使用相同引用指向该数据的目标集合中的对应元素也就发生了相同的变化。因此,在需求要求必须深复制的情况下,要是使用上面提到的方法,请确保List中的T类对象是不易被外部修改和破坏的。


相关文章
|
3月前
|
Java 测试技术
Java浮点类型详解:使用与区别
Java中的浮点类型主要包括float和double,它们在内存占用、精度范围和使用场景上有显著差异。float占用4字节,提供约6-7位有效数字;double占用8字节,提供约15-16位有效数字。float适合内存敏感或精度要求不高的场景,而double精度更高,是Java默认的浮点类型,推荐在大多数情况下使用。两者都存在精度限制,不能用于需要精确计算的金融领域。比较浮点数时应使用误差范围或BigDecimal类。科学计算和工程计算通常使用double,而金融计算应使用BigDecimal。
1683 102
|
1月前
|
Java
Java语言实现字母大小写转换的方法
Java提供了多种灵活的方法来处理字符串中的字母大小写转换。根据具体需求,可以选择适合的方法来实现。在大多数情况下,使用 String类或 Character类的方法已经足够。但是,在需要更复杂的逻辑或处理非常规字符集时,可以通过字符流或手动遍历字符串来实现更精细的控制。
213 18
|
4月前
|
存储 缓存 人工智能
Java int和Integer的区别
本文介绍了Java中int与Integer的区别及==与equals的比较机制。Integer是int的包装类,支持null值。使用==比较时,int直接比较数值,而Integer比较对象地址;在-128至127范围内的Integer值可缓存,超出该范围或使用new创建时则返回不同对象。equals方法则始终比较实际数值。
159 0
|
1月前
|
存储 Java 索引
(Python基础)新时代语言!一起学习Python吧!(二):字符编码由来;Python字符串、字符串格式化;list集合和tuple元组区别
字符编码 我们要清楚,计算机最开始的表达都是由二进制而来 我们要想通过二进制来表示我们熟知的字符看看以下的变化 例如: 1 的二进制编码为 0000 0001 我们通过A这个字符,让其在计算机内部存储(现如今,A 字符在地址通常表示为65) 现在拿A举例: 在计算机内部 A字符,它本身表示为 65这个数,在计算机底层会转为二进制码 也意味着A字符在底层表示为 1000001 通过这样的字符表示进行转换,逐步发展为拥有127个字符的编码存储到计算机中,这个编码表也被称为ASCII编码。 但随时代变迁,ASCII编码逐渐暴露短板,全球有上百种语言,光是ASCII编码并不能够满足需求
127 4
|
1月前
|
Java 编译器 Go
【Java】(5)方法的概念、方法的调用、方法重载、构造方法的创建
Java方法是语句的集合,它们在一起执行一个功能。方法是解决一类问题的步骤的有序组合方法包含于类或对象中方法在程序中被创建,在其他地方被引用方法的优点使程序变得更简短而清晰。有利于程序维护。可以提高程序开发的效率。提高了代码的重用性。方法的名字的第一个单词应以小写字母作为开头,后面的单词则用大写字母开头写,不使用连接符。例如:addPerson。这种就属于驼峰写法下划线可能出现在 JUnit 测试方法名称中用以分隔名称的逻辑组件。
188 4
|
2月前
|
算法 安全 Java
除了类,Java中的接口和方法也可以使用泛型吗?
除了类,Java中的接口和方法也可以使用泛型吗?
130 11
|
1月前
|
编解码 Java 开发者
Java String类的关键方法总结
以上总结了Java `String` 类最常见和重要功能性方法。每种操作都对应着日常编程任务,并且理解每种操作如何影响及处理 `Strings` 对于任何使用 Java 的开发者来说都至关重要。
250 5
|
2月前
|
Java 开发者
Java 函数式编程全解析:静态方法引用、实例方法引用、特定类型方法引用与构造器引用实战教程
本文介绍Java 8函数式编程中的四种方法引用:静态、实例、特定类型及构造器引用,通过简洁示例演示其用法,帮助开发者提升代码可读性与简洁性。
|
3月前
|
算法 Java 开发者
Java 项目实战数字华容道与石头迷阵游戏开发详解及实战方法
本文介绍了使用Java实现数字华容道和石头迷阵游戏的技术方案与应用实例,涵盖GUI界面设计、二维数组操作、游戏逻辑控制及自动解法算法(如A*),适合Java开发者学习游戏开发技巧。
265 46
|
2月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
350 1