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()

    /**
* Returns a shallow copy of this <tt>ArrayList</tt> instance. (The
* elements themselves are not copied.)
*
* @return a clone of this <tt>ArrayList</tt> instance
*/
public Object clone() {
try {
ArrayList<?> v = (ArrayList<?>) super.clone();
v.elementData = Arrays.copyOf(elementData, size);
v.modCount = 0;
return v;
} catch (CloneNotSupportedException e) {
// this shouldn't happen, since we are Cloneable
throw new InternalError(e);
}
}

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

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

package a;

public class CloneTest  implements Cloneable {
private int v_a;
public void setV_a(int v) {
v_a = v;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void print_v_a() {
System.out.println(v_a);
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneTest ct0 = new CloneTest();
ct0.setV_a(66);
CloneTest ct1 = (CloneTest)ct0.clone();
ct1.print_v_a();
ct0.setV_a(88);
ct1.print_v_a();
ct0.print_v_a();
}
}

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

package a;

import java.util.Arrays;

class A {
private int v;
public void setV(int v) {
this.v = v;
}
public void p_v() {
System.out.println(v);
}
} public class CloneTest implements Cloneable {
private A v_a;
public void setV_a(A v) {
v_a = v;
}
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public void print_v_a() {
v_a.p_v();
}
public static void main(String[] args) throws CloneNotSupportedException {
CloneTest ct0 = new CloneTest();
A a = new A();
a.setV(66);
ct0.setV_a(a);
CloneTest ct1 = (CloneTest)ct0.clone();
ct1.print_v_a();
a.setV(88);
ct0.setV_a(a);
ct1.print_v_a();
}
}

上面这个例子就体现出了浅拷贝的弱点,输出为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. Linux中export导入环境变量的几种方式

    1.首先类似于windows中的设定系统环境变量的方式为,在/etc/profile中 export PATH=$PATH:....:... 注意间隔符为: 然后复用原来路径是$PATH的方式 2.用 ...

  2. QT类库与Delphi VCL类库的体系结构对比——两者十分类似!

    今天在看QT对象内存管理的一篇文章时:http://blog.csdn.net/dbzhang800/article/details/6300025想到了一个问题:就是QT类库体系结构与Delphi类 ...

  3. Erlang类型及函数声明规格

    http://erlangdisplay.iteye.com/blog/404570 Erlang类型及函数声明规格 Author: Mail: Date: Copyright: litaocheng ...

  4. 用决策树模型求解回归问题(regression tree)

    How do decision trees for regression work? 决策树模型既可以求解分类问题(对应的就是 classification tree),也即对应的目标值是类别型数据, ...

  5. Android高度仿新浪微博引导页面

    在写这一篇文章之前,先向大家推荐一篇博文:http://blog.csdn.net/dawanganban/article/details/17297671 感谢这位博主,我在该博主的基础上完成了对新 ...

  6. vue: 关于多路由公用模板,导致组件内数组缓存问题

    当多个路由复用同一个模板,此时在这几个路由间切换,模板并不会重新挂载.针对这个情况,我们需要在当前逻辑内对路由做监听,在发生变化时更新对应属性,已满足需求. 但是,在实现的过程中会遇到如下情况: 如图 ...

  7. Msg DisPatch

    一天写了个Carlife 协议数据分流器 #include <stdio.h> #include <string.h> typedef unsigned char uint8_ ...

  8. Android开发之 shape的使用

    android shape的使用 shape用于设定形状,能够在selector,layout等里面使用,有6个子标签,各属性例如以下: <?xml version="1.0" ...

  9. VS2010设置VC6的字体样式及背景色、选中字高亮

    习惯了VC6.0的fixedsys字体,用VS2010还真不习惯.把VS2010打造成经典的.熟悉的模样,也并非难事.网上有相应的文章,我再记录下来,主要是为了自己查找方便(刚刚重装了系统,一切从头再 ...

  10. Retrieving data from a server

    A system includes a server and a controller embedded in a device. Both the server and the embedded c ...