在使用原型设计模式的时候,如果我们的原型类,往往都实现了clonable接口,并覆盖了clone方法;
重新生成一个新的对象;这个方法的底层是Object对象的clone方法,他是一个native方法,他直接操作的是JVM的内存;
即生成对象不通过对象所在类的构造函数;直接复制对应的内存中的东西;
在copy过程中,基本数据类型(及包装类也算),不变类型的数据;都是深度copy,什么意思呢?就是不将源对象中非基本类型成员变量的引用交给
clone的副本,使得副本中的非基本数据类型成员和源对象使用的是不同的对象;并且相互之间操作互不影响;
我们的做法是:
实现对象深复制的方法一:
package com.lrq.copy;
public class User implements Cloneable{
public User() {
System.out.println("user");
}
private String username;
private int age;
private Integer length;
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Integer getLength() {
return length;
}
public void setLength(Integer length) {
this.length = length;
}
private Account account;
public Account getAccount() {
return account;
}
public void setAccount(Account account) {
this.account = account;
}
//必须要覆盖, 为如果不覆盖的话,父类的protected方法,到了子类就是private的了;对于外部不可用;
@Override
protected Object clone() throws CloneNotSupportedException {
//copy一个新的东西出来;
User clone = (User) super.clone();
//将非基本数据类型的数据也copy一份过来;注意必须要copy.
clone.setAccount((Account) this.getAccount().clone());
return clone;
}
}
package com.lrq.copy;
public class Account implements Cloneable{
public Account() {
System.out.println("account");
}
private String id;
private Float money;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public Float getMoney() {
return money;
}
public void setMoney(Float money) {
this.money = money;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
这样就实现了源对象和copy对象直接使用互不干扰:
测试代码:
@Test
public void test() throws Exception{
User user=new User();
Account account=new Account();
account.setId("ssss");
account.setMoney(23f);
user.setAccount(account);
user.setAge(20);
user.setLength(111);
User clone = (User) user.clone();
Account account2 = clone.getAccount();
System.out.println(account2.getMoney()+"--clone");
clone.getAccount().setMoney(9999f);
System.out.println(user.getAccount().getMoney());
}
输出结果:user的account还是之前的23;而不是修改后的9999;
这里的核心是不让clone对象获取到源对象中,非基本数据类型的成员变量的引用;
处理方式二:
package com.lrq.copy;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Person implements Serializable{
private static final long serialVersionUID = -8954779984792810004L;
private String id;
private String name;
private Card card;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Card getCard() {
return card;
}
public void setCard(Card card) {
this.card = card;
}
@Override
protected Object clone(){
ByteArrayOutputStream bos=new ByteArrayOutputStream();
try {
ObjectOutputStream objectOut=new ObjectOutputStream(bos);
objectOut.writeObject(this);
ByteArrayInputStream bis=new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream objectIn=new ObjectInputStream(bis);
return objectIn.readObject();
} catch (IOException e) {
e.printStackTrace();
throw new RuntimeException(e);
} catch (ClassNotFoundException e) {
e.printStackTrace();
throw new RuntimeException(e);
}
}
}
package com.lrq.copy;
import java.io.Serializable;
public class Card implements Serializable{
private static final long serialVersionUID = -6258840793361311762L;
private String id;
private String no;
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
public String getNo() {
return no;
}
public void setNo(String no) {
this.no = no;
}
}
测试代 :
@Test
public void test2(){
Person person=new Person();
Card card=new Card();
card.setId("ooo");
card.setNo("xxx");
person.setCard(card);
person.setId("afdaf");
person.setName("dfadffaf");
Person clone = (Person) person.clone();
clone.getCard().setNo("aaaaaaaaaaaa");
System.out.println(clone.getCard().getNo()+"clone");
System.out.println(person.getCard().getNo()+"perosn");
}
完全没问题,建议使用第二种;
转发至微博
转发至微博