一種c#深拷貝方式完勝java深拷貝(實現(xiàn)上的對比分析)
樓主是一名asp.net攻城獅,最近經(jīng)常跑java組客串幫忙開發(fā),所以最近對java的一些基礎(chǔ)知識特別上心。卻遇到需要將一個對象深拷貝出來做其他事情,而原對象保持原有狀態(tài)的情況。(實在是不想自己new一個出來,然后對著一堆字段賦值......好吧,再此之前我沒有關(guān)心是否項目框架有深拷貝的方法),然后就想著用反射實現(xiàn)吧....接下來

是我自己的原因,還是真的不存在這樣的純用反射實現(xiàn)的深拷貝方式....(c#是有純反射實現(xiàn)的)
但也不能算自己白忙活吧,也找到了其他實現(xiàn)深拷貝的方式(但是每種方式我都覺得并不是太合理,也許是因為c#的方式帶入了吧,最后貼出c#版本純反射實現(xiàn)深拷貝的代碼)
方式一:實現(xiàn)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);
}
輸出結(jié)果:
car:1223737555 car.tire:906199566 car_copy:542081238 car_copy.tire:906199566 car_copy:blue car:white
從結(jié)果可以的之,car與car_copy的內(nèi)存地址并不一致,但car.tire與car_copy.tire的內(nèi)存地址卻是一致的,說明“奔馳”車確實又造出了一輛,但卻公用同一幅輪胎(這種情形....哈哈哈),好吧,也就是只復制了tire的引用,這可以說是深拷貝的不徹底 (hashCode()的值可以當作是內(nèi)存地址來理解),那么要怎樣才能徹底,真正的深拷貝?
修改Car類中的clone方法:
@Override
protected Object clone() throws CloneNotSupportedException {
Car car = (Car)super.clone();
car.tire = (Tire)car.tire.clone();
return car;
}
輸出結(jié)果:
car:1223737555 car.tire:906199566 car_copy:542081238 car_copy.tire:1133736492 car_copy:blue car:white
這樣最終實現(xiàn)了,但這種方式用到項目中并不是很合適吧,每個需要深拷貝的類,都要實現(xiàn)Cloneable接口,并覆蓋其clone方法,遇到引用其他類時候更是需要修改clone方法,要是引用其他類,其他類再引用其他類呢?這不好吧......
方式二:通過序列化與反序列化實現(xiàn)(實現(xiàn)Serializable接口)
實體類:與第一種方式類似,換成實現(xiàn)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);
}
輸出結(jié)果:
car:2019524978 car.tire:855703640 car_copy:1407965019 car_copy.tire:545768040 car_copy:blue car:white
從結(jié)果集中可以看出是深拷貝是正確的,但是每個類還是需要實現(xiàn)Serializable,好像也不合適吧......
優(yōu)化一下深拷貝方法:將其換成泛型,這樣拷貝出來就不需要強轉(zhuǎn)了(好吧,其實也沒比上面的方法好到哪去...)
@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;
}
通過序列化與反序列化深拷貝還有更簡單的實現(xiàn)方式,就是需要導個包(拷貝的類也必須實現(xiàn)Serializable接口),當然,我已經(jīng)為你們準備好了 點擊->org.apache.commons.lang
深拷貝方法:就一行代碼...
public Object deepClone(Object obj){
return org.apache.commons.lang.SerializationUtils.clone((Serializable)obj);
}
好了,java的暫時就到這里了,當然對于這兩種方式并不是很滿意...
-------------------------------------------------
C#深拷貝 反射實現(xiàn)
下面方法是c#的深拷貝,純反射實現(xiàn),無需實現(xiàn)任何接口,哦對,需要實體類有個無參的構(gòu)造方法,簡單使用強大,微軟大法好啊......有需要用到的同學就拿去用吧,目前經(jīng)過一個幾百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); //創(chuàng)建引用對象
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深拷貝(實現(xiàn)上的對比分析)就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。
單元測試:
相關(guān)文章
DevExpress實現(xiàn)GridControl單元格編輯驗證的方法
這篇文章主要介紹了DevExpress實現(xiàn)GridControl單元格編輯驗證的方法,很實用的功能,需要的朋友可以參考下2014-08-08

