知识点: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. Chrome浏览器下CSS字体大小设置小于12px无效问题

    当字体大小被设置小于12px时,IE.firefox可以起作用.但chrome中仍然显示为12px大小. 解决方法为: html, body {     -webkit-text-size-adjus ...

  2. Activity 设置切换动画

    extends://blog.csdn.net/luohaowang320/article/details/42124225 | http://blog.csdn.net/xuewater/artic ...

  3. Android DatepickerDialog(日期选择器)的使用

    效果图如下: 日期和时间选择对话框,首先是要获得当前时间,这里用 java类中的Calendar来获得日期和时间(也可以用Date,但是不提倡,Date部分方法已经注释为过时), Calendar是一 ...

  4. 如何获取e.printStackTrace()的内容

    e.printStackTrace()通常是打印在控制台的,但是,有时候程序上线了需要看这个堆栈的内容就不容易了,一来生产环境打印的东西很多或者很少,二来有时候无法直接查看到,这个时候就需要把这些内容 ...

  5. 拼接的html的onclick事件中无法传递对象给js方法的处理办法

    如下: 拼接的html: " onclick=\"valDocName2('"+JSON.stringify(doc).replace(new RegExp(" ...

  6. Hive桶列BucketedTables

    The CLUSTERED BY and SORTED BY creation commands do not affect how data is inserted into a table – o ...

  7. LCA(离线算法)

    hdu4547 CD操作 Time Limit: 10000/5000 MS (Java/Others)    Memory Limit: 65535/32768 K (Java/Others) To ...

  8. Java虚拟机规范----JVM体系结构

    一.Java平台的结构图 二.JVM与JRE.JDK关系? JVM:Java Virtual Machine(Java虚拟机),负责执行符合规范的Class文件 JRE:Java Runtime En ...

  9. mysql中sql注入的随笔

    当使用如下登录代码时:就会引发sql注入问题 怎么注入呢? 'or 1=1 # 就可以了. 为什么呢? 首先or:在sql中是或者,只要满足前一个或后一个条件即可,只要所以不论你是 'or 1=1 # ...

  10. rk3188 公板调试记录

    打开ccache后编译android果然快很多. make rk3188_sdk_defconfig 触摸屏有问题,然后再吧input底下的touchscreen 屏蔽掉     james@jame ...