参考文章:http://blog.csdn.net/XIAXIA__/article/details/41652057

解决问题:深拷贝、浅拷贝 和普通的对象赋值有什么区别?

对象复制

例如:Person p2 = p1;实质就是对象地址复制。把p1地址赋值给p2。此时二者同时指向一块堆内存,所以改变p1的属性值之后,p2所对应的属性值也会跟着变化。

例如有一个如下所示的Person类:

 package tudou.javabasic.clone;

 class Person {
private int age;
private String name;
private Address address; public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} public Person(int age, String name) {
this.age = age;
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "Person{" +
"age=" + age +
", name='" + name + '\'' +
'}';
}
}

Person

执行如下代码:

 public class CloneTest {
public static void main(String[] args) {
Person p1 = new Person(1, "first");
Person p2 = p1;//把p1的引用赋值给p2
System.out.println("p2.name before:"+p2.getName());
p1.setName("second");
System.out.println("p2.name after:"+p2.getName());
}
}

CloneTest

输出结果为:

p2.name before:first
p2.name after:second

如果在改变p1的值之后不想改变p2的值,应该如何处理呢?这时候需要用到拷贝,拷贝用到的函数为object的clone()方法

深拷贝和浅拷贝

clone()方法:

创建一个新对象,然后将当前对象的非静态字段复制到该新对象,
如果字段是值类型的,那么对该字段执行复制;
如果该字段是引用类型的话,则复制引用但不复制引用的对象。(这个称为浅拷贝)
原始对象及其副本引用同一个对象。
这个也就是说:如果使用clone()方法,对于值类型直接复制,对于引用类型 则还是采用复制 引用地址的方式。
代码如下:
 package tudou.javabasic.clone;

 /**
* Created by tudou on 2017-02-22.
* 浅拷贝
*/
public class ShallowCopyPerson implements Cloneable {
private int age;
private String name;
private Address address; public ShallowCopyPerson(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}
public Object clone() {
try {
return (ShallowCopyPerson)super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "ShallowCopyPerson{" +
"age=" + age +
", name='" + name + '\'' +
", address=" + address +
'}';
}
}

ShallowCopyPerson

ShallowCopyPerson 类扩展Cloneable接口,重点关注的方法是clone()方法,这里只是简单使用:

 public Object clone() {
try {
return (ShallowCopyPerson)super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
}

接下来使用ShallowCopyPerson 类,来观察下列代码的运行结果:

 //对象浅拷贝
private static void shallowCopyTest() {
Address address = new Address("Henan", "zhoukou");
ShallowCopyPerson shallowCopyPerson = new ShallowCopyPerson(
18,
"tudou",
address
);
ShallowCopyPerson personClone = (ShallowCopyPerson) shallowCopyPerson.clone();
System.out.println("personClone info before:" + personClone.toString());
System.out.println("shallowCopyPerson info before:" + shallowCopyPerson.toString());
//这里改变原 shallowCopyPerson的值
shallowCopyPerson.setName("new tudou");
shallowCopyPerson.setAge(19);
//改变address的地址值
address.setCity("fj");
address.setProvince("fz");
shallowCopyPerson.setAddress(address);
System.out.println("personClone info after:" + personClone.toString());
System.out.println("shallowCopyPerson info before:" + shallowCopyPerson.toString());
}

shallowCopyTest

结果如下:

 ersonClone info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}
shallowCopyPerson info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}
personClone info after:ShallowCopyPerson{age=18, name='tudou', address=Address{province='fz', city='fj'}}
shallowCopyPerson info before:ShallowCopyPerson{age=19, name='new tudou', address=Address{province='fz', city='fj'}}
从结果可以看到:age和name字段 在原对象shallowCopyPerson的属性改变之后 personclone并未改变。但是,address中的字段province和city均有改变!这种方式属于浅拷贝,即clone()方法是浅拷贝。
如何使得address中的字段值也不改变呢?就需要用到深拷贝。
 package tudou.javabasic.clone;

 /**
* Created by tudou on 2017-02-22.
* 深拷贝
*/
public class DeepCopyPerson implements Cloneable {
private int age;
private String name;
private Address address; public DeepCopyPerson(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}
public Object clone() {
try {
return (DeepCopyPerson)super.clone();
} catch (Exception e) {
e.printStackTrace();
return null;
}
} public Address getAddress() {
return address;
} public void setAddress(String province, String city) {
address = new Address(province,city);
address.setCity(city);
address.setProvince(province);
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} @Override
public String toString() {
return "ShallowCopyPerson{" +
"age=" + age +
", name='" + name + '\'' +
", address=" + address +
'}';
}
}

DeepCopyPerson

运行下面代码:

     //对象深拷贝
private static void deepCopyTest() {
Address address = new Address("Henan", "zhoukou");
DeepCopyPerson deepCopyPerson = new DeepCopyPerson(
18,
"tudou",
address
);
DeepCopyPerson personClone = (DeepCopyPerson) deepCopyPerson.clone();
System.out.println("personClone info before:" + personClone.toString());
//这里改变原 shallowCopyPerson的值
deepCopyPerson.setName("new tudou");
deepCopyPerson.setAge(19);
//改变address的地址值
// address.setCity("zhengzhou");
deepCopyPerson.setAddress("fj","fz");
System.out.println("personClone info after:" + personClone.toString());
}

deepCopyTest

结果如下:

personClone info before:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}
personClone info after:ShallowCopyPerson{age=18, name='tudou', address=Address{province='Henan', city='zhoukou'}}

可以看到这里值完全没有改变。这里实现的深拷贝只是简单的来实现效果,不做效率方面的考虑。

总结

对象赋值:把一个对象的地址复制给另一个对象,二者都指向堆栈中的地址。所以一个对象中的值变了,另一个也会变。

浅拷贝:对于基本类型,克隆对象和原对象相互独立,没有影响,对于引用类型,复制的还是地址值,所以一个改变了,另一个也会改变。

深拷贝:原对象和克隆对象相互独立,不受影响。


java对象拷贝和复制的更多相关文章

  1. JAVA 对象拷贝

    1.java里的clone分为:  A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象.  b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍.  Java中对 ...

  2. java对象实现深复制的方法

    p2 = (Person)org.apache.commons.lang3.ObjectUtils.cloneBean(p); Person p2 = new Person(); p2 = (Pers ...

  3. Java对象拷贝备忘

    列举 //cglib net.sf.cglib.beans.BeanCopier.create net.sf.cglib.beans.BeanCopier.copy //spring-beans or ...

  4. java 对象之间的复制

    package com.jy.demo.web; import java.util.Date; public class People { private String name;//姓名 priva ...

  5. Java 对象拷贝方式

    (1)BeanUtils.cloneBean()使用: http://www.cnblogs.com/fervour/archive/2009/12/18/1627868.html package c ...

  6. Java Object 对象拷贝

    Java Object 对象拷贝 @author ixenos JAVA 对象拷贝 Java里的clone分为:  1.浅拷贝:浅复制仅仅复制所考虑的对象,而不复制它所引用的对象,Object类里的c ...

  7. 通过与C++程序对比,彻底搞清楚JAVA的对象拷贝

    目录 一.背景 二.JAVA对象拷贝的实现 2.1 浅拷贝 2.2 深拷贝的实现方法一 2.3 深拷贝的实现方法二 2.3.1 C++拷贝构造函数 2.3.2 C++源码 2.3.3 JAVA通过拷贝 ...

  8. Java对象和集合的拷贝/克隆/复制

    昨天同事遇到了一个奇怪的问题,他需要将一个JavaBean拷贝一份,然后对新创建的Bean进行操作.但是他对新的Bean操作后,会影响旧的Bean的值.当听到这个问题的时候,我第一反应就是他的拷贝方法 ...

  9. Java提高篇——对象克隆(复制)

    假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short, ...

随机推荐

  1. ASP.NET没有魔法——ASP.NET MVC是如何运行的?它的生命周期是什么?

    前面的文章我们使用ASP.NET MVC创建了个博客应用,那么它是如何工作的呢?我们都知道ASP.NET的程序需要部署到IIS上才能够通过浏览器来访问,那么IIS与ASP.NET MVC程序之间又是如 ...

  2. MYSQL数据库引擎区别详解

    数据库引擎介绍 MySQL数据库引擎取决于MySQL在安装的时候是如何被编译的.要添加一个新的引擎,就必须重新编译MYSQL.在缺省情况下,MYSQL支持三个引擎:ISAM.MYISAM和HEAP.另 ...

  3. struts2使用模型传值

    用户bean package userBeans; public class User { private String username; public String getUsername() { ...

  4. (4.1)Spring MVC执行原理和基于Java的配置过程

    一.Spring MVC执行原理和基于Java配置的配置过程 (一)Spring MVC执行过程,大致为7步. 所有的请求都会经过Spring的一个单例的DispacherServlet. Dispa ...

  5. Python基础3切片,字符串的方法

    切片:截取字符串某一段字符,并不改变原字符串.结构:[起始位置:终止位置:步长]  但不包括终止位置.所谓:顾头不顾尾 索引:序列中每个元素都是有编号的,都是从0开始编号的.使用负数索引时,Pytho ...

  6. 在 JPA、Hibernate 和 Spring 中配置 Ehcache 缓存

    jpa, hibernate 和 spring 时配置 ehcache 二级缓存的步骤. 缓存配置 首先在 persistence.xml 配置文件中添加下面内容: <property name ...

  7. JAVA基础知识总结:二

    一.数据类型 1.常量 在程序运行的过程中,值不会发生改变的标识符 常量的分类:整数常量.小数常量.布尔值常量.字符常量.字符串常量.null常量 2.变量 表示的值可以发生改变 定义一个变量,需要在 ...

  8. Jquery DataTable AJAX跨域请求的解决方法及SSM框架下服务器端返回JSON格式数据的解决方法

    如题,用HBuilder开发APP,涉及到用AJAX跨域请求后台数据,刚接触,费了不少时间.幸得高手指点,得以解决. APP需要用TABLE来显示数据,因此采用了JQ 的DataTable.  在实现 ...

  9. JPA的一对多映射(双向)关联

    实体Customer:用户. 实体Order:订单. Customer和Order是一对多关系.那么在JPA中,如何表示一对多的双向关联呢? JPA使用@OneToMany和@ManyToOne来标识 ...

  10. tarjan求强连通分量+缩点+割点以及一些证明

    “tarjan陪伴强联通分量 生成树完成后思路才闪光 欧拉跑过的七桥古塘 让你 心驰神往”----<膜你抄>   自从听完这首歌,我就对tarjan开始心驰神往了,不过由于之前水平不足,一 ...