关键词:
原文链接:
http://blog.csdn.net/tounaobun/article/details/8491392
假如说你想复制一个简单变量。很简单:
- int apples = 5;
- int pears = apples;
不仅仅是int类型,其它七种原始数据类型(boolean,char,byte,short,float,double.long)同样适用于该类情况。
但是如果你复制的是一个对象,情况就有些复杂了。
假设说我是一个beginner,我会这样写:
- class Student {
- private int number;
- public int getNumber() {
- return number;
- }
- public void setNumber(int number) {
- this.number = number;
- }
- }
- public class Test {
- public static void main(String args[]) {
- Student stu1 = new Student();
- stu1.setNumber(12345);
- Student stu2 = stu1;
- System.out.println("学生1:" + stu1.getNumber());
- System.out.println("学生2:" + stu2.getNumber());
- }
- }
打印结果:
- 学生1:12345
- 学生2:12345
这里我们自定义了一个学生类,该类只有一个number字段。
我们新建了一个学生实例,然后将该值赋值给stu2实例。(Student stu2 = stu1;)
再看看打印结果,作为一个新手,拍了拍胸腹,对象复制不过如此,
难道真的是这样吗?
我们试着改变stu2实例的number字段,再打印结果看看:
- stu2.setNumber(54321);
- System.out.println("学生1:" + stu1.getNumber());
- System.out.println("学生2:" + stu2.getNumber());
打印结果:
- 学生1:54321
- 学生2:54321
这就怪了,为什么改变学生2的学号,学生1的学号也发生了变化呢?
原因出在(stu2 = stu1) 这一句。该语句的作用是将stu1的引用赋值给stu2,
这样,stu1和stu2指向内存堆中同一个对象。如图:
那么,怎样才能达到复制一个对象呢?
是否记得万类之王Object。它有11个方法,有两个protected的方法,其中一个为clone方法。
该方法的签名是:
protected native Object clone() throws CloneNotSupportedException;
因为每个类直接或间接的父类都是Object,因此它们都含有clone()方法,但是因为该方法是protected,所以都不能在类外进行访问。
要想对一个对象进行复制,就需要对clone方法覆盖。
一般步骤是(浅复制):
1. 被复制的类需要实现Clonenable接口(不实现的话在调用clone方法会抛出CloneNotSupportedException异常) 该接口为标记接口(不含任何方法)
2. 覆盖clone()方法,访问修饰符设为public。方法中调用super.clone()方法得到需要的复制对象,(native为本地方法)
下面对上面那个方法进行改造:
- class Student implements Cloneable{
- private int number;
- public int getNumber() {
- return number;
- }
- public void setNumber(int number) {
- this.number = number;
- }
- @Override
- public Object clone() {
- Student stu = null;
- try{
- stu = (Student)super.clone();
- }catch(CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return stu;
- }
- }
- public class Test {
- public static void main(String args[]) {
- Student stu1 = new Student();
- stu1.setNumber(12345);
- Student stu2 = (Student)stu1.clone();
- System.out.println("学生1:" + stu1.getNumber());
- System.out.println("学生2:" + stu2.getNumber());
- stu2.setNumber(54321);
- System.out.println("学生1:" + stu1.getNumber());
- System.out.println("学生2:" + stu2.getNumber());
- }
- }
打印结果:
- 学生1:12345
- 学生2:12345
- 学生1:12345
- 学生2:54321
如果你还不相信这两个对象不是同一个对象,那么你可以看看这一句:
- System.out.println(stu1 == stu2); // false
上面的复制被称为浅复制(Shallow Copy),还有一种稍微复杂的深度复制(deep copy):
我们在学生类里再加一个Address类。
- class Address {
- private String add;
- public String getAdd() {
- return add;
- }
- public void setAdd(String add) {
- this.add = add;
- }
- }
- class Student implements Cloneable{
- private int number;
- private Address addr;
- public Address getAddr() {
- return addr;
- }
- public void setAddr(Address addr) {
- this.addr = addr;
- }
- public int getNumber() {
- return number;
- }
- public void setNumber(int number) {
- this.number = number;
- }
- @Override
- public Object clone() {
- Student stu = null;
- try{
- stu = (Student)super.clone();
- }catch(CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return stu;
- }
- }
- public class Test {
- public static void main(String args[]) {
- Address addr = new Address();
- addr.setAdd("杭州市");
- Student stu1 = new Student();
- stu1.setNumber(123);
- stu1.setAddr(addr);
- Student stu2 = (Student)stu1.clone();
- System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
- System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
- }
- }
打印结果:
- 学生1:123,地址:杭州市
- 学生2:123,地址:杭州市
乍一看没什么问题,真的是这样吗?
我们在main方法中试着改变addr实例的地址。
- addr.setAdd("西湖区");
- System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
- System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
打印结果:
- 学生1:123,地址:杭州市
- 学生2:123,地址:杭州市
- 学生1:123,地址:西湖区
- 学生2:123,地址:西湖区
这就奇怪了,怎么两个学生的地址都改变了?
原因是浅复制只是复制了addr变量的引用,并没有真正的开辟另一块空间,将值复制后再将引用返回给新对象。
所以,为了达到真正的复制对象,而不是纯粹引用复制。我们需要将Address类可复制化,并且修改clone方法,完整代码如下:
- package abc;
- class Address implements Cloneable {
- private String add;
- public String getAdd() {
- return add;
- }
- public void setAdd(String add) {
- this.add = add;
- }
- @Override
- public Object clone() {
- Address addr = null;
- try{
- addr = (Address)super.clone();
- }catch(CloneNotSupportedException e) {
- e.printStackTrace();
- }
- return addr;
- }
- }
- class Student implements Cloneable{
- private int number;
- private Address addr;
- public Address getAddr() {
- return addr;
- }
- public void setAddr(Address addr) {
- this.addr = addr;
- }
- public int getNumber() {
- return number;
- }
- public void setNumber(int number) {
- this.number = number;
- }
- @Override
- public Object clone() {
- Student stu = null;
- try{
- stu = (Student)super.clone(); //浅复制
- }catch(CloneNotSupportedException e) {
- e.printStackTrace();
- }
- stu.addr = (Address)addr.clone(); //深度复制
- return stu;
- }
- }
- public class Test {
- public static void main(String args[]) {
- Address addr = new Address();
- addr.setAdd("杭州市");
- Student stu1 = new Student();
- stu1.setNumber(123);
- stu1.setAddr(addr);
- Student stu2 = (Student)stu1.clone();
- System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
- System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
- addr.setAdd("西湖区");
- System.out.println("学生1:" + stu1.getNumber() + ",地址:" + stu1.getAddr().getAdd());
- System.out.println("学生2:" + stu2.getNumber() + ",地址:" + stu2.getAddr().getAdd());
- }
- }
打印结果:
- 学生1:123,地址:杭州市
- 学生2:123,地址:杭州市
- 学生1:123,地址:西湖区
- 学生2:123,地址:杭州市
这样结果就符合我们的想法了。
总结:浅拷贝是指在拷贝对象时,对于基本数据类型的变量会重新复制一份,而对于引用类型的变量只是对引用进行拷贝,
没有对引用指向的对象进行拷贝。
而深拷贝是指在拷贝对象时,同时会对引用指向的对象进行拷贝。
区别就在于是否对 对象中的引用变量所指向的对象进行拷贝。
最后我们可以看看API里其中一个实现了clone方法的类:
java.util.Date:
- /**
- * Return a copy of this object.
- */
- public Object clone() {
- Date d = null;
- try {
- d = (Date)super.clone();
- if (cdate != null) {
- d.cdate = (BaseCalendar.Date) cdate.clone();
- }
- } catch (CloneNotSupportedException e) {} // Won‘t happen
- return d;
- }
该类其实也属于深度复制。
javascript中的深拷贝和浅拷贝
文章目录JavaScript中的变量类型深拷贝和浅拷贝的理解深拷贝和浅拷贝的实现方式为什么需要深拷贝和浅拷贝 JavaScript中的变量类型(1)、基本类型 JavaScript中的基本类型有五种:null、undefined、boolean、string、number。变量是按... 查看详情
详解java技术的深拷贝和浅拷贝
...会问的问题,而且了解深拷贝和浅拷贝的原理,对于Java中的所谓值传递或者引用传递将会有更深的理解。1、创建对象的5种方式①、通过new关键字这是最常用的一种方式,通过new关键字调用类的有参或无参构造方法来创建对象。... 查看详情
js中的深拷贝和浅拷贝
深复制和浅复制只针对像Object,Array这样的复杂对象的。简单来说,浅复制只复制一层对象的属性,而深复制则递归复制了所有层级。深浅拷贝 的主要区别就是:复制的是引用(地址)还是复制的是实例。所谓 深浅拷贝:对... 查看详情
java中的深拷贝和浅拷贝(代码片段)
目录🍎引出拷贝🍎浅拷贝🍎深拷贝🍎总结引出拷贝现在有一个学生类和书包类,在学生类中有引用类型的书包变量:classSchoolBagprivateStringbrand;//书包的品牌privateintsize;//书包的尺寸//getter、setter略publicSchoo... 查看详情
objective-c中的深拷贝和浅拷贝
...内容原封不动的给我拿过来。对容器类的深拷贝是对容器中的每个元素都进行拷贝,容器类的浅拷贝是对容器里的内容不进行拷贝,两个容器的地址是不同的,但容器里的所装的东西是一样的,在一个 查看详情
$.extend()的深拷贝和浅拷贝详细讲解
版权声明:作者原创,转载请注明出处!语法:jQuery.extend([deep],target,object1[,objectN])描述: 将两个或更多对象的内容合并到第一个对象。关于$.extend()的用法网上有很多文章,在这里指向写写对深浅拷贝的理解深浅拷贝对应的参... 查看详情
python中的深拷贝和浅拷贝区别(代码片段)
首先,我们知道Python3中,有6个标准的数据类型,他们又分为可变和不可变。不可变:Number(数字)、String(字符串)、Tuple(元组)。可以变:List(列表)、Dictionary(字典)、Set(集合)。浅拷贝copy模块里面的copy方法实现。... 查看详情
java的深拷贝和浅拷贝
熟悉C++的朋友对这个话题应该很熟悉,浅拷贝就是指两个对象共同拥有同一个值,一个对象改变了该值,也会影响到另一个对象。深拷贝就是两个对象的值相等,但是互相独立。本来想把以前写的一篇文章扩充一下... 查看详情
javascript中的深拷贝和浅拷贝到底是什么(代码片段)
前言:深拷贝和浅拷贝最根本的区别在于是否真正获取一个对象的复制实体,而不是引用。学习深拷贝和浅拷贝之前要先理解什么是基本类型和引用类型。一、到底什么是基本类型和引用类型?基本类型:就是值... 查看详情
javascript中的深拷贝和浅拷贝常用方法总结(代码片段)
本文乃学习总结,学习参考自:https://medium.com/javascript-in-plain-english/how-to-deep-copy-objects-and-arrays-in-javascript-7c911359b089对于引用类型(数值类型的拷贝就是字面的拷贝,就不说了)来说,赋值运算符 查看详情
对象的深拷贝和浅拷贝
...对象时(用一个对象去初始化另外一个对象),会调用类中的拷贝构造函数。如果我们自己没有在类里面写拷贝构造函数,则C++编译器会调用默认的拷贝构造函数。 浅拷贝:如果类定义的对象包含的某个成员是动态内存分配... 查看详情
c++中的深拷贝和浅拷贝构造函数(代码片段)
1,对象的构造在实际工程开发当中是相当重要的,C++中使用类就要创建对象,这就涉及了对象的构造,本节课讲解对象的构造和内存操作方面的问题; 2,实际工程开发中,bug产生的根源,必然的会有内存操作的问题,... 查看详情
js的深拷贝和浅拷贝
浅拷贝和深拷贝都是对于复杂对象Object和Array来说的,对于直接量来说,复制的是值,也就不存在深浅的区别.对于对象来说,浅拷贝就是将自身的属性复制到另外一个空对象上,深拷贝则更近一步,它会将对象的对象属性进行递归拷贝,... 查看详情
c++中的深拷贝和浅拷贝的案例对比理解(代码片段)
用两个案例对比来理解为什么要深拷贝和浅拷贝案例一#include<iostream>usingnamespacestd;/*简单说浅拷贝就是赋值操作:深拷贝就是在堆区间又申请了一个空间,进行拷贝操作*/classPerpublic: int*name;public: Per(intn) name=newint(n... 查看详情
js中引用类型的深拷贝和浅拷贝的区别
一、曾经在读JQ源码的时候,对深拷贝算是有了一点的理解。我们在项目中是不是经常会遇到这样的问题呢?后台返回一个数组对象(引用类型).次数在页面渲染中需要对部分数据进行处理比如:银行卡62345092534(这么长)但在... 查看详情
解析js中的深拷贝和浅拷贝(代码片段)
js中的浅拷贝和深拷贝,只是针对复杂数据类型(Objcet,Array)的复制问题。简单来讲浅拷贝和深拷贝都可以实现在原有对象的基础上再生成一份的作用。但是根据新生成的对象能否影响到原对象可以分为浅拷贝和深拷贝。... 查看详情
解析js中的深拷贝和浅拷贝(代码片段)
js中的浅拷贝和深拷贝,只是针对复杂数据类型(Objcet,Array)的复制问题。简单来讲浅拷贝和深拷贝都可以实现在原有对象的基础上再生成一份的作用。但是根据新生成的对象能否影响到原对象可以分为浅拷贝和深拷贝。... 查看详情
清晰python的深拷贝和浅拷贝(代码片段)
强推可可老师视频pythontutor工具网址查了好多资料,看了好多示例代码,都没理解成功,b站上发现宝藏视频,分享给大家。文章目录1、可变对象(1)浅拷贝(2)深拷贝2、不可变对象1、可变对象可变对象包括list(... 查看详情