对象的创建方式:浅拷贝和深拷贝
前言
今天面试了一家公司,问到了一个面试题:对象的创建方式,我只想到了一个new关键字来创建,面试结束一查才恍然大悟,对象的创建方式不止是使用new来创建,还可以使用拷贝的方式,而拷贝又分为浅拷贝和深拷贝,我们来详细了解一下。
一、值传递和引用传递
在将浅拷贝之前,我们首先来讲一下值传递和引用传递吧,我来说一下我的理解,值传递和引用传递是数据复制的方式。
值传递:值传递是传递参数和原变量的数据相同,但存储位置不同,两者完全独立,不会相互影响(基本数据类型和String都是值传递,因为String类型数据底层由final修饰的字符数组常量,因此当字符串改变时会指向新的字符串的地址,并不会影响原数据的内存地址)
引用传递:引用传递指的是传递参数和原变量指向同一块内存地址,当有一方数据改变时,会影响另一块数据
二、浅拷贝和深拷贝的理解
1 浅拷贝
复制的对象和原对象的基本数据类型是值传递,引用数据类型是引用传递,共用同一个引用(即指向同一块内存地址),当有一方数据修改时另一方会受到影响。
2.深拷贝
复制的对象和原对象的基本数据类型是值传递,引用数据类型不是引用传递,而是创建一个对象,复制原对象的引用数据,但是指向不同的内存地址,它们之间完全对立,不会收到影响。
三、代码验证和实现
3.1 浅拷贝的代码实现
我使用的是StringUtils类的copyProperties实现浅拷贝
导入依赖以及代码实现
<dependency>
<groupId>commons-beanutils</groupId>
<artifactId>commons-beanutils</artifactId>
<version>1.9.4</version>
</dependency>
结果分析
浅拷贝的复制对象和原对象地址相同,它们的基本数据类型变量和引用数据类型变量相同,且引用数据指向的地址相同,当引用数据改变后,另一方数据也会改变。
3.2 深拷贝的代码实现
一、实现cloneable接口
结果分析
我们发现通过深克隆出来的对象和原对象的地址不同,它们的引用数据类型指向的内存地址也不同,当有一方的基本数据和引用数据发生改变时,另一方不会受到影响。
实现Cloneable接口并重写方法的缺点
当对象实现接口并重写克隆方法后,如果对象中含有其他对象,那么这个对象将会是浅克隆,因此需要让内部的所有对象都实现克隆接口并重写克隆方法,但是如果要被克隆的对象嵌套了很多对象,那么实现克隆将会异常的麻烦