clone()方法是Object的native方法。protected native Object clone() throws CloneNotSupportedException;  声明为protected,表明子类必须重新实现该方法,除非是与Obeject类在一个包里,后者是不可能的。而实际上,作为native方法clone()已经有一份field to field的浅拷贝实现,实际上是不需要一定重写的。这种情况下,需要的做法就是覆写clone()方法,在方法里通过super.clone()调用Object的clone()。

而Cloneable是标记型接口,实现了Cloneable才可以实现clone()方法。否则使用clone()方法会报错。

下面是ArrayList的clone()

  1. /**
  2. * Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
  3. * elements themselves are not copied.)
  4. *
  5. * @return a clone of this <tt>ArrayList</tt> instance
  6. */
  7. public Object clone() {
  8. try {
  9. ArrayList<?> v = (ArrayList<?>) super.clone();
  10. v.elementData = Arrays.copyOf(elementData, size);
  11. v.modCount = 0;
  12. return v;
  13. } catch (CloneNotSupportedException e) {
  14. // this shouldn't happen, since we are Cloneable
  15. throw new InternalError(e);
  16. }
  17. }

这里为何不是简单的super.clone()浅拷贝呢?因为成员变量是复杂类型时(涉及成员变量为对象的引用),就需要深拷贝。

下面做个小实验,先使用浅拷贝,验证普通的成员变量是ok的:

  1. package a;
  2.  
  3. public class CloneTest implements Cloneable {
  4. private int v_a;
  5. public void setV_a(int v) {
  6. v_a = v;
  7. }
  8. public Object clone() throws CloneNotSupportedException {
  9. return super.clone();
  10. }
  11. public void print_v_a() {
  12. System.out.println(v_a);
  13. }
  14. public static void main(String[] args) throws CloneNotSupportedException {
  15. CloneTest ct0 = new CloneTest();
  16. ct0.setV_a(66);
  17. CloneTest ct1 = (CloneTest)ct0.clone();
  18. ct1.print_v_a();
  19. ct0.setV_a(88);
  20. ct1.print_v_a();
  21. ct0.print_v_a();
  22. }
  23. }

先设置ct0的v_a对象为66,然后ct1对象是ct0的拷贝,打印ct1的v_a,也为66,说明拷贝成功。 之后重新设置ct0的值为88,ct1的值没变还是66。

  1. package a;
  2.  
  3. import java.util.Arrays;
  4.  
  5. class A {
  6. private int v;
  7. public void setV(int v) {
  8. this.v = v;
  9. }
  10. public void p_v() {
  11. System.out.println(v);
  12. }
  13. }
  14.  
  15. public class CloneTest implements Cloneable {
  16. private A v_a;
  17. public void setV_a(A v) {
  18. v_a = v;
  19. }
  20. public Object clone() throws CloneNotSupportedException {
  21. return super.clone();
  22. }
  23. public void print_v_a() {
  24. v_a.p_v();
  25. }
  26. public static void main(String[] args) throws CloneNotSupportedException {
  27. CloneTest ct0 = new CloneTest();
  28. A a = new A();
  29. a.setV(66);
  30. ct0.setV_a(a);
  31. CloneTest ct1 = (CloneTest)ct0.clone();
  32. ct1.print_v_a();
  33. a.setV(88);
  34. ct0.setV_a(a);
  35. ct1.print_v_a();
  36. }
  37. }

上面这个例子就体现出了浅拷贝的弱点,输出为66 88。

ct1是浅拷贝的ct0,此时ct0的v_a(成员变量,A对象)的v值为66。拷贝后,ct1的v_a(A对象的v)输出也是66。然后重设ct0的v_a(A对象的v)为88,再输出ct1的v_a(A对象的v),竟然也是88。说明二者的引用指向的是同样的堆内存。

浅拷贝情况下,两个对象的成员变量(A对象)引用的是同一个堆内存,并没有完全实现拷贝后内存独立。

这种情况就需要深拷贝。

例如文章最开始提到的ArrayList的clone()的写法。

java的clone()、浅拷贝与深拷贝的更多相关文章

  1. 【转】JAVA中的浅拷贝和深拷贝

    原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...

  2. java中的浅拷贝和深拷贝

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

  3. java中的浅拷贝与深拷贝

    浅拷贝: package test; class Student implements Cloneable { private int number; public int getNumber() { ...

  4. Java对象的浅拷贝和深拷贝&&String类型的赋值

    Java中的数据类型分为基本数据类型和引用数据类型.对于这两种数据类型,在进行赋值操作.方法传参或返回值时,会有值传递和引用(地址)传递的差别. 浅拷贝(Shallow Copy): ①对于数据类型是 ...

  5. java引用类型的浅拷贝与深拷贝理解

    1.浅拷贝 只会复制地址值,也就是同一个对象两个引用,只是复制了一个引用而已. 2.深拷贝 重新在堆里创建一个新对象给新引用,连同地址值也不一样. 首先要知道Object的clone()方法, pub ...

  6. 【Java】 Java中的浅拷贝和深拷贝

    先抛出结论: 浅拷贝是引用拷贝,A对象拷贝B以后,A对象和B对象指向同一块内存地址,改变A对象的属性值会触发B对象属性的改变,有安全风险 深拷贝是对象拷贝,A对象拷贝B以后,A对象和B对象指向不同的额 ...

  7. Java 数组的浅拷贝和深拷贝

    浅拷贝: 在堆内存中不会分配新的空间,而是增加一个引用变量和之前的引用指向相同的堆空间. int[] a = {1,2,3,4,5}; int[]b = a; public class Test { ...

  8. java 浅拷贝和深拷贝 对象克隆clone

    分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...

  9. 浅拷贝和深拷贝(谈谈java中的clone)

    clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那么在java语言中,有 ...

  10. Java中的clone方法-理解浅拷贝和深拷贝

    最近学到Java虚拟机的相关知识,更加能理解clone方法的机制了 java中的我们常常需要复制的类型有三种: 1:8种基本类型,如int,long,float等: 2:复合数据类型(数组): 3:对 ...

随机推荐

  1. 【LCA最近公共祖先】在线离线

    [在线] 1.倍增法 现将深度较大的跳至与深度较小的统一深度.预处理$fa[u][i]$表示$u$往上跳$2^i$个单位后的祖先,则就可以像快速幂一样,将移动的步数化为二进制,如果第$i$位为$1$, ...

  2. spark action之countbykey

    java public class CountByKeyDemo { private static SparkConf conf = new SparkConf().setMaster("l ...

  3. 【足迹C++primer】49、超载,更改,运营商

    超载,更改.运营商 Conversion Operators 转换操作符 operator type() const Conversions to an array or a function typ ...

  4. 移动应用拉起微信小程序

    APP支持打开微信小程序了 最新微信文档 如何实现APP打开小程序 通过文档打开微信开放平台添加移动应用,然后关联小程序,这些步骤按照文档描述走. IOS开发示例参考 android开发示例参考 开发 ...

  5. dzone Cloud Zone

    dzone Cloud Zonehttps://dzone.com/cloud-computing-tutorials-tools-news有一些统计:https://dzone.com/refcar ...

  6. 利用WPF建立自己的3d gis软件(非axhost方式)(八)拖动一个UI到地球上

    原文:利用WPF建立自己的3d gis软件(非axhost方式)(八)拖动一个UI到地球上 先下载SDK:https://pan.baidu.com/s/1M9kBS6ouUwLfrt0zV0bPew ...

  7. Struts2——(3)ValueStack(值栈)

    一.ValueStack 主要用于存储请求相关信息,内部结构如下 root区:被称为根存储区,是一个栈结构,栈顶元素为当前请求的Action对象. context区:被称为变量存储区,是一个Map结构 ...

  8. Cordova 返回键切换后台

    这里需要用到 cordova-plugin-backbutton 这个插件 1.安装插件,命令窗口输入(当前目录是你项目所在的目录) cordova plugin add cordova-plugin ...

  9. 国产操作系统剽窃Linux内核可耻!

    10月28日,新浪科技发表文章,题为"国产操作系统迎来利好:部委机构正大量採购",读后有感. 如今,国家进入法制时代.政府採购"国产操作系统",似乎成为一种&q ...

  10. oracle 数组

    定义一个长度为5的字符串数组 type str_array is varray(5) of varchar2(30); v_str_array str_array := expr_key_array( ...