前言
常见的创建对象有两种方式: new 和 clone
当一个对象创建过程复杂,我们是否可以根据已有的对象直接来克隆一份,而不必关系创建的细节呢(原型模式)。
1、实现 Cloneable 接口,重写 clone 方法
Object 默认的 clone 方法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝;
对于复杂类型的字段,则是指针地址的拷贝,clone 后的对象和原对象指向的还是一个地址空间。
所以说默认的 clone 方法是浅克隆。我们用下面例子验证一下:
执行结果:
这种克隆方式显然表示原始对象和克隆对象的 Car 是同一个 引用。也就是说,Car 对象没有被克隆。如果修改了 Car 对象的值,原始对象和克隆对象都将会发生变化。这并不是我们希望看到的。
所以,我们需要连对象里面的对象也要是一个新的对象。每一个属性都被完全拷贝,这才是深克隆。
为了实现深度克隆,我们需要对 Person 中的 clone 方法进行改造一下,getCar() 测试代码不变。
再次进行测试:
这么做就要在 super.clone 的基础上 继续对非基本类型的对象递归地再次 clone.
显然这么方式是繁琐的且不可靠的。
2、实现序列化接口
2.1 使用 java 自身的序列化转为二进制数 ,再反序列化为对象
ObjectStream 序列化的工具类
测试类:
运行结果:
其他方式还可以是用序列化工具如 fastjson 进行序列化和反序列化进行对象 clone。
2.2 fastjson 序列化
Maven 依赖
Car 类:
Person 类
运行结果:
总结:
实现对象克隆主要有两种方式:
1、实现 Cloneable 接口并重写其中的 clone() 方法完成对象的浅拷贝
- Object 默认的 clone 方法实际是对域的简单拷贝,对于简单数据类型,是值的拷贝;
- 对于复杂类型的字段,则是指针地址的拷贝,clone 后的对象和原对象指向的还是一个地址空间。
- 所以说默认的 clone 方法是浅克隆。
- 想要实现深克隆需要复杂类实现中为每个类都实现 Cloneable 接口并重写 clone 方法(复杂类中的对象也要是新的对象)这么做就要在 super.clone 的基础上 继续对非基本类型的对象递归的再次 clone.
- 显然这么方式是繁琐的且不可靠的。
2、实现序列化接口 Serializable,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆。
- 基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是通过编译器完成的,
- 不是在运行时抛出异常,这汇总方案明显优于使用 Object 类的 clone 方法克隆对象。让问题在编译的时候暴露出来中是好过把问题留到运行时。