今天,简单讲讲



android 浅复制与深复制的内容。

一、前言

任何变成语言中,其实都有浅拷贝和深拷贝的概念,Java 中也不例外。在对一个现有的对象进行拷贝操作的时候,是有浅拷贝和深拷贝之分的,他们在实际使用中,区别很大,如果对其进行混淆,可能会引发一些难以排查的问题。

本文就在 Java 中的深拷贝和浅拷贝做一个详细的解说。

二、什么是浅拷贝和深拷贝

首先需要明白,浅拷贝和深拷贝都是针对一个已有对象的操作。那先来看看浅拷贝和深拷贝的概念。

在 Java 中,除了基本数据类型(元类型)之外,还存在 类的实例对象 这个引用数据类型。而一般使用 『 = 』号做赋值操作的时候。对于基本数据类型,实际上是拷贝的它的值,但是对于对象而言,其实赋值的只是这个对象的引用,将原对象的引用传递过去,他们实际上还是指向的同一个对象。

而浅拷贝和深拷贝就是在这个基础之上做的区分,如果在拷贝这个对象的时候,只对基本数据类型进行了拷贝,而对引用数据类型只是进行了引用的传递,而没有真实的创建一个新的对象,则认为是浅拷贝。反之,在对引用数据类型进行拷贝的时候,创建了一个新的对象,并且复制其内的成员变量,则认为是深拷贝。

所以到现在,就应该了解了,所谓的浅拷贝和深拷贝,只是在拷贝对象的时候,对 类的实例对象 这种引用数据类型的不同操作而已。

三、Java 中的 clone()

3.1 Object 上的 clone() 方法

在 Java 中,所有的 Class 都继承自 Object ,而在 Object 上,存在一个 clone() 方法,它被声明为了 protected ,所以我们可以在其子类中,使用它。

而无论是浅拷贝还是深拷贝,都需要实现 clone() 方法,来完成操作。

它的实现非常的简单,它限制所有调用 clone() 方法的对象,都必须实现 Cloneable 接口,否者将抛出 CloneNotSupportedException 这个异常。最终会调用 internalClone() 方法来完成具体的操作。而 internalClone() 方法,实则是一个 native 的方法。对此我们就没必要深究了,只需要知道它可以 clone() 一个对象得到一个新的对象实例即可。

而反观 Cloneable 接口,可以看到它其实什么方法都不需要实现。对他可以简单的理解只是一个标记,是开发者允许这个对象被拷贝。

具体的使用很简单。

⑴clone方法将对象复制了一份并返回给调用者。一般而言,clone()方法满足:
①对任何的对象x,都有x.clone() !=x//克隆对象与原对象不是同一个对象
②对任何的对象x,都有x.clone().getClass()= =x.getClass()//克隆对象与原对象的类型一样
③如果对象x的equals()方法定义恰当,那么x.clone().equals(x)应该成立。

⑵Java中对象的克隆

①为了获取对象的一份拷贝,我们可以利用Object类的clone()方法。
②在派生类中覆盖基类的clone()方法,并声明为public。
③在派生类的clone()方法中,调用super.clone()。
④在派生类中实现Cloneable接口。

请看如下代码:

public class Student implements Cloneable
{ String name; int age; Student(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try{ o=(Student)super.clone();//Object 中的clone()识别出你要复制的是哪一个对象。 } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; }  public static void main(String[] args) { Student s1=new Student("zhangsan",18); Student s2=(Student)s1.clone(); s2.name="lisi"; s2.age=20; //修改学生2后,不影响学生1的值。System.out.println("name="+s1.name+","+"age="+s1.age); System.out.println("name="+s2.name+","+"age="+s2.age);}
}

说明:
①为什么我们在派生类中覆盖Object的clone()方法时,一定要调用super.clone()呢?在运行时刻,Object中的clone()识别出你要复制的是哪一个对象,然后为此对象分配空间,并进行对象的复制,将原始对象的内容一一复制到新对象的存储空间中。

②继承自java.lang.Object类的clone()方法是浅复制。以下代码可以证明之。

class Professor
{ String name; int age; Professor(String name,int age) { this.name=name; this.age=age; }
}
public class Student implements Cloneable
{ String name;// 常量对象。 int age; Professor p;// 学生1和学生2的引用值都是一样的。 Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try{ o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } o.p=(Professor)p.clone(); return o; }  public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30;  System.out.println("name="+s1.p.name+","+"age="+s1.p.age);System.out.println("name="+s2.p.name+","+"age="+s2.p.age);//输出结果学生1和2的教授成为lisi,age为30。}
}

那应该如何实现深层次的克隆,即修改s2的教授不会影响s1的教授?代码改进如下。
改进使学生1的Professor不改变(深层次的克隆)

class Professor implements Cloneable
{ String name; int age; Professor(String name,int age) { this.name=name; this.age=age; } public Object clone() { Object o=null; try{ o=super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } return o; }
}
public class Student implements Cloneable
{ String name; int age; Professor p; Student(String name,int age,Professor p) { this.name=name; this.age=age; this.p=p; } public Object clone() { Student o=null; try{ o=(Student)super.clone(); } catch(CloneNotSupportedException e) { System.out.println(e.toString()); } //对引用的对象也进行复制o.p=(Professor)p.clone(); return o; }  public static void main(String[] args) { Professor p=new Professor("wangwu",50); Student s1=new Student("zhangsan",18,p); Student s2=(Student)s1.clone(); s2.p.name="lisi"; s2.p.age=30; //学生1的教授不 改变。System.out.println("name="+s1.p.name+","+"age="+s1.p.age); System.out.println("name="+s2.p.name+","+"age="+s2.p.age); }
}

3.利用串行化来做深复制(主要是为了避免重写比较复杂对象的深复制的clone()方法,也可以程序实现断点续传等等功能)
    把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做 “解冻”或者“回鲜(depicking)”过程。
    应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
    在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
如下为深复制源代码。

public Object deepClone()
{ //将对象写到流里 ByteArrayOutoutStream bo=new ByteArrayOutputStream(); ObjectOutputStream oo=new ObjectOutputStream(bo); oo.writeObject(this); //从流里读出来 ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray()); ObjectInputStream oi=new ObjectInputStream(bi); return(oi.readObject());
}

这样做的前提是对象以及对象内部所有引用到的对象都是可串行化的,否则,就需要仔细考察那些不可串行化的对象或属性可否设成transient,从而将之排除在复制过程之外。上例代码改进如下。

class Teacher implements Serializable{String name;int age;public void Teacher(String name,int age){this.name=name;this.age=age;}
}
public class Student implements Serializable{String name;//常量对象int age;Teacher t;//学生1和学生2的引用值都是一样的。public void Student(String name,int age,Teacher t){this.name=name;this.age=age;this.p=p;}public Object deepClone() throws IOException,OptionalDataException,ClassNotFoundException{//将对象写到流里ByteArrayOutoutStream bo=new ByteArrayOutputStream();ObjectOutputStream oo=new ObjectOutputStream(bo);oo.writeObject(this);//从流里读出来ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());ObjectInputStream oi=new ObjectInputStream(bi);return(oi.readObject());}public static void main(String[] args){ Teacher t=new Teacher("tangliang",30);Student s1=new Student("zhangsan",18,t);Student s2=(Student)s1.deepClone();s2.t.name="tony";s2.t.age=40;//学生1的老师不改变System.out.println("name="+s1.t.name+","+"age="+s1.t.age);}
}

总之,可以通过重写clone来实现对象的复制,也可以通过序列号实现对象的复制。

android 浅复制与深复制就讲完了。

就这么简单。

android 浅复制与深复制相关推荐

  1. java自我复制_原型模式--自我复制(结合Java浅复制与深复制)

    原型模式,字面上的理解,以原型为标杆的模式. 原型模式其实就是从一个对象再创建另外一个可定制对象,而且不需知道任何创建的细节. 我们可以用原型示例指定创建对象的种类,并且通过拷贝这些原型创建新的对象. ...

  2. JAVA中浅复制与深复制

    來源:http://coolmist.javaeye.com/blog/127455 1.浅复制与深复制概念 ⑴浅复制(浅克隆) 被复制对象的所有变量都含有与原来的对象相同的值,而所有的对其他对象的引 ...

  3. python浅复制与深复制_Python中的浅复制与深复制

    python浅复制与深复制 In python, the assignment operator does not copy the objects, instead, they create bin ...

  4. 详解Python中的浅复制与深复制

    列表对象的copy()方法返回列表的浅复制.所谓浅复制,是指生产一个新的列表,并且把原列表中所有元素的引用都复制到新列表中.如果原列表中只包含整数.实数.复数等基本类型或元组.字符串这样的不可变类型, ...

  5. 深度解析javascript中的浅复制和深复制

    在谈javascript的浅复制和深复制之前,我们有必要在来讨论下js的数据类型.我们都知道有Number,Boolean,String,Null,Undefined,Object五种类型.而Obje ...

  6. java引用复制_Java中引用的浅复制和深复制

    Java中除了基本类型int,char,double等的赋值是按照值传递之外,其余的类型和对象都是按照引用进行传递的. 下面来看一个关于引用的例子. package referenceCopy; // ...

  7. 也来谈一谈js的浅复制和深复制

    2019独角兽企业重金招聘Python工程师标准>>> 1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制 ...

  8. C++ 浅复制、深复制详解

    文章目录 浅复制 深复制 有关浅复制与深复制的定义为:对类进行复制的时候按位复制,即把一个对象各数据成员的值原样复制到目标对象中.当类中涉及到指针类型数据成员的时候,往往就会产生指针悬挂问题. 浅复制 ...

  9. Java中Cloneable接口的浅复制与深复制

    Java中的深拷贝(深复制)和浅拷贝(浅复制) 深拷贝(深复制)和浅拷贝(浅复制)是两个比较通用的概念,尤其在C++语言中,若不弄懂,则会在delete的时候出问题,但是我们在这幸好用的是Java.虽 ...

最新文章

  1. Python/Jupyter Notebook以及可视化的运用
  2. canvas图表(4) - 散点图
  3. 全球铁矿石行业供给分析与投资可行性分析报告2022年版
  4. 宝塔/Linux下自动更新maccms到github原版的最新版
  5. 穿越计算机的迷雾--读书笔记二
  6. Spring Globle Transaction VS Local Transaction .
  7. Qt多线程之QThread
  8. RGB和CMYK配色表
  9. 北京租房住起来舒服的地方(小区)有哪些?
  10. 关键词搜索查找工具-批量关键词查找搜索工具-根据关键词自动采集素材软件
  11. commit 和 push 的临界点
  12. 判断图书的ISBN号码是否正确
  13. 华为od业务主管面试问题-我的回答
  14. 几个招聘网站,智联的最垃圾
  15. 微服务架构深度解析与最佳实践
  16. 如何成为有效学习的高手(笔记)
  17. 使用Packer 在 VMware vSphere 上构建 Redhat/CentOS 虚拟机
  18. 卷积神经网络中全连接层、softmax与softmax loss理解
  19. 常用的adodb使用方法
  20. (附源码)计算机毕业设计SSM基于框架的报修系统

热门文章

  1. 【Java面试题】34 List 、Map、Set 区别?
  2. [Material Design] 教你做一个Material风格、动画的button(MaterialButton)
  3. IDEA 设置忽略那些文件不提交到SVN服务器
  4. SPOJ 3267: DQUERY 树状数组,离线算法
  5. 11gOCP 1z0-052 :2013-09-11 MGR_ROLE role........................................................A66
  6. Normal Vector Using WorldInverseTranspose
  7. Lumia 800 7.10.8858.136
  8. Oracle笔记 十四、查询XML操作、操作系统文件
  9. 由于启动用户实例的进程时出错,导致无法生成 SQL Server 的用户实例。该连接将关闭...
  10. django建表报错