Java中對(duì)象快速?gòu)?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類(lèi)的protected 方法,只有類(lèi)的對(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ù)值或者基本類(lèi)型,使用clone()即可滿足需求,如:
Person p = new Person(); Person p1 = p.clone();
這樣p和p1分別指向不同的對(duì)象。
二、深度拷貝
如果在對(duì)象中包含子對(duì)象的引用,拷貝的結(jié)果是使得兩個(gè)域引用同一個(gè)對(duì)象,默認(rèn)的拷貝是淺拷貝,沒(méi)有拷貝包含在對(duì)象中的內(nèi)部對(duì)象。
如果子對(duì)象是不可變的,如String,這沒(méi)有什么問(wèn)題;如果對(duì)象是可變的,必須重新定義clone方法;
三、序列化可克?。ㄉ羁截悾?/h2>
/*
* 為克隆使用序列化,
* 直接將對(duì)象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對(duì)象是對(duì)現(xiàn)有對(duì)象的一個(gè)深拷貝
* 在此過(guò)程中,不必將對(duì)象寫(xiě)出到文件,可以用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)閷?xiě)在流里的是對(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
+ "]";
}
}
/* * 為克隆使用序列化, * 直接將對(duì)象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對(duì)象是對(duì)現(xiàn)有對(duì)象的一個(gè)深拷貝 * 在此過(guò)程中,不必將對(duì)象寫(xiě)出到文件,可以用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)閷?xiě)在流里的是對(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è)試類(lèi)
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ì)象,沒(méi)有實(shí)現(xiàn)嵌套的拷貝(如Dog對(duì)象)
到此這篇關(guān)于Java中對(duì)象快速?gòu)?fù)制的幾種方式詳解的文章就介紹到這了,更多相關(guān)Java對(duì)象快速?gòu)?fù)制內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫(kù)自動(dòng)更新時(shí)間的一些問(wèn)題
這篇文章主要介紹了關(guān)于Mybatis-Plus字段策略與數(shù)據(jù)庫(kù)自動(dòng)更新時(shí)間的一些問(wèn)題,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧2020-10-10Mybatis傳單個(gè)參數(shù)和<if>標(biāo)簽同時(shí)使用的問(wèn)題及解決方法
這篇文章主要介紹了Mybatis傳單個(gè)參數(shù)和<if>標(biāo)簽同時(shí)使用的問(wèn)題及解決方法,非常不錯(cuò),具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2018-05-05IDEA工程運(yùn)行時(shí)總是報(bào)xx程序包不存在實(shí)際上包已導(dǎo)入(問(wèn)題分析及解決方案)
這篇文章主要介紹了IDEA工程運(yùn)行時(shí),總是報(bào)xx程序包不存在,實(shí)際上包已導(dǎo)入,本文給大家分享問(wèn)題分析及解決方案,通過(guò)實(shí)例代碼給大家介紹的非常詳細(xì),需要的朋友可以參考下2020-08-08淺談Java包裝類(lèi)型Long的==操作引發(fā)的低級(jí)bug
本文主要介紹了淺談Java包裝類(lèi)型Long的==操作引發(fā)的低級(jí)bug,文中通過(guò)示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08解析Jmeter脫離Jenkins后Ant集成郵件通知問(wèn)題
今天來(lái)講下本地的ant構(gòu)建并發(fā)送郵件。配置下來(lái)挺順利也挺簡(jiǎn)單的,對(duì)Jmeter脫離Jenkins后Ant集成郵件通知問(wèn)題感興趣的朋友跟隨小編一起看看吧2021-12-12