在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. .NET面试

    作者:最佳菜鸟链接:https://zhuanlan.zhihu.com/p/22224795来源:知乎著作权归作者所有.商业转载请联系作者获得授权,非商业转载请注明出处. 1 .术语 面试出现频率: ...

  2. C#操作AD及Exchange Server总结(二)

    上一节C#操作AD及Exchange Server总结(一)写了对AD的操作,新建AD用户后,通常都需要为此用户开启Exchange邮箱,接下来写如何远程操作Exchange. 三.对Exchange ...

  3. pro_select_roleinfo_p3

    DELIMITER | drop procedure if exists pro_select_roleinfo_p3; CREATE PROCEDURE pro_select_roleinfo_p3 ...

  4. Ansi、GB2312、GBK、Unicode(utf8、16、32)

    关于ansi,一般默认为本地编码方式,中文应该是gb编码 他们之间的关系在这边文章里描写的很清楚:http://blog.csdn.net/ldanduo/article/details/820353 ...

  5. 阻塞IO 非阻塞IO 异步IO

    阻塞IO 一般表现为 进程/线程 调用IO操作后就一直死循环等待,直至IO操作结束,返回IO结果 非阻塞IO 一般表现为 进程/线程 调用IO操作后,可以先去干别的事情,但是每隔一段时间,回去询问一下 ...

  6. django的cookie和session以及缓存

    cookie和session cookie和session的作用: cookie和session都记录了客户端的某种状态,用来跟踪用户访问网站的整个回话.两者最大的区别是cookie的信息是存放在浏览 ...

  7. java 遍历map的方法

    package com.jackey.topic; import java.util.ArrayList;import java.util.HashMap;import java.util.Itera ...

  8. JVM虚拟机—JVM内存

    JVM在运行时将数据划分为了5个区域来存储,这5个区域图示如下: 其中方法区和堆对是所有线程共享的内存区域:而java栈.本地方法栈和程序员计数器是运行时线程私有的内存区域. 首先我们熟悉一下一个 J ...

  9. C/C++中浮点数输出格式问题

    在C语言中,浮点数的输出格式有三种:%g, %f, %e 首先要说的是%e是采用科学计数法来显示. %g与后两者有一个重要的差别,就是设置输出精度的时候,(C中默认浮点输出精度是6),%g认为,包括整 ...

  10. (转)牛B的代码不一定是好代码

    最近经常做业务逻辑代码review的工作,发现各种风格的代码,其中有一种是封装和抽象做的非常的多,代码层次非常的深入,表面给人感觉是:牛逼的代码. 但是从清晰度和可维护性来说,还是不推荐这么做. 1. ...