浅复制与深复制在很多编程语言中都有出现,那么什么是浅复制,什么是深复制呢?

要区分浅复制与深复制,首先我们要明确什么是复制,怎样才算是复制。复制的例子在生活中也随处可见,如复印一份文档,复制一段文字等。我们可以发现,复制操作后可以得到两份相同的东西,即复制由一变为二了。下面来看一个例子:

  1. public class User{
  2.  
  3. private int age;
  4.  
  5. public int getAge(){
  6.  
  7. return age;
  8.  
  9. }
  10.  
  11. }
  12.  
  13. User user1 = new User();
  14.  
  15. User user2 = user1;

上面把user2 = user1属于复制吗?显然,这种操作不属于复制,因为user2=user1仅仅是把user1的引用赋值给user2,此时user1与user2指向内存中同一个对象,所以没有一变成二。在Java中的复制需要得到两个相同的对象,而不是指两个相同的引用。

如果要得到一个真正的复制对象,需要自行实现clone()方法,clone()方法存在于Object类中,默认被所有的类继承,方法签名如下:

protected native Object clone() throws CloneNotSupportedException;

由于clone()方法是用protected修饰的,不能在类外被调用,所以我们如果要复制一个对象,就需要在类中覆盖clone()方法,并把修饰符升级为public,而且被复制的类需要实现Cloneable接口,否则调用clone()方法时会抛出CloneNotSupportedException异常。

  1. public class User implements Cloneable{
  2.  
  3. public User(int age){
  4.  
  5. this.age = age;
  6.  
  7. }
  8.  
  9. private int age;
  10.  
  11. public int getAge(){
  12.  
  13. return age;
  14.  
  15. }
  16.  
  17. public Object clone() {
  18.  
  19. User user = null;
  20.  
  21. try{
  22.  
  23. user = super.clone();
  24.  
  25. }catch(Exception e){
  26.  
  27. }
  28.  
  29. return user;
  30.  
  31. }
  32.  
  33. }
  34.  
  35. User usr1 = new User();
  36.  
  37. User usr2 = usr1.clone();
  38.  
  39. System.out.println(usr1==usr2);
  40.  
  41. System.out.println(usr1.getAge()+", "+ usr2.getAge());
  42.  
  43. ######结果
  44.  
  45. false
  46.  
  47. ,

说明clone方法得到了两个对象,且变量相同。上面的例子说明的仅仅是浅复制的情况,下面再来看一个例子:

  1. public class Phone{
  2.  
  3. private String name;
  4.  
  5. public Phone(String name){
  6.  
  7. this.name = name;
  8.  
  9. }
  10.  
  11. public void setName(String name){
  12.  
  13. this.name = name;
  14.  
  15. }
  16.  
  17. public String getName(){
  18.  
  19. return this.name;
  20.  
  21. }
  22.  
  23. }
  24.  
  25. public class User implements Cloneable{
  26.  
  27. public User(int age){
  28.  
  29. this.age = age;
  30.  
  31. this.phone = new Phone("华为");
  32.  
  33. }
  34.  
  35. private int age;
  36.  
  37. public Phone phone;
  38.  
  39. public int getAge(){
  40.  
  41. return age;
  42.  
  43. }
  44.  
  45. public Object clone() {
  46.  
  47. User user = null;
  48.  
  49. try{
  50.  
  51. user = super.clone();
  52.  
  53. }catch(Exception e){
  54.  
  55. }
  56.  
  57. return user;
  58.  
  59. }
  60.  
  61. }

上面代码定义了User类和Phone类,其中User类有一个Phone类的变量,下面调用这两个类:

  1. User usr1 = new User();
  2.  
  3. User usr2 = usr1.clone();
  4.  
  5. System.out.println(usr1==usr2);
  6.  
  7. System.out.println(usr1.getAge()+", "+ usr2.getAge());
  8.  
  9. System.out.println(usr1.phone.getName()+", "+ usr2.phone.getName());
  10.  
  11. usr1.phone.setName("小米");
  12.  
  13. System.out.println(usr1.phone.getName()+", "+ usr2.phone.getName());
  14.  
  15. ###结果
  16.  
  17. false
  18.  
  19. ,
  20.  
  21. 华为, 华为
  22.  
  23. 小米, 小米

有没有发现一些问题了?修改usr1的变量phone的name的值,修改为“小米”,但是usr2的变量phone的name的值也变为“小米”了。这说明了usr1与usr2的phone变量引用的Phone对象是同一个的,上面的这种复制就是浅复制,浅复制没有复制引用类型的变量。

为了达到深复制,我们需要把类中的引用类型也变成可复制化,即实现Cloneable接口,如下:

  1. public class Phone implements Cloneable{
  2.  
  3. private String name;
  4.  
  5. public Phone(String name){
  6.  
  7. this.name = name;
  8.  
  9. }
  10.  
  11. public void setName(String name){
  12.  
  13. this.name = name;
  14.  
  15. }
  16.  
  17. public String getName(){
  18.  
  19. return this.name;
  20.  
  21. }
  22.  
  23. public Object clone(){
  24.  
  25. Phone phone = null;
  26.  
  27. try{
  28.  
  29. phone = super.clone();
  30.  
  31. }catch(Exception e){
  32.  
  33. }
  34.  
  35. return phone;
  36.  
  37. }
  38.  
  39. }
  40.  
  41. public class User implements Cloneable{
  42.  
  43. public User(int age){
  44.  
  45. this.age = age;
  46.  
  47. this.phone = new Phone("华为");
  48.  
  49. }
  50.  
  51. private int age;
  52.  
  53. public Phone phone;
  54.  
  55. public int getAge(){
  56.  
  57. return age;
  58.  
  59. }
  60.  
  61. public Object clone() {
  62.  
  63. User user = null;
  64.  
  65. try{
  66.  
  67. user = super.clone();
  68.  
  69. }catch(Exception e){
  70.  
  71. }
  72.  
  73. user.phone = (Phone)phone.clone();
  74.  
  75. return user;
  76.  
  77. }
  78.  
  79. }

由上可以总结,浅复制会把基本数据类型的变量都复制一份,对于引用类型变量只是仅仅对引用进行复制,没有对引用的内存对象进行复制;而深复制会把对象复制一份,也会把对象的引用变量指向的对象复制一份,深复制复制更加彻底。

文章同步发布在朗度云网站上,传输门:

http://www.wolfbe.com/detail/201608/271.html

java基础-浅复制与深复制的理解的更多相关文章

  1. JAVA中浅复制与深复制 - coolmist - ITeye技术网站

    body{ font-family: "Microsoft YaHei UI","Microsoft YaHei",SimSun,"Segoe UI& ...

  2. Java中引用的浅复制和深复制

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

  3. Java里的浅复制与深复制

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

  4. JAVA中浅复制与深复制

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

  5. Java中的“浅复制”与“深复制”

    复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...

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

    1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制问题(Object,Array等),不讨论基本数据类型(null,unde ...

  7. js的浅复制和深复制

    1.浅复制VS深复制 本文中的复制也可以称为拷贝,在本文中认为复制和拷贝是相同的意思.另外,本文只讨论js中复杂数据类型的复制问题(Object,Array等),不讨论基本数据类型(null,unde ...

  8. php对象复制、clone、浅复制与深复制实例详解

    php对象复制.clone.浅复制与深复制实例详解 一.用clone(克隆)来复制对象$obj1 = new Object();$obj2 = clone $obj1;clone方法会触发对象里定义的 ...

  9. iOS 浅复制和深复制的深层理解,含示例

    转载:https://www.zybuluo.com/MicroCai/note/50592 版权归 @MicroCai 所有 以下是正文: 浅复制就是指针拷贝:深复制就是内容拷贝. 集合的浅复制 ( ...

随机推荐

  1. <QtEndian> - Endian Conversion Functions

    The <QtEndian> header provides functions to convert between little and big endian representati ...

  2. linux之history

    1.使用HISTTIMEFORMAT在历史中显示TIMESTAMP 通常情况下,当你在命令行中键入history时,终端中将显示你刚输入的命令及其编号.如果出于审查命令的目的,和命令一起显示时间戳将会 ...

  3. mysql 历史记录查询

    SHOW SLAVE STATUS insert into jy510_admin set userid='123123' mysqlbinlog d:xampp\mysql\data\mysql-b ...

  4. 短小实用 渗透用的Python小脚本

    渗透的很多时候,找到的工具并不适用,自己码代码才是王道,下面三个程序都是渗透时在网络上找不到合适工具,自己辛苦开发的,短小实用. 一.记录root密码小工具 root.py #!/usr/bin/py ...

  5. 2015 FVDI V6.3 Software Free Download

    2015 FVDI with software USB dongle has newly upgraded to V6.3. Here software upgrade list: ABRITES C ...

  6. 【Linux/Ubuntu学习5】Ubuntu 下android 开发,eclipse不能识别手机

    ubuntu下eclipse不能识别手机解决方法: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 1) 在终端运行 lsusb 会发现结果 ...

  7. 启动 Eclipse 弹出“Failed to load the JNI shared library jvm.dll”错误的解决方法!&&在eclipse.ini中为eclipse指定jdk启动

    参考:http://blog.csdn.net/zyz511919766/article/details/7442633 http://blog.sina.com.cn/s/blog_028f0c1c ...

  8. poj 3621 0/1分数规划求最优比率生成环

    思路:以val[u]-ans*edge[i].len最为边权,判断是否有正环存在,若有,那么就是ans小了.否则就是大了. 在spfa判环时,先将所有点进队列. #include<iostrea ...

  9. HTML常见标签

    标题:h1.h2.h3.h4.h5.... 段落:p 换行:br 容器:div.span(用来容纳其他标签) 表格:table.tr.td 列表:ul.ol.li 图片:img 表单:input 链接 ...

  10. centos 6.5 安装lnmp(linux+nginx+mysql+php)

    参考:http://www.cnblogs.com/AloneSword/archive/2013/03/18/2966750.html (总结并简要) 一安装cmake wget -c http:/ ...