在Java语言中,数据类型分为值类型(基本数据类型)和引用类型,值类型包括int、double、byte、boolean、char等简单数据类型,引用类型包括类、接口、数组等复杂类型。

浅克隆和深克隆的主要区别在于是否支持引用类型的成员变量的复制,下面将对两者进行详细介绍。

浅clone:

在浅克隆中,如果原型对象的成员变量是值类型,将复制一份给克隆对象;如果原型对象的成员变量是引用类型,则将引用对象的地址复制一份给克隆对象,也就是说原型对象和克隆对象的成员变量指向相同的内存地址。

简单来说,在浅克隆中,当对象被复制时只复制它本身和其中包含的值类型的成员变量,而引用类型的成员对象并没有复制。

示意如下图:

Object类中的native clone方法提供了浅clone的支持。可以实现Cloneable接口并调用Object的clone方法为一个类实现浅clone:

public static void main(String[] args) throws CloneNotSupportedException {

        Foo f1 = new Foo(1, new Bar(0));
Foo f2 = f1.clone(); System.out.println(f1);
System.out.println(f2); f1.id = 2;
f1.bar.setId(2); System.out.println(f1);
System.out.println(f2); } public static class Foo implements Cloneable { private int id; private Bar bar; public Foo(int id, Bar bar) {
this.id = id;
this.bar = bar;
} @Override
public Foo clone() throws CloneNotSupportedException {
return (Foo) super.clone();
} @Override
public String toString() {
return "Foo{" +
"id=" + id +
", bar=" + bar +
'}';
}
} public static class Bar implements Cloneable { private int id; public Bar(int id) {
this.id = id;
} public void setId(int id) {
this.id = id;
} @Override
public String toString() {
return "Bar{" +
"id=" + id +
'}';
}
}

程序的执行结果如下:

Foo{id=1, bar=Bar{id=0}}
Foo{id=1, bar=Bar{id=0}}
Foo{id=2, bar=Bar{id=2}}
Foo{id=1, bar=Bar{id=2}}

在示例程序中改变了f1的引用变量成员bar的值,f2的成员变量bar也受到了影响。不过改变了f1的直接类型成员id的值,f2却没有受影响。

可知:浅clone只能clone成员变量中直接类型的值,对于应用类型的值则是clone了引用对象的地址。

深clone:

在深克隆中,无论原型对象的成员变量是值类型还是引用类型,都将复制一份给克隆对象,深克隆将原型对象的所有引用对象也复制一份给克隆对象。

简单来说,在深克隆中,除了对象本身被复制外,对象所包含的所有成员变量也将复制。

示意如下图:

要让我们上面的程序支持深clone,需要对其做些调整:

首先需要给Bar类也添加clone方法的支持:

public static class Bar implements Cloneable {

        private int id;

        public Bar(int id) {
this.id = id;
} public void setId(int id) {
this.id = id;
} @Override
public String toString() {
return "Bar{" +
"id=" + id +
'}';
} @Override
public Bar clone() throws CloneNotSupportedException {
return (Bar) super.clone();
}
}

而后修改Foo类的clone方法:

@Override
public Foo clone() throws CloneNotSupportedException {
Foo f = (Foo) super.clone();
f.bar = bar.clone();
return f;
}

执行结果如下:

Foo{id=1, bar=Bar{id=0}}
Foo{id=1, bar=Bar{id=0}}
Foo{id=2, bar=Bar{id=2}}
Foo{id=1, bar=Bar{id=0}}

此时f2不再受到f1的影响了。

此时再继续想一下,如果Bar中还有引用类型成员呢,如果Bar中的引用类型成员也有自己的引用类型成员,那么该怎么办呢?

挺好解决的事情,懒得解释了。

java对象的深浅clone的更多相关文章

  1. Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    Java对象克隆(Clone)及Cloneable接口.Serializable接口的深入探讨 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的克隆,就不得不说为什么 ...

  2. (转)Java对象克隆(Clone)及Cloneable接口、Serializable接口的深入探讨

    原文地址:http://blog.csdn.net/kenthong/article/details/5758884 Part I 没啥好说的,直接开始Part II吧. Part II 谈到了对象的 ...

  3. 关于Java的Object.clone()方法与对象的深浅拷贝

    文章同步更新在个人博客:关于Java的Object.clone()方法与对象的深浅拷贝 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Object.clon ...

  4. java对象转json应clone,避免生成json串有问题

    今天因为一个java对象转json,搞了我一下午,在些记录一下: 是这样:我在strtuts2的action中调用services返回 Row: 26, 中国银行海鹰, 29, 东楼, 36, 1F ...

  5. Object.clone()方法与对象的深浅拷贝

    转载:[https://www.cnblogs.com/nickhan/p/8569329.html] 引言 在某些场景中,我们需要获取到一个对象的拷贝用于某些处理.这时候就可以用到Java中的Obj ...

  6. Java对象的克隆和深浅问题

    Java实现克隆的方式 Java实现克隆的方式有如下两种, 推荐采用实现Cloneable接口的方式 实现Cloneable接口, 重写clone方法, 调用父类的clone方法 还有另一种方法, 不 ...

  7. java对象clone

    java克隆 为什么需要克隆 我们在很多时候需要使用一个对象去记录另外一个对象的当前状态,对象中可能会有很多属性,如果我们一个一个去设置,不仅不方便,而且效率很低,我们看一个初学者可能遇到的问题 cl ...

  8. java对象比较器和克隆

    一.比较器Comparable和Comparator 上一篇博客介绍了工具类Arrays工具类 .我们可以对基本类型的数组调用Arrays.sort()函数来进行数组的排序.排序操作在日常开发中经常要 ...

  9. JAVA 对象拷贝

    1.java里的clone分为:  A:浅复制(浅克隆): 浅复制仅仅复制所考虑的对象,而不复制它所引用的对象.  b:深复制(深克隆):深复制把要复制的对象所引用的对象都复制了一遍.  Java中对 ...

随机推荐

  1. python中,有关正则表达式re函数:compile、match、search、findall

    1.全局匹配函数 re.compile(pattern=pattern,re.S).findall(text)函数: compile 函数根据一个模式字符串和可选的标志参数生成一个正则表达式对象.该对 ...

  2. delphi--自带控件(Tcheckbox、TComBobox、TpageControl、TDBGrid,TScrollBox,TEdit)

    一.TCheckBox 使CheckBox选中CheckBox1.Checked := True;选择发生变化 ,OnClick事件if CheckBox1.Checked thenbegin //. ...

  3. 10.php引用(&)详解及注意事项

    <?php function &test() { static $b=0;//申明一个静态变量 $b=$b+1; echo $b; return $b; } $a=test();//这条 ...

  4. 如何基于Go搭建一个大数据平台

    如何基于Go搭建一个大数据平台 - Go中国 - CSDN博客 https://blog.csdn.net/ra681t58cjxsgckj31/article/details/78333775 01 ...

  5. Eclipse 介绍

    设置背景的插件: Darkest Dark Theme 添加 properties 插件: Properties Editor Git 插件: Egit 常用快捷键 command + 1 : 代码提 ...

  6. c++智能指针,new之后不需要delete,简单的垃圾回收

    http://www.cnblogs.com/TenosDoIt/p/3456704.html 智能指针的初始化: 错误: std::shared_ptr<Serializer> seri ...

  7. Redis2.8配置文件详解(转)

    add by zhj : 没找到本文的原文.另外,redis配置文件中文翻译 也翻译的不错,可以与本文对照看.两篇文章都是以Redis2.8来介绍的 在Redis中直接启动redis-server服务 ...

  8. 服务器(Ubuntu)远程访问ipython notebook(服务器运行ipython notebook 本地浏览器访问)

    准备工作 首先要安装 ipython 推荐直接 Anaconda 搞起(装在服务器). Anaconda 帮你集成N多python相关环境(包),省得你再手动咔咔一顿安装 服务器启动ipython n ...

  9. 007-Centos 7.x 安装 Mysql 5.7.13

    1. 下载mysql的repo源 CentOS 7.2的yum源中默认没有mysql,要先下载mysql的repo源 wget http://repo.mysql.com/mysql57-commun ...

  10. Grunt JS构建环境搭建以及使用入门

    Grunt JS构建环境搭建以及使用入门 1.应用场景 一种自动化任务处理工具,对于日常的需求(代码规则检查.代码合并)可以实现自动化执行,只需要保留package.json和Gruntfile.js ...