Java中對(duì)象快速復(fù)制的幾種方式詳解
淺拷貝、深度復(fù)制、BeanUtils.copyProperties()
對(duì)象的克隆是指創(chuàng)建一個(gè)新的對(duì)象,且新的對(duì)象的狀態(tài)與原始對(duì)象的狀態(tài)相同。當(dāng)對(duì)克隆的新對(duì)象進(jìn)行修改時(shí),不會(huì)影響原始對(duì)象的狀態(tài)。
注釋:clone()是object類的protected 方法,只有類的對(duì)象自己可以克隆自己
因此,必須實(shí)現(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 也必須實(shí)現(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()
如果對(duì)象中的所有數(shù)據(jù)域都是數(shù)值或者基本類型,使用clone()即可滿足需求,如:
Person p = new Person(); Person p1 = p.clone();
這樣p和p1分別指向不同的對(duì)象。
二、深度拷貝
如果在對(duì)象中包含子對(duì)象的引用,拷貝的結(jié)果是使得兩個(gè)域引用同一個(gè)對(duì)象,默認(rèn)的拷貝是淺拷貝,沒有拷貝包含在對(duì)象中的內(nèi)部對(duì)象。
如果子對(duì)象是不可變的,如String,這沒有什么問題;如果對(duì)象是可變的,必須重新定義clone方法;
三、序列化可克隆(深拷貝)
/* * 為克隆使用序列化, * 直接將對(duì)象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對(duì)象是對(duì)現(xiàn)有對(duì)象的一個(gè)深拷貝 * 在此過程中,不必將對(duì)象寫出到文件,可以用ByteArrayOutPutStream將數(shù)據(jù)保存到字節(jié)數(shù)組中 * * 這個(gè)方法很靈巧,它通常會(huì)比顯示地構(gòu)建新對(duì)象并復(fù)制或克隆數(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 //將該對(duì)象序列化成流,因?yàn)閷懺诹骼锏氖菍?duì)象的一個(gè)拷貝,而原對(duì)象仍然存在于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()
三個(gè)測(cè)試類
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、針對(duì)對(duì)象中的一般字段可以實(shí)現(xiàn)復(fù)制對(duì)象和源對(duì)象各自修改互不影響(如person的name屬性)
2、針對(duì)里面的引用對(duì)象,沒有實(shí)現(xiàn)嵌套的拷貝(如Dog對(duì)象)
到此這篇關(guān)于Java中對(duì)象快速復(fù)制的幾種方式詳解的文章就介紹到這了,更多相關(guān)Java對(duì)象快速復(fù)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動(dòng)更新時(shí)間的一些問題
這篇文章主要介紹了關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫自動(dòng)更新時(shí)間的一些問題,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Mybatis傳單個(gè)參數(shù)和<if>標(biāo)簽同時(shí)使用的問題及解決方法
這篇文章主要介紹了Mybatis傳單個(gè)參數(shù)和<if>標(biāo)簽同時(shí)使用的問題及解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05IDEA工程運(yùn)行時(shí)總是報(bào)xx程序包不存在實(shí)際上包已導(dǎo)入(問題分析及解決方案)
這篇文章主要介紹了IDEA工程運(yùn)行時(shí),總是報(bào)xx程序包不存在,實(shí)際上包已導(dǎo)入,本文給大家分享問題分析及解決方案,通過實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-08-08淺談Java包裝類型Long的==操作引發(fā)的低級(jí)bug
本文主要介紹了淺談Java包裝類型Long的==操作引發(fā)的低級(jí)bug,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08