Map深clone

Map深clone  

 

 

       近来看到很多的关于Map深克隆的文章,可谓是良莠不齐; 有的文章分析的比较好,但是给出的例子却不对。在我所看的文章的例子几乎都用String类作为演示例子。测试出来的结果貌似是对了,但是这个结果却蒙蔽了大家,就连原文作者也没有发现。值得注意的是:String这个类是非常特殊!从API中可以看到类的声明:public final class String ;注意是final修饰的,改变它的值,实则它的引用地址也发生了改变,下面我们看一下例子:
①String aStr = "a";
②String bStr = "a";
③bStr = "c";
当程序执行完①时,内存中将保存“a”并将aStr指向这个内存地址;但执行到②时,注意,此时并没有开辟新的内存,而是将bStr直接指向“a”;因此aStr与bStr一定是完全相等的(注意,是完全相等;这个例子也可以区分‘equals’与‘==’的区别。)但程序执行到③时,内存就重新开辟空间保存“c” 此时bStr就指向“c”的内存地址。我们输出bStr确实看到bStr发生了改变,但是并没有改变原来bStr所指地址的那个值,也就是说并没有将“a”改成“c”,而是将bStr直接指向另一个引用地址,因此我们往往误以为bStr的‘值(地址和值)’改变了。 不打算继续说了,估计大家被绕晕了。简而言之就是:你一旦改变了String的值就意味着它所指向的内存地址也就发生了变化(这个原理同样也可以解释声明String类型变量时建议直接用“=String”而不是用“=new String()”的方式声明,以及String类型变量不要用累加次数过多(一般是3次或3次以下))。所以那些文章用String做演示是犯了一个非常低级的错误!  若用其它的类(比如自定义的JavaBean)代替String的话你就发现,其实任然还只是浅克隆,而大费周章的所重写的clone方法然与Object里面继承过来的方法结果仍然相同,可谓是白费了一番心思!
 下面本人写的一个Map深克隆的例子,仍然是通过重写clone方法来实现的,供给大家参考使用:

JAVABean , Map格式:Map<String,User>

/**

* @author TDW
*
*/

publicclassUser  implementsSerializable{
 privatestaticfinallong serialVersionUID =1L;
 privateString id;
 privateString userName;
 privateString password;
 privateString nickName;
 privateString[] hobby;

//get、set method 略

}

deep clone test :

package com.study.demo.clone;

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;
import com.study.api.bean.User;

/**
 * Map deep clone test
 * @author TDW
 *
 */
publicclassMapCloneTest{
 class customHashMap extendsHashMap<Object,Object>{
  privatestaticfinallong serialVersionUID =1L;

  public customHashMap(){
   super();
  }

  public customHashMap(int initialCapacity){
   super(initialCapacity);
  }

  publicObject clone(){
   Map<Object,Object> target =newHashMap<Object,Object>();
   try{
    ByteArrayOutputStream byteout =null;
    ObjectOutputStreamout=null;
    Object obj =null;
    for(Iterator<Object> keyIt =this.keySet().iterator(); keyIt
      .hasNext();){
     Object key = keyIt.next();
     byteout =newByteArrayOutputStream();
     out=newObjectOutputStream(byteout);
     out.writeObject(this.get(key));
     ByteArrayInputStream bytein =newByteArrayInputStream(
       byteout.toByteArray());
     ObjectInputStreamin=newObjectInputStream(bytein);
     obj =in.readObject();// 反序列化出来,就相当于将原来的值和地址(即引用)copy了一份
     target.put(key, obj);// 习惯上一般key是不做修改的,因此没有copy key的必要
           // ,倘若有必要则同样反序列化出来就行了(如果是String类型也无需反序列化,上面已经解释的很清楚了)
    }
   } catch(Exception e){
    e.printStackTrace();
   }
   return target;
  }
 }

 publicstaticvoid main(String[] args){
  User user1 =newUser();
  user1.setId("11111111111111");
  User user2 =newUser();
  user2.setId("22222222222222");
  customHashMap source =(newMapCloneTest()).new customHashMap();
  source.put("key1", user1);
  source.put("key2", user2);

  System.out.println(source);
  Map target =(Map) source.clone();
  User user =(User) target.get("key1");
  user.setId("xxxxxxxxxxxxxx");// 改变副本的值

  System.out.println(target);// 对比结果
  System.out.println(source);// 源,没有被修改
 }

}

输出结果大家自行对比。
  不仅如此,List也可以用此方式进行深克隆,凡是实现过序列号接口的都可以通过此方式进行深克隆,下面是list深克隆例子:

/**
  * List深度clone
  * @param src
  * @return
  */
 publicstaticArrayList<Object> copyList(ArrayList<Object> src){  
  ArrayList<Object> list =null;
  try{
   ByteArrayOutputStream byteout =newByteArrayOutputStream();  
         ObjectOutputStreamout=newObjectOutputStream(byteout);  
         out.writeObject(src);
         ByteArrayInputStream bytein =newByteArrayInputStream(byteout.toByteArray());  
         ObjectInputStreamin=newObjectInputStream(bytein);  
         list =(ArrayList<Object>)in.readObject();
        }catch(Exception e){
         System.out.println("cache copy error !");
         e.printStackTrace();
        }
        return list;  
    }

 
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值