java的clone()、浅拷贝与深拷贝
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()、浅拷贝与深拷贝的更多相关文章
- 【转】JAVA中的浅拷贝和深拷贝
原文网址:http://blog.bd17kaka.net/blog/2013/06/25/java-deep-copy/ JAVA中的浅拷贝和深拷贝(shallow copy and deep co ...
- java中的浅拷贝和深拷贝
复制 将一个对象的引用复制给另一个对象,一共有三种方式.第一种方式是直接赋值,第二种方式是浅复制,第三种方式是深复制. 1.直接赋值 在Java中,A a1 = a2,这实际上复制的是引用,也就是说 ...
- java中的浅拷贝与深拷贝
浅拷贝: package test; class Student implements Cloneable { private int number; public int getNumber() { ...
- Java对象的浅拷贝和深拷贝&&String类型的赋值
Java中的数据类型分为基本数据类型和引用数据类型.对于这两种数据类型,在进行赋值操作.方法传参或返回值时,会有值传递和引用(地址)传递的差别. 浅拷贝(Shallow Copy): ①对于数据类型是 ...
- java引用类型的浅拷贝与深拷贝理解
1.浅拷贝 只会复制地址值,也就是同一个对象两个引用,只是复制了一个引用而已. 2.深拷贝 重新在堆里创建一个新对象给新引用,连同地址值也不一样. 首先要知道Object的clone()方法, pub ...
- 【Java】 Java中的浅拷贝和深拷贝
先抛出结论: 浅拷贝是引用拷贝,A对象拷贝B以后,A对象和B对象指向同一块内存地址,改变A对象的属性值会触发B对象属性的改变,有安全风险 深拷贝是对象拷贝,A对象拷贝B以后,A对象和B对象指向不同的额 ...
- Java 数组的浅拷贝和深拷贝
浅拷贝: 在堆内存中不会分配新的空间,而是增加一个引用变量和之前的引用指向相同的堆空间. int[] a = {1,2,3,4,5}; int[]b = a; public class Test { ...
- java 浅拷贝和深拷贝 对象克隆clone
分一下几点讨论: 为什么要克隆? 如何实现克隆 浅克隆和深克隆 解决多层克隆问题 总结 一:为什么要克隆? 大家先思考一个问题,为什么需要克隆对象?直接new一个对象不行吗? 答案是:克隆的对象可能包 ...
- 浅拷贝和深拷贝(谈谈java中的clone)
clone顾名思义就是复制, 在Java语言中, clone方法被对象调用,所以会复制对象.所谓的复制对象,首先要分配一个和源对象同样大小的空间,在这个空间中创建一个新的对象.那么在java语言中,有 ...
- Java中的clone方法-理解浅拷贝和深拷贝
最近学到Java虚拟机的相关知识,更加能理解clone方法的机制了 java中的我们常常需要复制的类型有三种: 1:8种基本类型,如int,long,float等: 2:复合数据类型(数组): 3:对 ...
随机推荐
- 新技能 get —— Python 断点续传下载文件
from urllib.request import urlretrieve import sys import os prev_reported_download_percent = None # ...
- CocoaPods详解之(一)----使用篇
CocoaPods详解之----使用篇 作者:wangzz 原文地址:http://blog.csdn.net/wzzvictory/article/details/18737437 一.什么是Coc ...
- erlang应用发布
http://blog.csdn.net/zhangxinrun/article/details/6993892 参考“转载1”和“转载2”就可以了,但需要注意以下两点: 1.如果用rebar - c ...
- 学习鸟哥的Linux私房菜笔记(1)——Linux系统入门
今天在阿里云申请了一个centos系统的云服务器,以前对linux了解的只是皮毛,记了几个命令还给忘了,整了半天都弄不好,作为一个做过javaweb开发的coder实在是惭愧啊,决定从今天开始学习Li ...
- cordova-plugin-android-update安卓版本更新插件使用
原文:cordova-plugin-android-update安卓版本更新插件使用 安装插件,使用方法官方都有. 安卓7.0以上要在AndroidMainfest.xml里加一句 <uses- ...
- Arcgis api for javascript学习笔记(4.5版本)-三维地图的飞行效果
其实就只是用到了 view.goTo() 函数,再利用 window.setInterval() 函数(定时器)定时执行goTo().代码如下: <!DOCTYPE html> < ...
- 继承之重写prototype
function Ff(){} //undefined Ff.prototype={a:"ss"} //Object {a: "ss"} var f1= new ...
- Matlab Tricks(十八)—— 矩阵间元素距离的计算
两个矩阵间元素(向量)距离的度量,首先想到的是遍历,循环的方式,显然 matlab 下的编程并不推荐,matlab 下矩阵向量化编程效率尤高. 先考虑两个向量距离的计算: ∥x−y∥2=∥x∥2+∥y ...
- 写一个去除AI2XAML注释及多余数字位数的WPF窗体程序
原文:写一个去除AI2XAML注释及多余数字位数的WPF窗体程序 使用正则表达式去除多余注释及冗余数字位,关键代码: string pattern = @"/b(/d+ ...
- 局部QEventLoop帮助QWidget不消失(也就是有一个局部事件循环始终在运行,导致程序被卡住那里,但仍可以接受事件。说白了就是有一个while语句死活不肯退出,直到收到退出信号)
熟悉的陌生人 Qt 是事件驱动的,所以当你用Qt的时候,几乎时时刻刻和 QEventLoop 打交道.,只是你可能没有意识到: QCoreApplicaton::exec() QApplication ...