HashMap不支持深拷貝問題解決方案

前言

當構造一個複雜耗時的對象的時候,而且實際用的時候僅僅只是需要改動一小部分,這個時候我們往往會想到使用實現Cloneable接口來開啓對象克隆。但是這裏有一個問題就是,對於自定義對象無法支持深拷貝,HashMap實現了Cloneable接口,自然也是存在這種問題的。

示例

  • 示例代碼
public class Test3 {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        HashMap<String, Person> map = new HashMap<>();
        Person person = new Person();
        person.setName("小明");
        map.put("xiaoming", person);

        HashMap<String, Person> map1 = (HashMap<String, Person>) map.clone();
        Person person1 = map1.get("xiaoming");

        System.out.println(person);
        System.out.println(person1);
    }
}
  • 結果
cn.itoak.storm.clone.Person@4dd8dc3
cn.itoak.storm.clone.Person@4dd8dc3
  • 說明
    在上面的示例中,Map的value是自定義類Person,在map.clone()後,我們看到person和person1的內存地址是一樣的,這樣的拷貝,在很多時候是會存在問題的,屬於淺拷貝。

解決方案

  • 思路
    通過重寫HashMap的clone(),實現value的拷貝,這種做法就相當於我們自己去增強了HashMap的clone函數。由於實現Cloneable接口非必須重寫clone()函數,所有我們得定義RequiredCloneable接口繼承Cloneable接口,讓自定義類去實現RequiredCloneable接口

  • 方案代碼

核心:RequiredCloneable接口

public interface RequiredCloneable extends Cloneable {
    Object clone();
}

核心:自定義DeepCloneHashMap

public class DeepCloneHashMap<K, V extends RequiredCloneable> extends HashMap<K, V> {
    @Override
    @SuppressWarnings("unchecked")
    public DeepCloneHashMap<K, V> clone() {
        DeepCloneHashMap<K, V> deepCloneHashMap = (DeepCloneHashMap<K, V>) super.clone();
        this.forEach((key, value) -> deepCloneHashMap.put(key, (V) value.clone()));
        return deepCloneHashMap;
    }
}

以上兩段代碼可直接使用,需要注意的地方:
(1)V extends RequiredCloneable,限制V的類型;
(2)value.clone(),這個就是爲什麼需要使用RequiredCloneable接口的原因

自定義Person類

public class Person implements RequiredCloneable {
    public String name;
    @Override
    public Person clone() {
        try {
            return (Person) super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
        return null;
    }
}
  • 使用示例
public class Test {
    public static void main(String[] args) {
        DeepCloneHashMap<String, Person> map = new DeepCloneHashMap<>();
        Person person = new Person();
        person.setName("小明");
        map.put("xiaoming", person);

        DeepCloneHashMap<String, Person> map1 = map.clone();
        Person person1 = map1.get("xiaoming");

        System.out.println(person);
        System.out.println(person1);
    }
}
  • 結果
cn.itoak.storm.clone.Person@46f7f36a
cn.itoak.storm.clone.Person@421faab1

最後

以上是筆者在工作中發現的問題,以及最後的解決方案,以上方案不會處理更深層次的拷貝,意思也就是說不會拷貝Person類中自定義的類,由於筆者的問題不涉及更深次的拷貝,因而也沒有繼續處理,這裏僅僅是拋磚引玉,提供一種解決思路吧。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章