Java编程中实现独立于原对象的新对象复制方法探究
在编程实践时,我们会碰到这样的需求:在某一时刻存在一个对象 A,它里面已经有了有效值,这时需要创建一个新对象 B,这个新对象 B 要和 A 完全一样,并且要保证对 B 的任何改动都不会对 A 中的值产生影响。这意味着 A 和 B 是两个相互独立的对象,B 的初始值是由 A 对象来确定的。比如程序所演示的那种情况:

结果:
>学生1:54321
>学生2:54321
为什么改变学生2的学号,学生1的学号也发生了变化呢?
原因是 stu2 等于 stu1。这样的操作把 stu1 的引用赋给了 stu2,使得 stu1 和 stu2 都指向了内存堆里的同一个对象。那怎样才能做到干净且清晰地复制一个对象呢?在 Java 中,仅仅使用简单的赋值语句是无法满足这种需求的,实现复制对象有很多种方法:
(1)逐个属性赋值。
改写为:对 java.lang.Object 类中的方法 clone()进行重写。
使用 org.apache.commons 中的工具类 PropertyUtils 来进行对象复制。
(4)通过JSON之间的转换,进行对象克隆。
(5)通过序列化实现对象的复制。
接下来,我们将详细介绍其中的几种方法。
将A对象的值分别通过set方法加入B对象中
逐个对属性进行赋值,这种方式适用于属性数量较少的场景,其操作较为直观。然而,对于属性较多的对象来说,这种方式会引发大量的 get 方法和 set 方法的调用,从而使操作变得繁琐。
改写“重写 java.lang.Object 类中的方法 clone()”可以这样写:对 java.lang.Object 类中的 clone()方法进行改写。
介绍浅克隆和深克隆的概念。
深克隆会复制对象内部包含的对象。
浅克隆
3. 在覆盖的 clone()方法中,使用 super.clone()来实现基本复制。
结果展示:复制对象后,如果成员变量属于引用类型,那么新对象和原对象会引用相同的内存地址。
深克隆
完整代码实现深克隆,解决浅克隆的局限性。
成员变量无论是值类型还是引用类型,在复制对象时都会复制所有的成员变量。
使用 BeanUtils 工具进行对象复制;使用 PropertyUtils 工具进行对象复制。
使用 BeanUtils 的 copyProperties()方法,把转换前的 A 类赋予转换后的 B 类,以此来简化属性复制的过程。
注意点:B 类具有某些属性,而 A 类不一定具备这些属性。Spring 的 BeanUtils 方法对属性有特定要求,即需有 getter 和 setter 方法。并且,当存在属性完全相同的内部类时,需要特别予以关注。
通过JSON转换实现深克隆
利用 fastjson 能够实现对象与 JSON 串之间的相互转换,这种转换的本质其实是反射操作。
通过序列化实现对象的复制
使用 Java 的序列化机制,其中像 SerializationUtils 的 clone()方法这样的方式,需要对象去实现 Serializable 接口。
总结与个人意见
当性能要求不高时,可以挑选简单且易于实现的方法,像是 fastjson、进行序列化或者使用 DozerBeanMapper 等。而在性能要求比较高的场景当中,建议通过自定义工具类来实现更加灵活的复制逻辑。