• 一种c#深拷贝方式完胜java深拷贝(实现上的对比)


    楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心。却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况。(实在是不想自己new一个出来,然后对着一堆字段赋值......好吧,再此之前我没有关心是否项目框架有深拷贝的方法),然后就想着用反射实现吧....接下来

    是我自己的原因,还是真的不存在这样的纯用反射实现的深拷贝方式....(c#是有纯反射实现的)

    但也不能算自己白忙活吧,也找到了其他实现深拷贝的方式(但是每种方式我都觉得并不是太合理,也许是因为c#的方式带入了吧,最后贴出c#版本纯反射实现深拷贝的代码)

    先说java的深拷贝方式0.0

    java深拷贝方式一:实现Cloneable接口,重写clone方法

    实体类:一个轮胎类,一个车辆类,车辆中包含轮胎

     1 /**轮胎类**/
     2 public class Tire implements Cloneable {
     3     public String color;
     4     public int radius;
     5     public Tire(){}
     6     public Tire(String color, int radius) {
     7         this.color = color;
     8         this.radius = radius;
     9     }
    10 
    11     @Override
    12     protected Object clone() throws CloneNotSupportedException {
    13         return super.clone();
    14     }
    15 }
    16 /**车辆类**/
    17 public class Car implements Cloneable{
    18     public String name;
    19     public String color;
    20     public Tire tire;
    21     public Car() {}
    22     public Car(String name, String color, Tire tire) {
    23         this.name = name;
    24         this.color = color;
    25         this.tire = tire;
    26     }
    27     public void whistle(){
    28         System.out.println("汽车"+this.name+" 鸣笛...");
    29     }
    30     public String getName() {
    31         return name;
    32     }
    33     public void setName(String name) {
    34         this.name = name;
    35     }
    36     public String getColor() {
    37         return color;
    38     }
    39     public void setColor(String color) {
    40         this.color = color;
    41     }
    42     public Tire getTire() {
    43         return tire;
    44     }
    45     public void setTire(Tire tire) {
    46         this.tire = tire;
    47     }
    48     @Override
    49     protected Object clone() throws CloneNotSupportedException {
    50         return super.clone();
    51     }
    52 }

    单元测试:

     1 @Test
     2     public void test() throws CloneNotSupportedException {
     3         Tire tire = new Tire("black",100);
     4         Car car  = new Car("奔驰","white",tire);
     5         Car car_copy = (Car)car.clone();
     6         System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
     7         System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
     8         car_copy.color = "blue";
     9         System.out.println("car_copy:"+car_copy.color+"  car:"+car.color);
    10     }

    输出结果:

    car:1223737555 car.tire:906199566
    car_copy:542081238 car_copy.tire:906199566
    car_copy:blue  car:white

    从结果可以的之,car与car_copy的内存地址并不一致,但car.tire与car_copy.tire的内存地址却是一致的,说明“奔驰”车确实又造出了一辆,但却公用同一幅轮胎(这种情形....哈哈哈),好吧,也就是只复制了tire的引用,这可以说是深拷贝的不彻底 (hashCode()的值可以当作是内存地址来理解),那么要怎样才能彻底,真正的深拷贝?

    修改Car类中的clone方法:

    1 @Override
    2     protected Object clone() throws CloneNotSupportedException {
    3         Car car = (Car)super.clone();
    4         car.tire = (Tire)car.tire.clone();
    5         return car;
    6     }

    输出结果:

    car:1223737555 car.tire:906199566
    car_copy:542081238 car_copy.tire:1133736492
    car_copy:blue  car:white

    这样最终实现了,但这种方式用到项目中并不是很合适吧,每个需要深拷贝的类,都要实现Cloneable接口,并覆盖其clone方法,遇到引用其他类时候更是需要修改clone方法,要是引用其他类,其他类再引用其他类呢?这不好吧......

    java深拷贝方式二:通过序列化与反序列化实现(实现Serializable接口)

    实体类:与第一种方式类似,换成实现Serializable接口,去掉clone方法

    /**轮胎类**/
    @SuppressWarnings("serial")
    public class Tire implements java.io.Serializable {
        public String color;
        public int radius;
        public Tire(){}
        public Tire(String color, int radius) {
            this.color = color;
            this.radius = radius;
        }
    }
    /**车辆类**/
    @SuppressWarnings("serial")
    public class Car implements java.io.Serializable{
        public String name;
        public String color;
        public Tire tire;
        public Car() {}
        public Car(String name, String color, Tire tire) {
            this.name = name;
            this.color = color;
            this.tire = tire;
        }
        public void whistle(){
            System.out.println("汽车"+this.name+" 鸣笛...");
        }
        public String getName() {
            return name;
        }
        public void setName(String name) {
            this.name = name;
        }
        public String getColor() {
            return color;
        }
        public void setColor(String color) {
            this.color = color;
        }
        public Tire getTire() {
            return tire;
        }
        public void setTire(Tire tire) {
            this.tire = tire;
        }
    }

    深拷贝方法:

     1 @SuppressWarnings("unchecked")
     2     public static Object deepClone(Object obj)
     3     {
     4         Object copyObj = null;
     5         ObjectOutputStream out = null;
     6         ObjectInputStream in = null;
     7         try {
     8             // 序列化
     9             ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
    10             out = new ObjectOutputStream(bufferOut);
    11 
    12             out.writeObject(obj);
    13 
    14             // 反序列化
    15             ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
    16             in = new ObjectInputStream(bufferIn);
    17             copyObj = in.readObject();
    18         } catch (Exception e) {
    19             e.printStackTrace();
    20             throw new RuntimeException(e); 
    21         }finally{
    22              try{
    23                  if(in != null){
    24                      in.close();
    25                  }
    26                  if(out!=null){
    27                      out.close();
    28                  }
    29              }catch(IOException e){
    30                  throw new RuntimeException(e);
    31              }
    32         }
    33         return copyObj;
    34     }

    单元测试:

     1 @Test
     2     public void test() throws CloneNotSupportedException {
     3         Tire tire = new Tire("black",100);
     4         Car car  = new Car("奔驰","white",tire);
     5         Car car_copy = (Car)deepClone(car);
     6         System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode());
     7         System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode());
     8         car_copy.color = "blue";
     9         System.out.println("car_copy:"+car_copy.color+"  car:"+car.color);
    10     }

    输出结果:

    car:2019524978 car.tire:855703640
    car_copy:1407965019 car_copy.tire:545768040
    car_copy:blue  car:white

    从结果集中可以看出是深拷贝是正确的,但是每个类还是需要实现Serializable,好像也不合适吧......

    优化一下深拷贝方法:将其换成泛型,这样拷贝出来就不需要强转了(好吧,其实也没比上面的方法好到哪去...)

     1 @SuppressWarnings("unchecked")
     2     public static <T> T deepClone(T obj)
     3     {
     4         T copyObj = null;
     5         ObjectOutputStream out = null;
     6         ObjectInputStream in = null;
     7         try {
     8             // 序列化
     9             ByteArrayOutputStream bufferOut = new ByteArrayOutputStream();
    10             out = new ObjectOutputStream(bufferOut);
    11 
    12             out.writeObject(obj);
    13 
    14             // 反序列化
    15             ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray());
    16             in = new ObjectInputStream(bufferIn);
    17             copyObj = (T)in.readObject();
    18         } catch (Exception e) {
    19             e.printStackTrace();
    20             throw new RuntimeException(e); 
    21         }finally{
    22              try{
    23                  if(in != null){
    24                      in.close();
    25                  }
    26                  if(out!=null){
    27                      out.close();
    28                  }
    29              }catch(IOException e){
    30                  throw new RuntimeException(e);
    31              }
    32         }
    33         return copyObj;
    34     }

    通过序列化与反序列化深拷贝还有更简单的实现方式,就是需要导个包(拷贝的类也必须实现Serializable接口),当然,我已经为你们准备好了 点击->org.apache.commons.lang

    深拷贝方法:就一行代码...

    1 public Object deepClone(Object obj){
    2         return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj);
    3     }

    好了,java的暂时就到这里了,当然对于这两种方式并不是很满意...

    -------------------------------------------------

    C#深拷贝 反射实现

    下面方法是c#的深拷贝,纯反射实现,无需实现任何接口,哦对,需要实体类有个无参的构造方法,简单使用强大,微软大法好啊......有需要用到的同学就拿去用吧,目前经过一个几百W的项目框架中考验,真的强大实用

     1 /// <summary>
     2         /// 对象拷贝
     3         /// </summary>
     4         /// <param name="obj">被复制对象</param>
     5         /// <returns>新对象</returns>
     6         private object CopyOjbect(object obj) {
     7             if (obj == null) {
     8                 return null;
     9             }
    10             Object targetDeepCopyObj;
    11             Type targetType = obj.GetType();
    12             //值类型  
    13             if (targetType.IsValueType == true) {
    14                 targetDeepCopyObj = obj;
    15             }
    16             //引用类型   
    17             else {
    18                 targetDeepCopyObj = System.Activator.CreateInstance(targetType);   //创建引用对象   
    19                 System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers();
    20 
    21                 foreach (System.Reflection.MemberInfo member in memberCollection) {
    22                     //拷贝字段
    23                     if (member.MemberType == System.Reflection.MemberTypes.Field)
    24                     {
    25                         System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member;
    26                         Object fieldValue = field.GetValue(obj);
    27                         if (fieldValue is ICloneable)
    28                         {
    29                             field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone());
    30                         }
    31                         else
    32                         {
    33                             field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue));
    34                         }
    35 
    36                     }//拷贝属性
    37                     else if (member.MemberType == System.Reflection.MemberTypes.Property) {
    38                         System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member;
    39 
    40                         MethodInfo info = myProperty.GetSetMethod(false);
    41                         if (info != null) {
    42                             try {
    43                                 object propertyValue = myProperty.GetValue(obj, null);
    44                                 if (propertyValue is ICloneable) {
    45                                     myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null);
    46                                 }
    47                                 else {
    48                                     myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null);
    49                                 }
    50                             }
    51                             catch (System.Exception ex) {
    52 
    53                             }
    54                         }
    55                     }
    56                 }
    57             }
    58             return targetDeepCopyObj;
    59         }
  • 相关阅读:
    32.ExtJS简单的动画效果
    set、env、export差分
    【翻译】Why JavaScript Is and Will Continue to Be the First Choice of Programmers
    J2EE请求和响应—Servlet
    Leetcode: Spiral Matrix. Java
    Android正在使用Handler实现信息发布机制(一)
    Android开发工具综述,开发人员必备工具
    Android 从硬件到应用程序:一步一步爬上去 5 -- 在Frameworks蒂姆层硬件服务
    HDU 2828 DLX搜索
    2016第三周三
  • 原文地址:https://www.cnblogs.com/fnz0/p/5645527.html
Copyright © 2020-2023  润新知