楼主是一名asp.net攻城狮,最近经常跑java组客串帮忙开发,所以最近对java的一些基础知识特别上心。却遇到需要将一个对象深拷贝出来做其他事情,而原对象保持原有状态的情况。(实在是不想自己new一个出来,然后对着一堆字段赋值......好吧,再此之前我没有关心是否项目框架有深拷贝的方法),然后就想着用反射实现吧....接下来
是我自己的原因,还是真的不存在这样的纯用反射实现的深拷贝方式....(c#是有纯反射实现的)
但也不能算自己白忙活吧,也找到了其他实现深拷贝的方式(但是每种方式我都觉得并不是太合理,也许是因为c#的方式带入了吧,最后贴出c#版本纯反射实现深拷贝的代码)
方式一:实现Cloneable接口,重写clone方法
实体类:一个轮胎类,一个车辆类,车辆中包含轮胎
/**轮胎类**/ public class Tire implements Cloneable { public String color; public int radius; public Tire(){} public Tire(String color, int radius) { this.color = color; this.radius = radius; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } /**车辆类**/ public class Car implements Cloneable{ 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; } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } }
@Test public void test() throws CloneNotSupportedException { Tire tire = new Tire("black",100); Car car = new Car("奔驰","white",tire); Car car_copy = (Car)car.clone(); System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode()); System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode()); car_copy.color = "blue"; System.out.println("car_copy:"+car_copy.color+" car:"+car.color); }
输出结果:
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方法:
@Override protected Object clone() throws CloneNotSupportedException { Car car = (Car)super.clone(); car.tire = (Tire)car.tire.clone(); return car; }
输出结果:
car:1223737555 car.tire:906199566 car_copy:542081238 car_copy.tire:1133736492 car_copy:blue car:white
这样最终实现了,但这种方式用到项目中并不是很合适吧,每个需要深拷贝的类,都要实现Cloneable接口,并覆盖其clone方法,遇到引用其他类时候更是需要修改clone方法,要是引用其他类,其他类再引用其他类呢?这不好吧......
方式二:通过序列化与反序列化实现(实现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; } }
深拷贝方法:
@SuppressWarnings("unchecked") public static Object deepClone(Object obj) { Object copyObj = null; ObjectOutputStream out = null; ObjectInputStream in = null; try { // 序列化 ByteArrayOutputStream bufferOut = new ByteArrayOutputStream(); out = new ObjectOutputStream(bufferOut); out.writeObject(obj); // 反序列化 ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray()); in = new ObjectInputStream(bufferIn); copyObj = in.readObject(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ try{ if(in != null){ in.close(); } if(out!=null){ out.close(); } }catch(IOException e){ throw new RuntimeException(e); } } return copyObj; }
单元测试:
@Test public void test() throws CloneNotSupportedException { Tire tire = new Tire("black",100); Car car = new Car("奔驰","white",tire); Car car_copy = (Car)deepClone(car); System.out.println("car:"+car.hashCode()+" car.tire:"+car.tire.hashCode()); System.out.println("car_copy:"+car_copy.hashCode()+" car_copy.tire:"+car_copy.tire.hashCode()); car_copy.color = "blue"; System.out.println("car_copy:"+car_copy.color+" car:"+car.color); }
输出结果:
car:2019524978 car.tire:855703640 car_copy:1407965019 car_copy.tire:545768040 car_copy:blue car:white
从结果集中可以看出是深拷贝是正确的,但是每个类还是需要实现Serializable,好像也不合适吧......
优化一下深拷贝方法:将其换成泛型,这样拷贝出来就不需要强转了(好吧,其实也没比上面的方法好到哪去...)
@SuppressWarnings("unchecked") public static <T> T deepClone(T obj) { T copyObj = null; ObjectOutputStream out = null; ObjectInputStream in = null; try { // 序列化 ByteArrayOutputStream bufferOut = new ByteArrayOutputStream(); out = new ObjectOutputStream(bufferOut); out.writeObject(obj); // 反序列化 ByteArrayInputStream bufferIn = new ByteArrayInputStream(bufferOut.toByteArray()); in = new ObjectInputStream(bufferIn); copyObj = (T)in.readObject(); } catch (Exception e) { e.printStackTrace(); throw new RuntimeException(e); }finally{ try{ if(in != null){ in.close(); } if(out!=null){ out.close(); } }catch(IOException e){ throw new RuntimeException(e); } } return copyObj; }
通过序列化与反序列化深拷贝还有更简单的实现方式,就是需要导个包(拷贝的类也必须实现Serializable接口),当然,我已经为你们准备好了 点击->org.apache.commons.lang
深拷贝方法:就一行代码...
public Object deepClone(Object obj){ return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj); }
好了,java的暂时就到这里了,当然对于这两种方式并不是很满意...
-------------------------------------------------
C#深拷贝 反射实现
下面方法是c#的深拷贝,纯反射实现,无需实现任何接口,哦对,需要实体类有个无参的构造方法,简单使用强大,微软大法好啊......有需要用到的同学就拿去用吧,目前经过一个几百W的项目框架中考验,真的强大实用
/// <summary> /// 对象拷贝 /// </summary> /// <param name="obj">被复制对象</param> /// <returns>新对象</returns> private object CopyOjbect(object obj) { if (obj == null) { return null; } Object targetDeepCopyObj; Type targetType = obj.GetType(); //值类型 if (targetType.IsValueType == true) { targetDeepCopyObj = obj; } //引用类型 else { targetDeepCopyObj = System.Activator.CreateInstance(targetType); //创建引用对象 System.Reflection.MemberInfo[] memberCollection = obj.GetType().GetMembers(); foreach (System.Reflection.MemberInfo member in memberCollection) { //拷贝字段 if (member.MemberType == System.Reflection.MemberTypes.Field) { System.Reflection.FieldInfo field = (System.Reflection.FieldInfo)member; Object fieldValue = field.GetValue(obj); if (fieldValue is ICloneable) { field.SetValue(targetDeepCopyObj, (fieldValue as ICloneable).Clone()); } else { field.SetValue(targetDeepCopyObj, CopyOjbect(fieldValue)); } }//拷贝属性 else if (member.MemberType == System.Reflection.MemberTypes.Property) { System.Reflection.PropertyInfo myProperty = (System.Reflection.PropertyInfo)member; MethodInfo info = myProperty.GetSetMethod(false); if (info != null) { try { object propertyValue = myProperty.GetValue(obj, null); if (propertyValue is ICloneable) { myProperty.SetValue(targetDeepCopyObj, (propertyValue as ICloneable).Clone(), null); } else { myProperty.SetValue(targetDeepCopyObj, CopyOjbect(propertyValue), null); } } catch (System.Exception ex) { } } } } } return targetDeepCopyObj; }
以上这篇一种c#深拷贝方式完胜java深拷贝(实现上的对比分析)就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持小牛知识库。
单元测试:
主要内容:到底是浅拷贝还是深拷贝对于基本类型的数据以及简单的对象,它们之间的拷贝非常简单,就是按位复制内存。例如: b 和 obj2 都是以拷贝的方式初始化的,具体来说,就是将 a 和 obj1 所在内存中的数据按照二进制位(Bit)复制到 b 和 obj2 所在的内存, 这种默认的拷贝行为就是 浅拷贝 ,这和调用 memcpy() 函数的效果非常类似。 对于简单的类,默认的拷贝构造函数一般就够用了,我们也没有必要再显式地定义一
本文向大家介绍Java Clone深拷贝与浅拷贝的两种实现方法,包括了Java Clone深拷贝与浅拷贝的两种实现方法的使用技巧和注意事项,需要的朋友参考一下 1.首先,你要知道怎么实现克隆:实现Cloneable接口,在bean里面重写clone()方法,权限为public。 2.其次,你要大概知道什么是地址传递,什么是值传递。 3.最后,你要知道你为什么使用这个clone方法。 先看第一条,简
一、引言 对象拷贝(Object Copy)就是将一个对象的属性拷贝到另一个有着相同类类型的对象中去。在程序中拷贝对象是很常见的,主要是为了在新的上下文环境中复用对象的部分或全部数据。Java中有三种类型的对象拷贝:浅拷贝(Shallow Copy)、深拷贝(Deep Copy)、延迟拷贝(Lazy Copy)。 二、浅拷贝 1、什么是浅拷贝 浅拷贝是按位拷贝对象,它会创建一个新对象,这个对象有着
本文向大家介绍深拷贝浅拷贝的区别和实现?相关面试题,主要包含被问及深拷贝浅拷贝的区别和实现?时的应答技巧和注意事项,需要的朋友参考一下 参考回答: 数组的浅拷贝: 如果是数组,我们可以利用数组的一些方法,比如slice,concat方法返回一个新数组的特性来实现拷贝,但假如数组嵌套了对象或者数组的话,使用concat方法克隆并不完整,如果数组元素是基本类型,就会拷贝一份,互不影响,而如果是对象或数
浅拷贝 对于对象或数组类型,当我们将a赋值给b,然后更改b中的属性,a也会随着变化。 也就是说,a和b指向了同一块堆内存,所以修改其中任意的值,另一个值都会随之变化,这就是浅拷贝。 深拷贝 那么相应的,如果给b放到新的内存中,将a的各个属性都复制到新内存里,就是深拷贝。 也就是说,当b中的属性有变化的时候,a内的属性不会发生变化。 参考链接: 深拷贝与浅拷贝的实现(一) javaScript中浅拷
本文向大家介绍C/C++ 浅拷贝和深拷贝的实例详解,包括了C/C++ 浅拷贝和深拷贝的实例详解的使用技巧和注意事项,需要的朋友参考一下 C/C++ 浅拷贝和深拷贝的实例详解 深拷贝是指拷贝对象的具体内容,而内存地址是自主分配的,拷贝结束之后,两个对象虽然存的值是相同的,但是内存地址不一样,两个对象也互不影响,互不干涉。 浅拷贝就是对内存地址的复制,让目标对象指针和源对象指向同一片内存空间. 浅拷贝