Java中的深复制与浅复制问题
2015-12-24 10:29
417 查看
在使用原型设计模式的时候,如果我们的原型类,往往都实现了clonable接口,并覆盖了clone方法;
重新生成一个新的对象;这个方法的底层是Object对象的clone方法,他是一个native方法,他直接操作的是JVM的内存;
即生成对象不通过对象所在类的构造函数;直接复制对应的内存中的东西;
在copy过程中,基本数据类型(及包装类也算),不变类型的数据;都是深度copy,什么意思呢?就是不将源对象中非基本类型成员变量的引用交给
clone的副本,使得副本中的非基本数据类型成员和源对象使用的是不同的对象;并且相互之间操作互不影响;
我们的做法是:
实现对象深复制的方法一:
这样就实现了源对象和copy对象直接使用互不干扰:
测试代码:
输出结果:user的account还是之前的23;而不是修改后的9999;
这里的核心是不让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"); }
完全没问题,建议使用第二种;
转发至微博
转发至微博
相关文章推荐
- 权限解决方案:Spring security3.0.…
- 权限解决方案:Spring Security3.0.…
- Java中的多线程
- SpringMVC:拦截器
- Struts2的邮件校验器正则表达式
- Spring中的工具类
- Spring给我的启发
- Spring中JdbcTemplate实现存储过程…
- Hibernate+SpringMVC整合:实战三,…
- Hibernate+SpringMVC整合:实战二,…
- Hibernate+SpringMVC整合实战一:搭…
- Spring定时器的使用
- struts总结完整整理版
- struts2总结:草稿
- Spring的总结
- struts2中默认拦截器栈中的拦截器…
- Java内存分析(转载)
- Struts2之Action处理多个方法总结
- Spring框架所有技术笔记总结
- JavaWeb基础回顾