浅克隆:
首先在克隆前对象需要实现Cloneble接口,实现clone方法,否则调用不了Object的该方法
@Data
public class User implements Cloneable{
private String name;
private Integer age;
private User2 user2;
@Override
protected User clone() throws CloneNotSupportedException {
return (User)super.clone();
}
}
@Data
@AllArgsConstructor
@NoArgsConstructor
public class User2 {
private String name;
private Integer age;
}
@Test
public void t18() throws CloneNotSupportedException {
User user = new User();
user.setName("张三");
user.setAge(12);
User2 user2 = new User2("老王",18);
user.setUser2(user2);
User clone = user.clone();
System.out.println("user = " + user);
System.out.println("clone1 = " + clone);
user2.setName("李四");
user.setName("张三2");
System.out.println("------------------------");
System.out.println("user = " + user);
System.out.println("clone1 = " + clone);
clone.setName("张三3");
System.out.println("------------------------");
System.out.println("user = " + user);
System.out.println("clone1 = " + clone);
}
//user = User(name=张三, age=12, user2=User2(name=老王, age=18))
//clone1 = User(name=张三, age=12, user2=User2(name=老王, age=18))
------------------------
//user = User(name=张三2, age=12, user2=User2(name=李四, age=18))
//clone1 = User(name=张三, age=12, user2=User2(name=李四, age=18))
------------------------
//user = User(name=张三2, age=12, user2=User2(name=李四, age=18))
//clone1 = User(name=张三3, age=12, user2=User2(name=李四, age=18))
可以看出,当浅克隆时,会把对象的基本属性克隆过来,包含string,且修改克隆对象的属性时,不影响原对象的属性。但如果原对象的属性包含对象,克隆时则是克隆该对象的地址,若修改原对象或克隆对象其中一个,则会影响另一个对象。这个时候咱们引入深克隆
深克隆:
public static Object deepClone(Object obj) {
try (ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);) {
oo.writeObject(obj);//将对象从流中读出来
try (ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);) {
return oi.readObject();
}
} catch (IOException | ClassNotFoundException e) {
}
return null;
}
以上为深克隆的方法,复制一个新的对象出来,与原对象隔离,接下来咱们验证一下
先把待克隆对象实现Serializable接口
@Data
public class User implements Serializable{
private String name;
private Integer age;
private User2 user2;
}
接下来看个有趣的现象
@Test
public void t19() throws Exception {
User user = new User();
user.setName("张三");
user.setAge(12);
User clone = (User) deepClone(user);
System.out.println("user = " + user);
System.out.println("clone = " + clone);
}
//user = User(name=张三, age=12, user2=null)
//clone = User(name=张三, age=12, user2=null)
@Test
public void t19() throws Exception {
User user = new User();
user.setName("张三");
user.setAge(12);
User2 user2 = new User2("老王",18);
user.setUser2(user2);
User clone = (User) deepClone(user);
System.out.println("user = " + user);
System.out.println("clone = " + clone);
}
//user = User(name=张三, age=12, user2=User2(name=老王, age=18))
//clone = null
发现没,我们给user对象增加user2对象时,就克隆失败了。
此时是因为user2没有实现序列化接口,只需要把user2序列化一下,就ok了。
想告诉同学们,使用深克隆,一定需要记得把对象实现序列化。有了这个示例同学们应该记得更清楚了
最后,我们来看一下深克隆的方法是否如我们预期一样,直接上代码
@Test
public void t19() throws Exception {
User user = new User();
user.setName("张三");
user.setAge(12);
User2 user2 = new User2("老王",18);
user.setUser2(user2);
User clone = (User) deepClone(user);
System.out.println("user = " + user);
System.out.println("clone = " + clone);
System.out.println("------------------------------");
user2.setName("我是user2");
System.out.println("user = " + user);
System.out.println("clone = " + clone);
}
//user = User(name=张三, age=12, user2=User2(name=老王, age=18))
//clone = User(name=张三, age=12, user2=User2(name=老王, age=18))
//------------------------------
//user = User(name=张三, age=12, user2=User2(name=我是user2, age=18))
//clone = User(name=张三, age=12, user2=User2(name=老王, age=18))
可以看出,使用深克隆出来的对象,值与原对象一致,但与原对象里的user2不是使用同一个地址值。
最后:有不对的地方欢迎评论区交流,互相学习。