Object对象有个clone()方法,实现了对象中各个属性的复制,但它的可见范围是protected的,所以实体类使用克隆的前提是:
① 实现Cloneable接口,这是一个标记接口,自身没有方法。
② 覆盖clone()方法,可见性提升为public。
浅拷贝:被复制对象的所有值属性都含有与原来对象的相同,而所有的对象引用属性仍然指向原来的对象
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象
也就是说,一个默认的clone()方法实现机制,仍然是赋值,如果一个呗赋值的属性都是基本类型,那么只需要实现当前类的cloneable机制就可以了,此为浅拷贝,如果被复制对象的属性包含其他实体类对象引用,那么这些实体类对象都需要实现cloneable接口并覆盖clone()方法
@Data
public class Person implements Cloneable {
private String name;
private Integer age;
@Override
public Person clone(){
try {
return (Person)super.clone();
} catch (CloneNotSupportedException e) {
return new Person();
}
}
}
测试结果
@Test
public void test1() {
Person p1 = new Person();
p1.setAge(31);
p1.setName("Peter");
Person p2 = p1.clone();
System.out.println(p1 == p2);//false
p2.setName("Jacky");
System.out.println("p1=" + p1);//p1=Person [name=Peter, age=31]
System.out.println("p2=" + p2);//p2=Person(name=Jacky, age=31)
}
修改person类,添加address属性
@Data
public class Address {
private String type;
private String value;
}
@Data
public class Person implements Cloneable {
private String name;
private Integer age;
private Address address;
@Override
public Person clone(){
try {
return (Person)super.clone();
} catch (CloneNotSupportedException e) {
return new Person();
}
}
}
测试结果
@Test
public void testShallowCopy(){
Address address=new Address();
address.setType("Home");
address.setValue("北京");
Person p1=new Person();
p1.setAge(31);
p1.setName("Peter");
p1.setAddress(address);
Person p2=p1.clone();
System.out.println(p1==p2);//false
p2.getAddress().setType("Office");
System.out.println("p1="+p1);//p1=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
System.out.println("p2="+p2);//p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
}
这里我们可以发现只修改p2的address,可是结果显示p1和p2的address都进行了修改
这里如果要保证只修改p2的address,需要address实体类也实现Cloneable接口和重写clone方法,并且Person的clone()需要显式地clone其引用成员
@Data
public class Address implements Cloneable{
private String type;
private String value;
@Override
public Address clone(){
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
return new Address();
}
}
}
@Data
public class Person implements Cloneable {
private String name;
private Integer age;
private Address address;
@Override
public Person clone(){
try {
Person person = (Person) super.clone();
Address address = person.getAddress();
person.setAddress(address.clone());
return person;
} catch (CloneNotSupportedException e) {
return new Person();
}
}
}
重新跑前面的测试用例:
false
p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
为了方便测试,节省篇幅,封装一个工程类
public class PersonFactory{
public static Person newPrototypeInstance(){
Address address = new Address();
address.setType("Home");
address.setValue("北京");
Person p1 = new Person();
p1.setAddress(address);
p1.setAge(31);
p1.setName("Peter");
return p1;
}
}
maven依赖
<dependency>
<groupId>net.sf.dozergroupId>
<artifactId>dozerartifactId>
<version>5.5.1version>
dependency>
测试用例:
@Test
public void testDozer() {
Person p1= PersonFactory.newPrototypeInstance();
Mapper mapper = new DozerBeanMapper();
Person p2 = mapper.map(p1, Person.class);
p2.getAddress().setType("Office");
System.out.println("p1=" + p1);
System.out.println("p2=" + p2);
}
@Data
public class Person{
private String name;
private Integer age;
private Address address;
}
@Data
public class Address {
private String type;
private String value;
}
输出结果:
p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
maven依赖
<dependency>
<groupId>commons-beanutilsgroupId>
<artifactId>commons-beanutilsartifactId>
<version>1.9.3version>
dependency>
测试用例:
@Test
public void testCommonsBeanUtils(){
Person p1=PersonFactory.newPrototypeInstance();
try {
Person p2=(Person) BeanUtils.cloneBean(p1);
//p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
System.out.println("p1=" + p1);
p2.getAddress().setType("Office");
//p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))
System.out.println("p2=" + p2);
} catch (Exception e) {
e.printStackTrace();
}
}
maven依赖
<dependency>
<groupId>ma.glasnost.orikagroupId>
<artifactId>orika-coreartifactId>
<version>1.5.0version>
dependency>
测试用例
@Test
public void testOrika() {
MapperFactory mapperFactory = new DefaultMapperFactory.Builder().build();
mapperFactory.classMap(Person.class, Person.class)
.byDefault()
.register();
MapperFacade mapper = mapperFactory.getMapperFacade();
Person p1=PersonFactory.newPrototypeInstance();
Person p2 = mapper.map(p1, Person.class);
System.out.println("p1=" + p1);
p2.getAddress().setType("Office");
System.out.println("p2=" + p2);
}
p1=Person(name=Peter, age=31, address=Address(type=Home, value=北京))
p2=Person(name=Peter, age=31, address=Address(type=Office, value=北京))