Java中對象快速復制的幾種方式詳解
淺拷貝、深度復制、BeanUtils.copyProperties()
對象的克隆是指創(chuàng)建一個新的對象,且新的對象的狀態(tài)與原始對象的狀態(tài)相同。當對克隆的新對象進行修改時,不會影響原始對象的狀態(tài)。
注釋:clone()是object類的protected 方法,只有類的對象自己可以克隆自己
因此,必須實現(xiàn)cloneable接口才可以使用obj.clone()方法,典型的方式,如下
//淺拷貝 class CloneClass implements Cloneable{ public int a; public Object clone(){ CloneClass o = null; try{ o = (CloneClass)super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return o; } }
//深度拷貝 class CloneClass implements Cloneable{ public int a; public Class1 t; public CloneClass (int a,Class1 t) { this.a = a; this.t = t; } public Object clone(){ CloneClass o = null; try{ o = (CloneClass)super.clone(); o.test = (Class1)t.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return o; } } //Class1 也必須實現(xiàn)Cloneable接口 class Class1 implements Cloneable{ public Object clone(){ Class1 o = null; try{ o = (Class1 )super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return o; } }
一、淺拷貝clone()
如果對象中的所有數(shù)據(jù)域都是數(shù)值或者基本類型,使用clone()即可滿足需求,如:
Person p = new Person(); Person p1 = p.clone();
這樣p和p1分別指向不同的對象。
二、深度拷貝
如果在對象中包含子對象的引用,拷貝的結(jié)果是使得兩個域引用同一個對象,默認的拷貝是淺拷貝,沒有拷貝包含在對象中的內(nèi)部對象。
如果子對象是不可變的,如String,這沒有什么問題;如果對象是可變的,必須重新定義clone方法;
三、序列化可克?。ㄉ羁截悾?/h2>
/*
* 為克隆使用序列化,
* 直接將對象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對象是對現(xiàn)有對象的一個深拷貝
* 在此過程中,不必將對象寫出到文件,可以用ByteArrayOutPutStream將數(shù)據(jù)保存到字節(jié)數(shù)組中
*
* 這個方法很靈巧,它通常會比顯示地構(gòu)建新對象并復制或克隆數(shù)據(jù)域的克隆方法慢得多
*/
public class SerialCloneTest
{
public static void main(String[] args)
{
Employee harry = new Employee("Harry Hacker", 35000);
// clone harry
Employee harry2 = (Employee) harry.clone();
System.out.println(harry==harry2);
System.out.println(harry);
System.out.println(harry2);
}
}
/**
A class whose clone method uses serialization.
*/
class SerialCloneable implements Cloneable, Serializable
{
private static final long serialVersionUID = 1L;
//深拷貝
public Object clone()
{
try
{
// save the object to a byte array
//將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在于JVM里面
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(this);
out.close();
// read a clone of the object from the byte array
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream in = new ObjectInputStream(bin);
Object ret = in.readObject();
in.close();
return ret;
}
catch (Exception e)
{
return null;
}
}
}
/**
The familiar Employee class, redefined to extend the
SerialCloneable class.
*/
class Employee extends SerialCloneable
{
private static final long serialVersionUID = 1L;
private String name;
private double salary;
public Employee(String n, double s)
{
name = n;
salary = s;
}
public String getName()
{
return name;
}
public double getSalary()
{
return salary;
}
public String toString()
{
return getClass().getName()
+ "[name=" + name
+ ",salary=" + salary
+ "]";
}
}
/* * 為克隆使用序列化, * 直接將對象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對象是對現(xiàn)有對象的一個深拷貝 * 在此過程中,不必將對象寫出到文件,可以用ByteArrayOutPutStream將數(shù)據(jù)保存到字節(jié)數(shù)組中 * * 這個方法很靈巧,它通常會比顯示地構(gòu)建新對象并復制或克隆數(shù)據(jù)域的克隆方法慢得多 */ public class SerialCloneTest { public static void main(String[] args) { Employee harry = new Employee("Harry Hacker", 35000); // clone harry Employee harry2 = (Employee) harry.clone(); System.out.println(harry==harry2); System.out.println(harry); System.out.println(harry2); } } /** A class whose clone method uses serialization. */ class SerialCloneable implements Cloneable, Serializable { private static final long serialVersionUID = 1L; //深拷貝 public Object clone() { try { // save the object to a byte array //將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在于JVM里面 ByteArrayOutputStream bout = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(bout); out.writeObject(this); out.close(); // read a clone of the object from the byte array ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray()); ObjectInputStream in = new ObjectInputStream(bin); Object ret = in.readObject(); in.close(); return ret; } catch (Exception e) { return null; } } } /** The familiar Employee class, redefined to extend the SerialCloneable class. */ class Employee extends SerialCloneable { private static final long serialVersionUID = 1L; private String name; private double salary; public Employee(String n, double s) { name = n; salary = s; } public String getName() { return name; } public double getSalary() { return salary; } public String toString() { return getClass().getName() + "[name=" + name + ",salary=" + salary + "]"; } }
四、BeanUtils.copyProperties()
三個測試類
public class Person { private String name; private String sex; private int age; private Date birthday; private Dog dog; public Dog getDog() { return dog; } public void setDog(Dog dog) { this.dog = dog; } private Double high; public String getName() { return name; } public Double getHigh() { return high; } public void setHigh(Double high) { this.high = high; } public void setName(String name) { this.name = name; } public String getSex() { return sex; } public void setSex(String sex) { this.sex = sex; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public Date getBirthday() { return birthday; } public void setBirthday(Date birthday) { this.birthday = birthday; } @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", sex='" + sex + '\'' + ", age=" + age + ", birthday=" + birthday + ", dog=" + dog + ", high=" + high + '}'; } }
public class Dog { public String dogName; public String getDogName() { return dogName; } public void setDogName(String dogName) { this.dogName = dogName; } @Override public String toString() { return "Dog{" + "dogName='" + dogName + '\'' + '}'; } }
import org.apache.commons.beanutils.BeanUtils; import java.lang.reflect.InvocationTargetException; import java.util.Date; public class BeanUtilTest { public static void main(String[] args) { Person per = new Person(); Person per1 = new Person(); per.setName("zhangsan"); per.setSex("男"); per.setAge(20); per.setBirthday(new Date()); Dog dog = new Dog(); dog.setDogName("1111111111111111"); per.setDog(dog); try { BeanUtils.copyProperties(per1, per); Dog dog1 = per.getDog(); dog1.setDogName("2222222222222222"); per.setName("666666666666"); } catch (IllegalAccessException e) { e.printStackTrace(); } catch (InvocationTargetException e) { e.printStackTrace(); } System.out.println(per.toString()); System.out.println(per1.toString()); } }
輸出:
Person{name='666666666666', sex='男', age=20, birthday=Wed Jul 25 18:21:29 CST 2018, dog=Dog{dogName='2222222222222222'}, high=null}
Person{name='zhangsan', sex='男', age=20, birthday=Wed Jul 25 18:21:29 CST 2018, dog=Dog{dogName='2222222222222222'}, high=0.0}
總結(jié):
1、針對對象中的一般字段可以實現(xiàn)復制對象和源對象各自修改互不影響(如person的name屬性)
2、針對里面的引用對象,沒有實現(xiàn)嵌套的拷貝(如Dog對象)
到此這篇關于Java中對象快速復制的幾種方式詳解的文章就介紹到這了,更多相關Java對象快速復制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關文章希望大家以后多多支持腳本之家!
相關文章
關于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題
這篇文章主要介紹了關于Mybatis-Plus字段策略與數(shù)據(jù)庫自動更新時間的一些問題,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧2020-10-10Mybatis傳單個參數(shù)和<if>標簽同時使用的問題及解決方法
這篇文章主要介紹了Mybatis傳單個參數(shù)和<if>標簽同時使用的問題及解決方法,非常不錯,具有一定的參考借鑒價值,需要的朋友可以參考下2018-05-05IDEA工程運行時總是報xx程序包不存在實際上包已導入(問題分析及解決方案)
這篇文章主要介紹了IDEA工程運行時,總是報xx程序包不存在,實際上包已導入,本文給大家分享問題分析及解決方案,通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下2020-08-08淺談Java包裝類型Long的==操作引發(fā)的低級bug
本文主要介紹了淺談Java包裝類型Long的==操作引發(fā)的低級bug,文中通過示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下2021-08-08