Java中对象快速复制的几种方式详解
作者:程序猿渣渣帅
浅拷贝、深度复制、BeanUtils.copyProperties()
对象的克隆是指创建一个新的对象,且新的对象的状态与原始对象的状态相同。当对克隆的新对象进行修改时,不会影响原始对象的状态。
注释:clone()是object类的protected 方法,只有类的对象自己可以克隆自己
因此,必须实现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 也必须实现Cloneable接口 class Class1 implements Cloneable{ public Object clone(){ Class1 o = null; try{ o = (Class1 )super.clone(); }catch(CloneNotSupportedException e){ e.printStackTrace(); } return o; } }
一、浅拷贝clone()
如果对象中的所有数据域都是数值或者基本类型,使用clone()即可满足需求,如:
Person p = new Person(); Person p1 = p.clone();
这样p和p1分别指向不同的对象。
二、深度拷贝
如果在对象中包含子对象的引用,拷贝的结果是使得两个域引用同一个对象,默认的拷贝是浅拷贝,没有拷贝包含在对象中的内部对象。
如果子对象是不可变的,如String,这没有什么问题;如果对象是可变的,必须重新定义clone方法;
三、序列化可克隆(深拷贝)
/* * 为克隆使用序列化, * 直接将对象序列化到输出流中,然后将其读回,这样产生的新对象是对现有对象的一个深拷贝 * 在此过程中,不必将对象写出到文件,可以用ByteArrayOutPutStream将数据保存到字节数组中 * * 这个方法很灵巧,它通常会比显示地构建新对象并复制或克隆数据域的克隆方法慢得多 */ 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}
总结:
1、针对对象中的一般字段可以实现复制对象和源对象各自修改互不影响(如person的name属性)
2、针对里面的引用对象,没有实现嵌套的拷贝(如Dog对象)
到此这篇关于Java中对象快速复制的几种方式详解的文章就介绍到这了,更多相关Java对象快速复制内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!