Java中的深复制与浅复制问题

在使用原型设计模式的时候,如果我们的原型类,往往都实现了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");
}

完全没问题,建议使用第二种;
<script type="text/javascript" id="wumiiRelatedItems"> </script>
 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值