Java中對象快速復(fù)制的幾種方式詳解
淺拷貝、深度復(fù)制、BeanUtils.copyProperties()
對象的克隆是指創(chuàng)建一個新的對象,且新的對象的狀態(tài)與原始對象的狀態(tài)相同。當(dāng)對克隆的新對象進行修改時,不會影響原始對象的狀態(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é)果是使得兩個域引用同一個對象,默認(rèn)的拷貝是淺拷貝,沒有拷貝包含在對象中的內(nèi)部對象。
如果子對象是不可變的,如String,這沒有什么問題;如果對象是可變的,必須重新定義clone方法;
三、序列化可克?。ㄉ羁截悾?/h2>
/*
* 為克隆使用序列化,
* 直接將對象序列化到輸出流中,然后將其讀回,這樣產(chǎn)生的新對象是對現(xiàn)有對象的一個深拷貝
* 在此過程中,不必將對象寫出到文件,可以用ByteArrayOutPutStream將數(shù)據(jù)保存到字節(jié)數(shù)組中
*
* 這個方法很靈巧,它通常會比顯示地構(gòu)建新對象并復(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
//將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在于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)建新對象并復(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
//將該對象序列化成流,因為寫在流里的是對象的一個拷貝,而原對象仍然存在于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)復(fù)制對象和源對象各自修改互不影響(如person的name屬性)
2、針對里面的引用對象,沒有實現(xiàn)嵌套的拷貝(如Dog對象)
到此這篇關(guān)于Java中對象快速復(fù)制的幾種方式詳解的文章就介紹到這了,更多相關(guān)Java對象快速復(fù)制內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
MyBatis處理CLOB/BLOB類型數(shù)據(jù)以及解決讀取問題
這篇文章主要介紹了MyBatis處理CLOB/BLOB類型數(shù)據(jù)以及解決讀取問題,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教2025-04-04
Java仿文庫的基本方法(openoffice+swftools+flexPaper)
這篇文章主要為大家詳細介紹了Java仿文庫的基本方法,具有一定的參考價值,感興趣的小伙伴們可以參考一下2017-02-02
在Java中使用ModelMapper簡化Shapefile屬性轉(zhuǎn)JavaBean實戰(zhàn)過程
本文介紹了在Java中使用ModelMapper庫簡化Shapefile屬性轉(zhuǎn)JavaBean的過程,對比了原始的set方法和構(gòu)造方法,展示了如何使用ModelMapper進行動態(tài)屬性映射,從而減少手動編寫轉(zhuǎn)換代碼的工作量,通過示例代碼,展示了如何使用GeoTools讀取Shapefile屬性并將其轉(zhuǎn)換為JavaBean對象2025-02-02
防止SpringMVC攔截器攔截js等靜態(tài)資源文件的解決方法
本篇文章主要介紹了防止SpringMVC攔截器攔截js等靜態(tài)資源文件的解決方法,具有一定的參考價值,有興趣的同學(xué)可以了解一下2017-09-09

