参考文章: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. GooglePlay - 文件上传限制的扩展

    前言 Google Play应用商店在上传限制100MB大小,超过该大小的应用必须将超过部分以扩展文件的形式进行上传处理. 总共可上传2个扩展文件,每个最大文件可为2GB,同时obb文件格式可自选. ...

  2. win10 uwp 截图 获取屏幕显示界面保存图片

    本文主要讲如何保存我们的屏幕显示的,保存为图片,也就是截图,截我们应用显示的. UWP有一个功能,可以截图,RenderTargetBitmap 我们首先写一个Grid,我们需要给他名字,我这里给他S ...

  3. 深入浅出:JavaScript作用域链

    1. 什么是作用域 任何程序设计语言都有作用域的概念,简单的说,作用域就是变量的作用范围. 2. 变量的分类和变量作用域的分类 在JavaScript中,变量分为全局变量和局部变量,与此相对应的,变量 ...

  4. (转)JVM性能调优之生成堆的dump文件

    转自:http://blog.csdn.net/lifuxiangcaohui/article/details/37992725 最近因项目存在内存泄漏,故进行大规模的JVM性能调优 , 现把经验做一 ...

  5. ASP.NET没有魔法——ASP.NET MVC使用Area开发一个管理模块

    之前的My Blog提供了列表的展示和文章显示功能,但是所有数据仍然只能通过数据库录入,为了完成最初的角色“作者”的用例,本章将介绍如何使用“Area”实现My Blog的管理功能. 根据功能分离代码 ...

  6. R学习笔记 第四篇:函数,分支和循环

    变量用于临时存储数据,而函数用于操作数据,实现代码的重复使用.在R中,函数只是另一种数据类型的变量,可以被分配,操作,甚至把函数作为参数传递给其他函数.分支控制和循环控制,和通用编程语言的风格很相似, ...

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

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

  8. 《Spark Python API 官方文档中文版》 之 pyspark.sql (一)

    摘要:在Spark开发中,由于需要用Python实现,发现API与Scala的略有不同,而Python API的中文资料相对很少.每次去查英文版API的说明相对比较慢,还是中文版比较容易get到所需, ...

  9. poj2689Prime Distance(大区间筛素数)

    Prime Distance Time Limit: 1000MS   Memory Limit: 65536K Total Submissions: 19635   Accepted: 5273 D ...

  10. 50 years, 50 colors

    50 years, 50 colors Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others) ...