浅拷贝:被复制对象的所有值属性都与原来对象相同,而所有的对象引用属性仍然指向原来的对象。(只需实体类实现Cloneable重写clone方法return super.clone();即可)
深拷贝:在浅拷贝的基础上,所有引用其他对象的变量也进行了clone,并指向被复制过的新对象。
如果创建一个对象的新的副本,也就是说他们的初始状态完全一样,但以后可以改变各自的状态,而互不影响,就需要用到java中对象的复制,如原生的clone()方法。
克隆方式有很多,偶尔用一次的话,用哪种克隆方式问题都不大。一般性能要求稍高的应用场景,cglib和orika完全可以接受。
使用clone方式深拷贝
① 如果有一个非原生成员,如自定义类型的成员,那么就需要:
该成员实现Cloneable接口并重写Object的clone()方法(默认访问级别为protected),所以不要忘记提升为public可见。 同时,修改被复制类的clone()方法,增加成员的克隆逻辑。
② 如果被复制对象不是直接继承Object,中间还有其它继承层次,每一层super类都需要实现Cloneable接口并覆盖clone()方法。与对象成员不同,继承关系中的clone不需要被复制类的clone()做多余的工作(如果没有自定义类型的对象的话)。
一句话来说,如果实现完整的深拷贝,需要被复制对象的继承链、引用链上的每一个对象都实现克隆机制
public class JavaTester {
@Test
public void testDeepCopy() throws Exception {
Address address = new Address();
address.setType("Home");
address.setValue("北京");
Person p1 = new Person();
p1.setAge(31);
p1.setName("Peter");
p1.setAddress(address);
Person p2 = (Person) p1.clone();
System.out.println(p1 == p2);//false
p2.getAddress().setType("Office");
System.out.println("p1=" + p1);
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=北京))
//若不处理,则type都为Office
}
}
class Person implements Cloneable {
private String name;
private Integer age;
private Address address;
@Override
public Object clone() throws CloneNotSupportedException {
Object obj = super.clone();//第一句话就是克隆对象
Address a = ((Person) obj).getAddress();//获取address对象,该对象目前由两个Person对象共同持有
((Person) obj).setAddress((Address) a.clone());//修改克隆对象的address属性,该address是由上面的address对象克隆得到的。
return obj;//返回克隆对象
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
@Override
public String toString() {
return "Person{" +
"name='" + name + '\'' +
", age=" + age +
", address=" + address +
'}';
}
}
class Address implements Cloneable {
private String type;
private String value;
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getType() {
return type;
}
public void setType(String type) {
this.type = type;
}
public String getValue() {
return value;
}
public void setValue(String value) {
this.value = value;
}
@Override
public String toString() {
return "Address{" +
"type='" + type + '\'' +
", value='" + value + '\'' +
'}';
}
}
String,Integer等也是对象,但是他们是不可变类,所以值改变了也不会影响到对方。
@Test
public void testPlusInteger() throws Exception {
Integer integer = 1;
plusInteger(integer);
System.out.println(integer);
}
public void plusInteger(Integer integer){
integer = integer + 1;
}