Java deep copy

本文介绍了一种使用Java序列化实现对象深克隆的方法。通过将对象写入字节流再从流中读取的方式完成复制过程。这种方法适用于实现了Serializable接口的对象。
public static <E> E deepClone(E object) throws IOException, ClassNotFoundException {
        ByteArrayOutputStream bo = new ByteArrayOutputStream();
        ObjectOutputStream oo = new ObjectOutputStream(bo);
        oo.writeObject(object);
        ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
        ObjectInputStream oi = new ObjectInputStream(bi);
        return (E)oi.readObject();
    }

转载于:https://www.cnblogs.com/frankliiu-java/archive/2009/12/15/1624601.html

<think> 在Java中,Map的复制通常指的是创建一个新的Map对象,并将原始Map中的所有键值对复制到新Map中。但需要注意的是,如果Map中的值对象是可变对象(如自定义对象、集合等),那么复制时可能需要进行深拷贝(deep copy)或浅拷贝(shallow copy),具体取决于需求。 浅拷贝(Shallow Copy):只复制对象的引用,而不复制引用指向的对象本身。因此,如果修改了原Map中的对象,新Map中的对象也会随之改变。 深拷贝(Deep Copy):不仅复制对象本身,还递归复制对象所引用的所有对象。因此,新Map和原Map中的对象是完全独立的。 Java中常用的Map复制方法: 1. 使用构造函数:大多数Map实现类(如HashMap, TreeMap, LinkedHashMap)都提供了一个构造函数,可以接受另一个Map作为参数,从而创建一个新的Map并复制所有键值对。这是浅拷贝。 2. 使用Map.putAll()方法:将指定Map中的所有键值对复制到当前Map中。 3. 使用Java 8的Stream API进行复制(同样也是浅拷贝)。 4. 使用序列化进行深拷贝:如果Map中的对象是可序列化的,我们可以通过序列化和反序列化来实现深拷贝。 5. 使用克隆(Clone)方法:但注意,Java中的Map接口没有继承Cloneable接口,所以不能直接调用clone()。但一些具体的实现类(如HashMap)提供了clone()方法(也是浅拷贝)。 下面分别给出几种复制方式的示例代码: ### 1. 浅拷贝(Shallow Copy) #### 方法1:构造函数 ```java import java.util.HashMap; import java.util.Map; public class MapCopyExample { public static void main(String[] args) { Map<String, Integer> originalMap = new HashMap<>(); originalMap.put("a", 1); originalMap.put("b", 2); // 使用构造函数复制 Map<String, Integer> shallowCopy = new HashMap<>(originalMap); System.out.println("Original Map: " + originalMap); System.out.println("Shallow Copy: " + shallowCopy); } } ``` #### 方法2:putAll方法 ```java Map<String, Integer> shallowCopy2 = new HashMap<>(); shallowCopy2.putAll(originalMap); ``` ### 2. 深拷贝(Deep Copy) 深拷贝需要复制Map中的每个对象。如果Map中的值是不可变对象(如Integer、String等),那么浅拷贝就等同于深拷贝,因为不可变对象无法被修改。但如果值是可变的,我们就需要递归地复制这些对象。 #### 方法1:手动复制每个对象 假设我们有一个可变的类,例如: ```java class Student implements Cloneable { private String name; public Student(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } ``` 然后我们可以这样深拷贝: ```java Map<String, Student> original = new HashMap<>(); original.put("john", new Student("John Doe")); Map<String, Student> deepCopy = new HashMap<>(); for (Map.Entry<String, Student> entry : original.entrySet()) { try { deepCopy.put(entry.getKey(), (Student) entry.getValue().clone()); } catch (CloneNotSupportedException e) { e.printStackTrace(); } } ``` 注意:上面的clone方法在Student类中重写,并且该类实现了Cloneable接口。但是,使用clone()方法进行深拷贝需要注意,如果Student类中有引用类型的字段,那么这些字段也需要实现Cloneable并重写clone方法,否则这些字段还是浅拷贝。 #### 方法2:序列化 如果Map及其包含的所有对象都是可序列化的,我们可以通过序列化和反序列化来实现深拷贝。 ```java import java.io.*; public class DeepCopyUtil { @SuppressWarnings("unchecked") public static <T extends Serializable> T deepCopy(T object) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(object); oos.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (T) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } } } // 使用 Map<String, Student> deepCopy = DeepCopyUtil.deepCopy(originalMap); ``` 注意:使用序列化方式要求Map中的键和值都实现Serializable接口。 ### 示例总结 - 浅拷贝适用于值类型是不可变对象(如String、Integer等)的情况,或者你确实希望共享对象引用。 - 深拷贝适用于需要完全独立的对象副本,尤其是当值对象是可变的,并且不希望原Map和拷贝Map之间相互影响。 ### 注意事项 - 使用构造函数或putAll()方法进行复制时,如果原Map是特殊类型的Map(如TreeMap),新Map的类型可以是HashMap(除非你需要保持原Map的顺序特性,那么就要选择相同的实现类或者LinkedHashMap、TreeMap)。 - 深拷贝通常比浅拷贝开销大,因为它涉及到创建每个对象及其内部对象的副本。 根据具体的需求选择合适的复制方式。 ### 完整示例代码(深拷贝使用序列化) 下面是一个使用序列化进行深拷贝的完整示例: ```java import java.io.*; import java.util.HashMap; import java.util.Map; public class DeepCopyExample { public static void main(String[] args) { Map<String, Student> originalMap = new HashMap<>(); originalMap.put("john", new Student("John Doe")); // 深拷贝 Map<String, Student> deepCopy = deepCopyMap(originalMap); // 修改原Map中的Student对象 originalMap.get("john").setName("Modified John"); System.out.println("Original Map: " + originalMap.get("john").getName()); System.out.println("Deep Copy: " + deepCopy.get("john").getName()); } @SuppressWarnings("unchecked") public static <K extends Serializable, V extends Serializable> Map<K, V> deepCopyMap(Map<K, V> original) { try { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(original); oos.flush(); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return (Map<K, V>) ois.readObject(); } catch (IOException | ClassNotFoundException e) { throw new RuntimeException(e); } } static class Student implements Serializable { private String name; public Student(String name) { this.name = name; } public void setName(String name) { this.name = name; } public String getName() { return name; } @Override public String toString() { return "Student{name='" + name + "'}"; } } } ``` 在这个例子中,我们修改了原Map中的Student对象,深拷贝后的Map中的对象保持不变,说明它们是独立的。 ### 相关问题 根据用户的要求,最后提出几个相关问题: </think> ### Java Map Copy 详解 在 Java 中复制 `Map` 有两种主要方式:**浅拷贝**(只复制引用)和**深拷贝**(递归复制所有对象)。以下是不同场景下的实现方法: #### 1. 浅拷贝(Shallow Copy) ```java import java.util.*; public class MapCopy { public static void main(String[] args) { Map<String, Integer> originalMap = new HashMap<>(); originalMap.put("A", 1); originalMap.put("B", 2); // 方法 1:构造函数复制 Map<String, Integer> shallowCopy1 = new HashMap<>(originalMap); // 方法 2:putAll() 方法 Map<String, Integer> shallowCopy2 = new HashMap<>(); shallowCopy2.putAll(originalMap); // 方法 3:Java 8 Stream API Map<String, Integer> shallowCopy3 = originalMap.entrySet() .stream() .collect(Collectors.toMap(Map.Entry::getKey, Map.Entry::getValue)); System.out.println("浅拷贝结果: " + shallowCopy1); } } ``` **解释**: - 上述方法只复制键值对的引用,不创建新对象 - 修改原始 Map 中的对象会影响到所有拷贝(如值是可变对象时) - 时间复杂度:O(n) #### 2. 深拷贝(Deep Copy) ```java import java.util.*; import java.util.stream.Collectors; class Data implements Cloneable { int value; Data(int v) { this.value = v; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } public class DeepMapCopy { public static void main(String[] args) throws Exception { Map<String, Data> original = new HashMap<>(); original.put("X", new Data(10)); original.put("Y", new Data(20)); // 手动深拷贝(需要对象支持 clone) Map<String, Data> deepCopy = new HashMap<>(); for (Map.Entry<String, Data> entry : original.entrySet()) { deepCopy.put(entry.getKey(), (Data) entry.getValue().clone()); } // 使用序列化(要求所有对象实现 Serializable) Map<String, Data> serializedCopy = deepCopyBySerialization(original); } @SuppressWarnings("unchecked") private static <K, V extends Serializable> Map<K, V> deepCopyBySerialization(Map<K, V> map) { try (ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos)) { oos.writeObject(map); oos.flush(); try (ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis)) { return (Map<K, V>) ois.readObject(); } } catch (IOException | ClassNotFoundException e) { throw new RuntimeException("Deep copy failed", e); } } } ``` **解释**: - 深拷贝创建完全独立的对象副本 - 方法 1:需要对象实现 `Cloneable` 接口(可能不彻底) - 方法 2:序列化要求所有键值实现 `Serializable` - 推荐使用第三方库如 Apache Commons 的 `SerializationUtils.clone()` #### 3. 特殊情况处理 ```java // ConcurrentHashMap 复制 Map<String, Integer> concurrentCopy = new ConcurrentHashMap<>(originalMap); // 不可变 Map 复制 Map<String, Integer> immutableCopy = Map.copyOf(originalMap); // Java 10+ ``` #### 最佳实践建议 1. 基本数据类型/不可变对象:使用浅拷贝 2. 嵌套可变对象:使用深拷贝 3. 线程安全场景:使用 `ConcurrentHashMap` 复制 4. 需要防御性编程:使用 `Collections.unmodifiableMap()`
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值