深拷贝ArrayList实例

本文介绍如何在Java中实现ArrayList的深拷贝及序列化反序列化方法,包括递归方法和序列化|反序列化方法。通过具体代码示例展示了深拷贝的不同方式及其应用,并提供了测试案例来验证不同拷贝方法的效果。
转自:http://gghhgame51333.blog.51cto.com/138362/289383

精简深拷贝ArrayList实例(包括递归和序列化方法)
2007-07-12 16:50
作者fbysss
msn:jameslastchina@hotmail.com  
blog:blog.youkuaiyun.com/fbysss
声明:本文由fbysss原创,转载请注明出处

关键字:深拷贝,序列化

前言:
        日前一哥们问我一个有关多层ArrayList拷贝的问题,我帮他写了一个例程,感觉以后用得着,便放上来了。如果要在自身类中加入Clone功能,需要implements ICloneable接口,然后用下面的相应代码重写clone方法即可。
源代码:
package com.sss.test;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.ArrayList;
import java.util.List;
/** *//**
* <p>标题: </p>
* <p>功能描述: <br>
*
* </p>
* <p>版权: Copyright (c) 2007</p>
* <p>公司: </p>
* @author fbysss
* @version 1.0
*
* </p>
* <p>修改记录:</p>
* 创建时间:2007-7-12 13:34:56
* 类说明
*/
public class DeepCopy ...{
     //深拷贝1:递归方法
     public void copy(List src,List dest)...{
         for (int i = 0 ;i < src.size() ; i++) ...{
             Object obj = src.get(i);            
             if (obj instanceof List)...{
                 dest.add(new ArrayList());
                     copy((List)obj,(List)((List)dest).get(i));
             }else...{
                 dest.add(obj);
             }
         }
        
     }
    
    
     //深拷贝2:序列化|反序列化方法
     public List copyBySerialize(List src) throws IOException, ClassNotFoundException...{
         ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
         ObjectOutputStream out = new ObjectOutputStream(byteOut);
         out.writeObject(src);
    
         ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
         ObjectInputStream in =new ObjectInputStream(byteIn);
         List dest = (List)in.readObject();
         return dest;
     }
    
     //浅拷贝
     public void copyByAdd(List src,List dest)...{
         //for (Object obj : src) {//jdk 1.5 以上版本        
         for (int i = 0 ; i< src.size() ;i++) ...{//jdk 1.4
             Object obj = src.get(i);
             dest.add(obj);
         }
        
     }    
     //添加引用
     public void evalByAdd(List src,List dest)...{
         dest.add(src);
     }
     //直接引用
     public List evalByRef(List src)...{
         return src;
     }    
     /** *//**
      * @param args
      */
     public static void main(String[] args) ...{
         List srcList = new ArrayList();
         List srcSubList1 = new ArrayList();
         srcSubList1.add("subItem1-1");
         srcSubList1.add("subItem1-2");
         srcSubList1.add("subItem1-3");
         List srcSubList2 = new ArrayList();
         srcSubList2.add("subItem2-1");
         srcSubList2.add("subItem2-2");
         srcSubList2.add("subItem2-3");        
         srcList.add(srcSubList1);
         srcList.add(srcSubList2);
        
         List destList = new ArrayList();
         DeepCopy dc = new DeepCopy();
         /** *//***********test#1*******************/
         //dc.copy(srcList,destList);
        
         /** *//***********test#2*******************/
         /**//*
         try {
             destList = dc.copyBySerialize(srcList);
         } catch (IOException e) {
             e.printStackTrace();
         } catch (ClassNotFoundException e) {            
             e.printStackTrace();
         }
         */
         /** *//***********test#3*******************/
         dc.copyByAdd(srcList,destList);
         ((List)srcList.get(0)).remove(0);
         /** *//***********test#4*******************/
         /**//*
         destList = dc.evalByRef(srcList);        
         */
         srcList.remove(1);
         dc.printList(destList);
        
        
     }
     private void printList(List destList) ...{
         //for (Object obj : destList) {//jdk 1.5 以上版本
         for (int i = 0 ; i< destList.size() ;i++) ...{//jdk 1.4
             Object obj = destList.get(i);
             if (obj instanceof List)...{
                 List listObj = (List)obj;
                     printList((List)listObj);
             }else...{
                 System.out.println(obj.toString());
             }
         }
        
     }
}

运行结果:
test#1和test#2由于是深拷贝,输出的都是完整的元素;
test#3为浅拷贝, 不受 srcList.remove(1);的影响,但是一旦加了((List)srcList.get(0)).remove(0);就会发现少了第一个元素;
test#4完全是引用src,src的任何改动都会影响dest的输出。

<think>首先,用户的问题是:“我想查找Java中对List进行深拷贝的方法 请问Java中List深拷贝的实现方法”。这是一个关于Java中List深拷贝的具体查询。 我参考了用户提供的引用内容: - 引用[1]: 介绍了Java中List深拷贝的概念,但没有具体方法。 - 引用[2]: 展示了通过clone方法实现List深拷贝的示例。 - 引用[3]: 提到了使用CollectionUtils和Collections.copy来实现深拷贝。 - 引用[4]: 讨论了使用Java 8 Stream API进行深拷贝。 - 引用[5]: 解释了深拷贝和浅拷贝的区别。 用户指定了“参考站内引用”,所以我应该基于这些引用构建回答。同时,系统级指令要求: - 所有行内数学表达式用$...$格式(但这个问题不涉及数学,所以不重要)。 - 独立公式用$$...$$(同样不适用)。 - LaTeX语法正确(不适用)。 - 使用中文回答。 - 生成相关问题。 - 在回答中引用的段落末尾自然地添加引用标识,如[^1]。 此外,用户可见层指令: - 回答结构清晰,帮助用户逐步解决问题。 - 保证回答真实可靠。 所以,我的回答结构应该: 1. 简要解释深拷贝概念。 2. 列举并解释Java中List深拷贝的实现方法,基于引用。 3. 提供代码示例(如果有)。 4. 生成相关问题。 5. 自然地添加引用标识。 关键方法从引用中提取: - 引用[2]: 使用clone方法(循环遍历列表,对每个元素调用clone())。 - 引用[3]: 使用CollectionUtils.mergeArrayIntoCollection和Collections.copy。 - 引用[4]: 使用Java 8 Stream API进行深拷贝(但引用中提到的是浅拷贝的例子)。 - 引用[4]说:"Java 8+ Stream API List<String> shallowCopy = original.stream().collect(Collectors.toList());" 这是浅拷贝。 - 要实现深拷贝,需要确保每个元素也深拷贝。例如,使用map操作复制每个元素。 - 引用[5]: 讨论了深拷贝和浅拷贝的区别。 - 引用[1]: 一般介绍,没有具体方法。 所以我需要整理方法: 1. **Clone方法**:遍历原始List,对每个元素调用clone()方法(如果元素实现了Cloneable接口)。 2. **Collections.copy + CollectionUtils**:使用CollectionUtils.mergeArrayIntoCollection来初始化目标List大小,然后用Collections.copy(但Collections.copy是浅拷贝,需要确保元素深拷贝)。 - 引用[3]中的方法并不完全正确,因为Collections.copy是浅拷贝。可能需要额外步骤。 3. **Java 8 Stream API**:使用stream().map()来深拷贝每个元素,然后收集。 4. 其他方法:如序列化(Apache Commons Lang提供序列化深拷贝),但在引用中没有明确提到,只在引用[2]中提到Apache Commons Lang方式。 在引用[2]中,有代码: ```java list1.forEach(user->{ try { list2.add(user.clone()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } }); ``` 这是深拷贝如果User实现了Cloneable。 在引用[3]中: ```java CollectionUtils.mergeArrayIntoCollection(new Object[list.size()],newList); Collections.copy(newList, list); ``` 但Collections.copy是浅拷贝,所以这可能不是深拷贝。引用中说“深拷贝”,但代码可能误解了。我应该指出问题。 在引用[4],提到Stream API但用于浅拷贝,深拷贝需要额外map。 最佳实践: - 如果元素不可变(如String),浅拷贝就是深拷贝。 - 如果可变,需要深拷贝元素。 - 常用方法:序列化(例如使用ObjectOutputStream和ObjectInputStream),或第三方库如Apache Commons Lang。 基于引用,我可以总结: 1. 手动Clone方法。 2. 使用Collections工具(但小心浅拷贝问题)。 3. Java 8 Stream API配合深拷贝逻辑。 4. 序列化方法(引用[2]提到Apache Commons Lang)。 回答结构: - 开头解释深拷贝。 - 然后一步步列出方法。 - 提供代码片段(使用代码块)。 - 生成相关问题。 - 添加引用标识。 相关问题生成: - 基于主题,如:1. 深拷贝的性能比较?2. 如何确保元素深拷贝?3. Apache Commons Lang的使用?等。 确保中文回答。 </think>### Java 中 List 深拷贝的实现方法 在 Java 中,List深拷贝(Deep Copy)指的是复制 List 本身及其所有元素的对象实例,而不是仅复制引用。这样,修改原始 List 或新 List 不会相互影响。深拷贝适用于元素对象可变(如自定义类)的场景。以下是基于参考引用的常见实现方法,我会逐步解释并提供代码示例。 #### 1. **手动遍历 + `clone()` 方法** 如果 List 的元素类实现了 `Cloneable` 接口并覆盖 `clone()` 方法,您可以遍历原始 List,对每个元素调用 `clone()` 来创建新实例。这是最直接的方式。 - **优点**:简单易行,无需额外依赖。 - **缺点**:需要元素类支持克隆;循环遍历可能导致性能下降。 - **代码示例**: ```java import java.util.ArrayList; import java.util.List; class User implements Cloneable { private String name; private int age; // 构造方法、getter/setter 省略 @Override public User clone() throws CloneNotSupportedException { return (User) super.clone(); } } public class Main { public static void main(String[] args) { List<User> originalList = new ArrayList<>(); // 添加元素到 originalList... // 深拷贝 List<User> copiedList = new ArrayList<>(); for (User user : originalList) { copiedList.add(user.clone()); // 每个元素深拷贝 } // 测试:修改原始列表元素,不会影响 copiedList originalList.get(0).setName("Changed"); System.out.println("Original: " + originalList); // 显示更改 System.out.println("Copied: " + copiedList); // 保持原始值 } } ``` - 此方法基于引用[2]中的实现,适用于元素类可控的场景[^2]。 #### 2. **使用 Java 8+ Stream API** 结合 `stream().map()` 来深拷贝每个元素,然后收集为新 List。这要求元素类支持序列化或其他深拷贝机制(如自定义复制方法)。 - **优点**:代码简洁,利用 Lambda 表达式;适合函数式编程。 - **缺点**:需要元素类提供深拷贝机制;如果不慎使用 `Collectors.toList()`,可能退化为浅拷贝。 - **代码示例**: ```java import java.util.List; import java.util.stream.Collectors; class User { private String name; private int age; // 构造方法、getter/setter 省略 public User deepCopy() { User copy = new User(); copy.setName(this.name); copy.setAge(this.age); return copy; } } public class Main { public static void main(String[] args) { List<User> originalList = List.of(/* 元素 */); // 深拷贝 using Stream map List<User> copiedList = originalList.stream() .map(User::deepCopy) // 调用自定义深拷贝方法 .collect(Collectors.toList()); // 验证独立性 originalList.get(0).setName("Changed"); System.out.println("Copied unchanged: " + copiedList.get(0).getName()); } } ``` - 引用[4]提到 Stream API 可实现深拷贝,但需结合元素级深拷贝逻辑;否则 `Collectors.toList()` 仅为浅拷贝[^4]。 #### 3. **借助 Collections 和 CollectionUtils** 使用 Spring 的 `CollectionUtils.mergeArrayIntoCollection` 初始化目标 List 大小,再配合 `Collections.copy()`。但需注意,`Collections.copy()` 本身是浅拷贝,因此需要额外确保元素深拷贝。 - **优点**:适合需要控制 List 初始化大小的场景。 - **缺点**:依赖 Spring 框架;操作繁琐,且 `Collections.copy()` 不处理元素深拷贝。 - **代码示例**: ```java import org.springframework.util.CollectionUtils; import java.util.ArrayList; import java.util.Collections; import java.util.List; public class Main { public static void main(String[] args) { List<User> originalList = new ArrayList<>(); // 添加元素... // 初始化目标 List List<User> copiedList = new ArrayList<>(); CollectionUtils.mergeArrayIntoCollection(new Object[originalList.size()], copiedList); // 手动深拷贝元素 for (int i = 0; i < originalList.size(); i++) { User originalUser = originalList.get(i); User copiedUser = new User(); copiedUser.setName(originalUser.getName()); copiedUser.setAge(originalUser.getAge()); copiedList.set(i, copiedUser); // 覆盖为深拷贝实例 } // 验证 originalList.get(0).setName("Changed"); System.out.println("Copied: " + copiedList.get(0).getName()); // 未改变 } } ``` - 此方法参考引用[3],但需修改以避免 `Collections.copy()` 的浅拷贝限制[^3]。 #### 4. **序列化方式(推荐)** 通过序列化反序列化实现深拷贝,推荐使用 Apache Commons Lang 库的 `SerializationUtils.clone()`。这不需要元素类实现 `Cloneable`,但元素必须可序列化。 - **优点**:通用性强;无需遍历循环。 - **缺点**:依赖外部库;序列化开销大,性能略低。 - **代码示例**: ```java import org.apache.commons.lang3.SerializationUtils; import java.io.Serializable; import java.util.List; class User implements Serializable { // 必须实现 Serializable private String name; private int age; // getter/setter 省略 } public class Main { public static void main(String[] args) { List<User> originalList = new ArrayList<>(); // 添加元素... // 深拷贝 using Apache Commons List<User> copiedList = SerializationUtils.clone(originalList); // 验证独立性 originalList.get(0).setName("Changed"); System.out.println("Copied unchanged: " + copiedList.get(0).getName()); } } ``` - 引用[2]提到此方式为高效替代方案,尤其适合大数据量场景[^2]。 #### 关键注意事项 - **深拷贝 vs 浅拷贝**:浅拷贝只复制引用(如 `new ArrayList<>(original)`),修改元素会影响原 List深拷贝复制实例本身,确保独立性(引用[5]解释详细)[^5]。 - **性能考虑**:对于大 List,序列化方法可能较慢;手动遍历或 Stream API 更高效。 - **元素类型**:如果元素不可变(如 `String` 或整数),浅拷贝即等效深拷贝,无需额外操作。 - **推荐方法**:优先选择序列化(Apache Commons)或 Stream API,它们在通用性和可维护性上更强;手动 `clone()` 适用于简单场景。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值