在最近的秋招中,阿里和多益网络都问到了这个问题,虽然很简单,但是我还是想总结一下,感兴趣的可以看一下我的个人博客网站(Spring+MyBatis+redis+nginx+mysql)(适合菜鸟),最近会抽空把最近面试遇到的问题总结一下。

本文针对问题:深克隆和浅克隆的区别和实现方式?(阿里电面,多益网络的选择题)

Talk is cheap

最近不止一次遇见深浅克隆(深复制,浅复制)的问题,除了印象中有个clone方法外一脸懵逼!!!克隆(复制)在Java中是一种常见的操作,目的是快速获取一个对象副本。克隆分为深克隆和浅克隆。

浅克隆:创建一个新对象,新对象的属性和原来对象完全相同,对于非基本类型属性,仍指向原有属性所指向的对象的内存地址。

深克隆:创建一个新对象,属性中引用的其他对象也会被克隆,不再指向原有对象地址。

总之深浅克隆都会在堆中新分配一块区域,区别在于对象属性引用的对象是否需要进行克隆(递归性的)。

Show you my picture

pos:当前对象的地址;

son:son属性所指向的地址;

name:对象的name属性。

Show you my code

case1:

public class Son implements Serializable , Cloneable{
private String name;
private Son son;
public Son() {
super();
}
public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public Son getSon() {
return son;
} public void setSon(Son son) {
this.son = son;
} @Override
public String toString() {
return super.toString();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}

测试

public static void main(String[] args) throws Exception{
// 创建父亲(LiLiu),儿子(LiWu),孙子(LiLiu)并关联
Son father = new Son();
father.setName("LiSi");
Son son = new Son();
son.setName("LiWu");
Son grandSon = new Son();
grandSon.setName("LiLiu");
father.setSon(son);
son.setSon(grandSon);
// 调用clone方法
Son fatherCopy = (Son) father.clone();
boolean flag1 = fatherCopy==father;
boolean flag2 = fatherCopy.getSon() == son;
boolean flag3 = fatherCopy.getSon().getSon() == grandSon;
// 比较克隆后的地址
System.out.println(flag1);// false
System.out.println(flag2);// true
System.out.println(flag3);// true
// 比较Name
flag1= fatherCopy.getName()==father.getName();
flag2 = fatherCopy.getSon().getName() == son.getName();
flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();
System.out.println(flag1);// true
System.out.println(flag2);// true
System.out.println(flag3);// true //将对象写到流里
ByteArrayOutputStream byteOut=new ByteArrayOutputStream();
ObjectOutputStream objOut=new ObjectOutputStream(byteOut);
objOut.writeObject(father);
//从流里读出来
ByteArrayInputStream byteIn=new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream objInput=new ObjectInputStream(byteIn);
fatherCopy = (Son) objInput.readObject();
flag1= fatherCopy==father;
flag2 = fatherCopy.getSon() == son;
flag3 = fatherCopy.getSon().getSon() == grandSon;
System.out.println(flag1);// false
System.out.println(flag2);// false
System.out.println(flag3);// false // 比较Name
flag1= fatherCopy.getName()==father.getName();
flag2 = fatherCopy.getSon().getName() == son.getName();
flag3 = fatherCopy.getSon().getSon().getName() == grandSon.getName();
System.out.println(flag1);// false
System.out.println(flag2);// false
System.out.println(flag3);// false
}

从上文代码及运行结果不难看出,如果对象实现Cloneable并重写clone方法不进行任何操作时,调用clone是进行的浅克隆。而使用对象流将对象写入流然后再读出是进行的深克隆。

思考:既然实现Cloneable接口并重写clone接口只能进行浅克隆。但是如果类的引用类型属性(以及属性的引用类型属性)都进行浅克隆,直到没有引用类型属性或者引用类型属性为null时,整体上就形成了深克隆。既对象的引用类型属性和属性的应用类型属性都实现Coloneable,重写clone方法并在clone方法中进行调用。

protected Object clone() throws CloneNotSupportedException {
Son result = (Son) super.clone();
if (son != null) {
result.son = (Son) son.clone();
}
return result;
}

说几句废话

个人认为,在选择深克隆方法时,应根据对象的复杂程度,如引用类型属性是否有多层引用类型属性关系。如果对象只有一层或者两层引用类型的属性,选择思考中所提到的方法较为方便,反之则使用对象流。

浅谈Java中的深克隆和浅克隆(阿里面试)的更多相关文章

  1. 浅谈Java中的equals和==(转)

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: 1 String str1 = new String("hello"); 2 String str ...

  2. 浅谈Java中的对象和引用

    浅谈Java中的对象和对象引用 在Java中,有一组名词经常一起出现,它们就是“对象和对象引用”,很多朋友在初学Java的时候可能经常会混淆这2个概念,觉得它们是一回事,事实上则不然.今天我们就来一起 ...

  3. 浅谈Java中的equals和==

    浅谈Java中的equals和== 在初学Java时,可能会经常碰到下面的代码: String str1 = new String("hello"); String str2 = ...

  4. 浅谈Java中的深拷贝和浅拷贝(转载)

    浅谈Java中的深拷贝和浅拷贝(转载) 原文链接: http://blog.csdn.net/tounaobun/article/details/8491392 假如说你想复制一个简单变量.很简单: ...

  5. 浅谈Java中的深拷贝和浅拷贝

    转载: 浅谈Java中的深拷贝和浅拷贝 假如说你想复制一个简单变量.很简单: int apples = 5; int pears = apples; 不仅仅是int类型,其它七种原始数据类型(bool ...

  6. 【转】浅谈Java中的hashcode方法(这个demo可以多看看)

    浅谈Java中的hashcode方法 哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native i ...

  7. 浅谈Java中的final关键字

    浅谈Java中的final关键字 谈到final关键字,想必很多人都不陌生,在使用匿名内部类的时候可能会经常用到final关键字.另外,Java中的String类就是一个final类,那么今天我们就来 ...

  8. 【转】浅谈Java中的hashcode方法

    哈希表这个数据结构想必大多数人都不陌生,而且在很多地方都会利用到hash表来提高查找效率.在Java的Object类中有一个方法: public native int hashCode(); 根据这个 ...

  9. 浅谈Java中的栈和堆

    人们常说堆栈堆栈,堆和栈是内存中两处不一样的地方,什么样的数据存在栈,又是什么样的数据存在堆中? 这里浅谈Java中的栈和堆 首先,将结论写在前面,后面再用例子加以验证. Java的栈中存储以下类型数 ...

随机推荐

  1. Linux中的do{...} while(0)

    摘抄自: <<Linux设备驱动开发详解(第二版)>> 在 Linux 内核中,经常会看到do{} while(0)这样的语句,许多人开始都会疑惑,认为do{} while(0 ...

  2. Oracle-归档日志详解(运行模式、分类)

    一.Oracle日志分类 分三大类: Alert log files--警报日志,Trace files--跟踪日志(用户和进程)和            redo log 重做日志(记录数据库的更改 ...

  3. 20155216 Exp8 WEB基础实践

    Exp8 WEB基础实践 实践内容 Apache环境配置 apache是kali下的web服务器,通过访问 ip地址+端口号+文件名称 打开对应的网页. 输入命令 vi /etc/apache2/po ...

  4. Spring集成Swagger,Java自动生成Api文档

    博主很懒... Swagger官网:http://swagger.io GitHub地址:https://github.com/swagger-api 官方注解文档:http://docs.swagg ...

  5. CS229笔记:生成学习算法

    在线性回归.逻辑回归.softmax回归中,学习的结果是\(p(y|x;\theta)\),也就是给定\(x\)的条件下,\(y\)的条件概率分布,给定一个新的输入\(x\),我们求出不同输出的概率, ...

  6. 蓝牙学习笔记二(Android连接问题)

    可以通过以下两点加速蓝牙连接: 1.更新连接参数 interval:连接间隔(connection intervals ),范围在 7.5 毫秒 到 4 秒. latency:连接延迟 ... 还有一 ...

  7. 6、Docker图形化管理(Portainer)

    一.Portainer简介 Portainer是Docker的图形化管理工具,提供状态显示面板.应用模板快速部署.容器镜像网络数据卷的基本操作(包括上传下载镜像,创建容器等操作).事件日志显示.容器控 ...

  8. C#字符串截取、获取当前电脑时间、判断输入日期对错 随手记

    字符串截取:这个就当复习了,看意见就可以 //身份证生日截取 //Console.WriteLine("请输入18位身份证号:"); //string x = Console.Re ...

  9. Python能做什么?

    Python作为一个功能强大,并且简单易学的编程语言而广受好评,那么Python都能做些什么呢?概括起来有以下几个方面: 1.Web开发: 2.大数据处理: 3.人工智能: 4.自动化运维: 5.云计 ...

  10. App云测试服务对比

    前言: 我们都知道在测试移动app时最耗时的是在各种测试设备进行测试, 因为不论是安卓还是iOS都已经碎片化了.而云测试看似是解决这一问题的有效途径.因此选择哪种云测试平台来协助测试人员进行各种测试就 ...