一 什么是克隆

克隆就是根据已有对象复制出另一个对象。比如用A克隆出B,一般在java中有如下约定:

// A与B的引用不同
A!=B
// A与B的类相同
A.getClass == B.getClass
// A和B内容相同
A.equals(B)通常来说 A.equals(B) == true,但是这不是强制的要求,开发人员可根据具体需要决定是否重写equals方法。

二 怎么实现克隆

需要克隆的类 实现 Cloneable 接口,并重写其中的clone方法。其中super.clone()会把原始对象的属性克隆到新对象的属性中。

public class Student1 implements Cloneable{private String name;private int age;public Student1(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Student1 clone() throws CloneNotSupportedException {return (Student1)super.clone();}
}

测试程序如下:

public class TestClone {public static void main(String[] args) {Student1 xiaoming = new Student1(new String("小明"),12);Student1 xiaoming_Copy = null;try {xiaoming_Copy = xiaoming.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}System.out.println(xiaoming.toString());System.out.println(xiaoming_Copy.toString());}
}

输出:

{“age”:12,”name”:”小明”}
{“age”:12,”name”:”小明”}

这样Student的克隆成功了。

实际上,Cloneable是个空接口,它没有定义任何成员。它只是一个对象可重写并使用clone方法的标志。

public interface Cloneable {
}

三 这样就结束了吗??

如果一个类中的域(属性)都是基本数据类型或者final类型当然就没有问题了,但是如果一个类的域是非final类型的引用类型(比如:数组、其他对象)。那么这样克隆就会出现一个问题,先看一个例子:
新加了一个Teacher类:

public class Teacher {private String name;private int age;public Teacher(String name, int age) {this.name = name;this.age = age;}

Stuent类中加入Teacher属性:

public class Student2 implements Cloneable {private String name;private int age;private Teacher teacher;public Student2(String name, int age, Teacher teacher) {this.name = name;this.age = age;this.teacher = teacher;}@Overrideprotected Student2 clone() throws CloneNotSupportedException {return (Student2)super.clone();}

运行下面的测试程序:

public class TestClone {public static void main(String[] args) {Teacher teacher = new Teacher("王尼玛",41);Student2 xiaoming = new Student2(new String("小明"),12,teacher);Student2 xiaoming_Copy = null;try {xiaoming_Copy = xiaoming.clone();} catch (CloneNotSupportedException e) {e.printStackTrace();}xiaoming_Copy.getTeacher().setName("齐东强");System.out.println(xiaoming.toString());System.out.println(xiaoming_Copy.toString());}
}

输出

{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齐东强”}}
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齐东强”}}

发现拷贝对象副本在改变自己属性的时候会影响原始主本的数据,这是因为super.clone()只会把Student中对Teacher的引用值copy给克隆对象。所以主本和副本中的teacher对象指向了相同的堆地址。显然这不是我们想要的。

四 如何解决

嵌套多少层非final类型的引用,我们就拷贝多少层!
Teacher也 实现 Cloneable类,添加clone方法

public class Teacher implements Cloneable{private String name;private int age;public Teacher(String name, int age) {this.name = name;this.age = age;}@Overrideprotected Teacher clone() throws CloneNotSupportedException {return (Teacher)super.clone();}}

修改Student中的clone方法为:

@Overridepublic Student2 clone() throws CloneNotSupportedException {Student2 copy = (Student2)super.clone();copy.teacher = teacher.clone();return copy;}

再次运行测试程序

{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”王尼玛”}}
{“age”:12,”name”:”小明”,”teacher”:{“age”:41,”name”:”齐东强”}}
这次修改克隆对象的引用属性,原对象就不会被改变了

五 总结

其实三中的demo被称为浅克隆(浅拷贝),四中的解决方案为深克隆(深拷贝)

5.1 浅拷贝

浅拷贝是指拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量),而不拷贝对象包含的非final引用类型属性指向的对象

public Object clone() {return super.clone();}

直接使用super.clone()方法。

5.2 深拷贝

深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象

public Object clone() {Object obj = super.clone();//先浅拷贝一下//然后修正需要修正的属性obj.属性1 = xxx;obj.属性2 = xxx;...}

5.3 如何选择使用哪种拷贝方式

1.如果类中的属性只包含有基本数据类型常量(包括String),那么这个类使用浅拷贝。

使用浅拷贝的类也可能需要修正,譬如代表序列号、其他唯一ID、对象的创建时间的属性,不管这些属性是基本类型还是常量,都需要修正。(常量需要修正时,不能使用super.clone()

2.如果类中的属性包含有非final的引用类型时(String不算),使用深拷贝,不然拷贝对象的改变会影响原对象,就失去了拷贝的意义。

5.4 什么时候使用克隆

  1. 当你想获取某个对象的数据内容,对其进行一系列操作又不想改变其内容时。
  2. 直接用构造器新生成一个对象的代价太大时。

Java中克隆的用法,深拷贝、浅拷贝概念的引出相关推荐

  1. Java中哈希集(HashSet)概念,实现以及操作

    Java中HashSet的用法 1. HashSet概念 2.Java文档中HashSet的实现 3.HashSet的构造函数 3.1 HashSet() 3.2 HashSet(int initia ...

  2. java中native的用法

    java中native的用法前言:在查看 Thread.java 文件时,发现有一个 方法比较特殊 private native void start0();概念:native关键字说明其修饰的方法是 ...

  3. java中的基本用法

    java中的基本用法 关键字:专门用途的字符串 所有java关键字都是小写英文 标识符 java常量 java变量 ■ 作用域:起作用的区域■ 使用前必须先声明,在赋值.使用变量名访问这块区域 jav ...

  4. Java中getResourceAsStream的用法

    Java中getResourceAsStream的用法 首先,Java中的getResourceAsStream有以下几种: 1. Class.getResourceAsStream(String p ...

  5. java中怎样克隆,如何在Java中克隆列表?

    要克隆Java中的列表,最简单的方法是使用ArrayList.clone()方法- 示例import java.util.ArrayList; public class Demo { public s ...

  6. Java中getResourceAsStream的用法小结

    2019独角兽企业重金招聘Python工程师标准>>> Java中getResourceAsStream的用法小结 一.Java中的getResourceAsStream主要有以下三 ...

  7. java中substring的用法

    2019独角兽企业重金招聘Python工程师标准>>> java中substring的用法 str=str.substring(int beginIndex);截取掉str从首字母起 ...

  8. JAVA中Final的用法

    JAVA中Final的用法 1. 修饰基础数据成员的final 这是final的主要用途,其含义相当于C/C++的const,即该成员被修饰为常量,意味着不可修改.如java.lang.Math类中的 ...

  9. php simpledateformat,Java中SimpleDateFormat的用法介绍(代码示例)

    本篇文章给大家带来的内容是关于Java中SimpleDateFormat的用法介绍(代码示例),有一定的参考价值,有需要的朋友可以参考一下,希望对你有所帮助. 1.为什么要使用SimpleDateFo ...

最新文章

  1. [转]SQL SERVER – Find Most Expensive Queries Using DMV
  2. python编写程序-Python 编程速成(推荐)
  3. 【Python刷题】_7
  4. php微信小程序会话保持,微信小程序保持session会话的方法
  5. [zz]volatile
  6. Oracle 存储过程入门
  7. Pytorch MNIST直接离线加载二进制文件到pytorch
  8. 四川省中职计算机考试题,(四川省计算机等级考试题库.doc
  9. 关于python_关于python的基础知识
  10. html - table分页断行,关于window.print网页分页换页table不断行的处理
  11. sql server版本 性能_迁移到高版本 SQL 数据库后,性能变差了
  12. 计算机语言系统不支持,win7电脑安装IE8出现“此安装不支持您的操作系统的当前语言”怎么办...
  13. C++第五章课后习题16-字符串按逆序输出
  14. 《深入理解计算机系统》读书笔记(ch1)
  15. 谈谈作为DBA我对MySQL数据库优化的理解
  16. C++ atuo关键字看这一篇就够了
  17. Qt之QImage类
  18. linux桌面入口文件(.desktop)规范
  19. Qt之JSON教程-实战篇
  20. Android 翻牌动画 实现

热门文章

  1. SQL高级语法学习总结(一)
  2. APP在线抢答解决方案(RTC直播间抢答或者抢背唱歌)
  3. F2FS源码分析-6.6 [其他重要数据结构以及函数] F2FS的重命名过程-f2fs_rename函数
  4. SQL Server AlwaysON从入门到进阶(1)——何为AlwaysON?
  5. 个人账本软件---界面设计
  6. anaconda新手使用心得
  7. thinkpad如何禁用触摸板(触控板)或指点杆
  8. 【2019-游记】中山纪念中学暑期游Day6
  9. 【云计算】实验3:Keystone 组件
  10. 猿创征文|Highgo Database安全版安装指导手册