知识点:java中关于Object.clone方法,对象的深拷贝与浅拷贝

引言

在一些场景中,我们需要获取到一个对象的拷贝,这时候就可以用java中的Object.clone方法进行对象的复制,得到一个一模一样的新对象。(使用new再次创建一个相同的对象也是可以的,有些区别),当对象中含有可变的引用类型属性时,在复制得到的新对象对该引用类型属性内容进行修改,原始对象相应的属性内容也会发生变化,这就是"浅拷贝"的现象。反之原始对象相应的引用类型属性不发生变化,是 "深拷贝"。

浅拷贝

先看一个浅拷贝的demo实例

1.创建一个Person类

public class Person implements Cloneable{
private String name;
private int age;
private Address address; //构造方法
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
} @Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
} public String display(){
return "Person[name="+name+",age="+age+",address"+address+"]";
} public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public int getAge() {
return age;
} public void setAge(int age) {
this.age = age;
} public Address getAddress() {
return address;
} public void setAddress(Address address) {
this.address = address;
}
} 由于clone()方法是protected修饰的,因此需要实现Cloneable接口才能调用,同时需要覆写clone()方法才能调用。 2.创建一个Address类
public class Address {
private String province;//省份
private String city;//所在城市 //构造方法
public Address(String province, String city) {
this.province = province;
this.city = city;
} public String getProvince() {
return province;
} public void setProvince(String province) {
this.province = province;
} public String getCity() {
return city;
} public void setCity(String city) {
this.city = city;
} @Override
public String toString() {
return "Address[province="+province+",city="+city+"]";
}
} 3.浅拷贝测试
public class Test {
public static void main(String[] args) throws CloneNotSupportedException {
Person person=new Person("张三",20,new Address("安徽","合肥")); Person clonePerson=(Person) person.clone(); System.out.println(person);
System.out.println(clonePerson); System.out.println(person.display());
System.out.println(clonePerson.display()); clonePerson.setName("李四");
clonePerson.setAge(22);
Address address=clonePerson.getAddress();
address.setProvince("江苏"); System.out.println(person.display());
System.out.println(clonePerson.display());
}
} 4.代码运行结果:

第1、2句输出说明了原对象与新对象是两个不同的对象。

第3、4句可以看到拷贝出来的新对象与原对象内容一致

但是,接着将新对象里面的信息进行了修改,然后输出发现原对象里面的部分信息也跟着变了。仔细观察发现原对象跟着变化的只是Address部分,这就跟clone本身的浅拷贝有关系了。

浅拷贝  :创建一个新对象,然后将当前对象的非静态字段复制到该对象,如果字段类型是值类型(基本类型)的,那么对该字段进行复制;如果字段是引用类型的,则只复制该字段的引用而不复制引用指向的对象。此时新对象里面的引用类型字段相当于是原始对象里面引用类型字段的一个副本,原始对象与新对象里面的引用字段指向的是同一个对象。

简而言之:类实现默认的Object.clone()方法,拷贝对象时,对于引用类型的成员变量(属性)拷贝只是拷贝“值”即地址(引用),没有在堆中开辟新的内存空间。

因此,修改clonePerson里面的address内容时,原person里面的address内容会跟着改变。

深拷贝” :类重写clone()方法,对于引用类型成员变量,重新在堆中开辟新的内存空间,简单地说,将引用类型的属性内容也拷贝一份新的。

如果我们想实现深拷贝,有两种方法,第一种是给需要拷贝的引用类型也实现Cloneable接口并覆写clone方法;第二种则是利用序列化。

具体代码演示可参考:https://www.cnblogs.com/nickhan/p/8569329.html

接下来补充一下,涉及到的知识点

复制对象和复制引用的区别

 

String的特殊性性

其实string类型也是引用类型,不是基本类型,那上面的例子中,修改拷贝对象person的name后,原对象的name值并没有改变,这是什么原因呢?

答:其实string也是引用类型,在深复制时并没有进行单独复制,仅仅复制了引用,String并没有实现cloneable接口,之所以修改新克隆对象的name值后,

原对象的name对应的值没有改变,是因为String在内存中是不可以改变的对象,我们在修改新对象(或者原对象)的name值时,会新分配一块内存保存新修改的name值,新对象的引用(或者原对象的引用)会指向新的内存空间,原来的String 还会存在它的引用name,如果String的值不存在引用,会被回收,也因为原来的String值存在引用name,所以不会被回收,这样,可以解释上面的demo中,name虽然是String引用类型,但是修改name的值,并没有改变原对象的name值。

我们也可以在idea中,用debugger调试验证一下

执行上面代码前三行代码,debugger

上面的箭头可以看出person和clonePerson的name是指向同一对象的引用(@468)

修改其中的对象的name值debugger看看

当我们执行clonePerson.setName("李四");修改新克隆对象的name值以后,则:

新克隆对象的name引用对应的值,发生了改变,原对象的引用对应的内存值没有发生变化

克隆一个对象与new一个对象的区别

(1)java中clone和new都可以创建一个新的对象

(2)clone()不会调用构造方法,而new一个对象会调用类的构造方法

(3)clone()能快速创建一个已有对象的副本,即创建对象并且将已有对象中所有属性值克隆;new只能在JVM中申请一个空的内存区域,对象的属性值要通过构造方法赋值。

谈谈java中对象的深拷贝与浅拷贝的更多相关文章

  1. PHP中对象的深拷贝与浅拷贝

    先说一下深拷贝和浅拷贝通俗理解 深拷贝:赋值时值完全复制,完全的copy,对其中一个作出改变,不会影响另一个 浅拷贝:赋值时,引用赋值,相当于取了一个别名.对其中一个修改,会影响另一个 PHP中, = ...

  2. 探究JS中对象的深拷贝和浅拷贝

    深拷贝和浅拷贝的区别 在讲深拷贝和浅拷贝的区别之前,回想一下我们平时拷贝一个对象时是怎么操作的?是不是像这样? var testObj1 = {a: 1, b:2}, testObj2=testObj ...

  3. java 复制Map对象(深拷贝与浅拷贝)

      java 复制Map对象(深拷贝与浅拷贝) CreationTime--2018年6月4日10点00分 Author:Marydon 1.深拷贝与浅拷贝 浅拷贝:只复制对象的引用,两个引用仍然指向 ...

  4. 谈谈JAVA中的安全发布

    谈谈JAVA中的安全发布 昨天看到一篇文章阐述技术类资料的"等级",看完之后很有共鸣.再加上最近在工作中越发觉得线程安全性的重要性和难以捉摸,又掏出了<Java并发编程实战& ...

  5. 谈谈java中静态变量与静态方法在有继承关系的两个类中调用

    谈谈java中静态变量与静态方法在有继承关系的两个类中调用 学习的中如果遇到不明白或者不清楚的的时候,就是自己做些测试,自己去试试,这次我就做一个关于静态变量和静态方法在有继承关系的两个类中的问题测试 ...

  6. Java中对象的深复制和浅复制详解

    1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引用仍然指向原来的对象.换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象. ⑵ ...

  7. java 中对象比较大小

    java 中对象比较大小 java 中对象比较大小有两种方法 1:实现Comparable 接口 的 public int compareTo(T o) 方法: 2:实现Comparator 接口 的 ...

  8. Java中对象、对象引用、堆、栈、值传递以及引用传递的详解

    Java中对象.对象引用.堆.栈.值传递以及引用传递的详解 1.对象和对象引用的差别: (1).对象: 万物皆对象.对象是类的实例. 在Java中new是用来在堆上创建对象用的. 一个对象能够被多个引 ...

  9. 谈谈java中成员变量与成员方法继承的问题

    谈谈java中成员变量与成员方法继承的问题 关于成员变量和成员方法的的继承问题,我也可以做一个小测试,来看看结果. 首先我们先创建一个父类:

随机推荐

  1. LeetCode - Employees Earning More Than Their Managers

    Description: The Employee table holds all employees including their managers. Every employee has an ...

  2. Excel 2010 如何在Excel的单元格中加入下拉选项

    http://jingyan.baidu.com/article/03b2f78c4ba8a05ea237ae95.html 第一步:打开excel文档,选中需加入下拉选项的单元格.   第二步:点击 ...

  3. serializeArray()与serialize()的区别

    serialize()序列化表单元素为字符串,用于 Ajax 请求. serializeArray()序列化表单元素为JSON数据. <script type="text/javasc ...

  4. CodeForces - 459E Pashmak and Graph[贪心优化dp]

    E. Pashmak and Graph time limit per test 1 second memory limit per test 256 megabytes input standard ...

  5. pano2vr制作360全景图

    1.下载pano2vr中文破解版2.制作360全景选择"矩形球面投影" 3.输出格式选择HTML5, 也可选择Flash(快被淘汰) 4.HTML5输出选项中3个重要选项4.1 F ...

  6. ipmi监控主机

    author: headsen   chen date: 2018-09-25  20:04:01 IPMI介绍       IPMI(Intelligent Platform Management ...

  7. linux shell中FS、OFS、RS、ORS图解

    在linux 中,总是会忘记FS\OFS\RS\ORS的使用 下面一张图非常明晰的显示

  8. 豆瓣api开发

    前面有说过豆瓣API的开发,在做一些开源项目的时候,很多时候会用到豆瓣API接口,拿过来做测试,现在只是对豆瓣API开发做一些简单的梳理: 豆瓣API开发的接口: https://developers ...

  9. 遍历DataSet

    using System; using System.Collections.Generic; using System.Linq; using System.Text; using System.D ...

  10. HOJ 2226&POJ2688 Cleaning Robot(BFS+TSP(状态压缩DP))

    Cleaning Robot Time Limit: 1000MS Memory Limit: 65536K Total Submissions: 4264 Accepted: 1713 Descri ...