建议44: 推荐使用序列化实现对象的拷贝

上一个建议说了对象的浅拷贝问题,实现Cloneable接口就具备了拷贝能力,那我们来思考这样一个问题:如果一个项目中有大量的对象是通过拷贝生成的,那我们该如何处理?每个类都写一个clone方法,并且还要深拷贝?想想看这是何等巨大的工作量呀,是否有更好的方法呢?

其实,可以通过序列化方式来处理,在内存中通过字节流的拷贝来实现,也就是把母对象写到一个字节流中,再从字节流中将其读出来,这样就可以重建一个新对象了,该新对象与母对象之间不存在引用共享的问题,也就相当于深拷贝了一个新对象,代码如下:

 1 public class CloneUtils {
 2      // 拷贝一个对象
 3      @SuppressWarnings("unchecked")
 4      public static <T extends Serializable>  T clone(T obj) {
 5           // 拷贝产生的对象
 6           T clonedObj = null;
 7           try {
 8             // 读取对象字节数据
 9             ByteArrayOutputStream baos = new ByteArrayOutputStream();
10             ObjectOutputStream oos = new ObjectOutputStream(baos);
11             oos.writeObject(obj);
12             oos.close();
13             // 分配内存空间,写入原始对象,生成新对象
14             ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
15             ObjectInputStream ois = new ObjectInputStream(bais);
16             //返回新对象,并做类型转换
17             clonedObj = (T)ois.readObject();
18             ois.close();
19          } catch (Exception e) {
20             e.printStackTrace();
21          }
22          return clonedObj;
23      }
24 } 

此工具类要求被拷贝的对象必须实现Serializable接口,否则是没办法拷贝的(当然,使用反射那是另外一种技巧),上一个建议中的例子只要稍微修改一下即可实现深拷贝,代码如下:

 1 public class CloneUtils {
 2     // 拷贝一个对象
 3     @SuppressWarnings("unchecked")
 4     public static <T extends Serializable>  T clone(T obj) {
 5          // 拷贝产生的对象
 6          T clonedObj = null;
 7          try {
 8            // 读取对象字节数据
 9            ByteArrayOutputStream baos = new ByteArrayOutputStream();
10            ObjectOutputStream oos = new ObjectOutputStream(baos);
11            oos.writeObject(obj);
12            oos.close();
13            // 分配内存空间,写入原始对象,生成新对象
14            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
15            ObjectInputStream ois = new ObjectInputStream(bais);
16            //返回新对象,并做类型转换
17            clonedObj = (T)ois.readObject();
18            ois.close();
19         } catch (Exception e) {
20            e.printStackTrace();
21         }
22         return clonedObj;
23     }
24 } 

此工具类要求被拷贝的对象必须实现Serializable接口,否则是没办法拷贝的(当然,使用反射那是另外一种技巧),上一个建议中的例子只要稍微修改一下即可实现深拷贝,代码如下:

1 class Person implements Serializable{
2      private static final long serialVersionUID = 1611293231L;
3      /*删除掉clone方法,其他代码保持不变*/
4 } 

上去的,然后我们就可以通过CloneUtils工具进行对象的深拷贝了。用此方法进行对象拷贝时需要注意两点:

(1)对象的内部属性都是可序列化的

如果有内部属性不可序列化,则会抛出序列化异常,这会让调试者很纳闷:生成一个对象怎么会出现序列化异常呢?从这一点来考虑,也需要把CloneUtils工具的异常进行细化处理。

(2)注意方法和属性的特殊修饰符

比如final、static变量的序列化问题会被引入到对象拷贝中来(参考第1章),这点需要特别注意,同时transient变量(瞬态变量,不进行序列化的变量)也会影响到拷贝的效果。

当然,采用序列化方式拷贝时还有一个更简单的办法,即使用Apache下的commons工具包中的SerializationUtils类,直接使用更加简洁方便。

转载于:https://www.cnblogs.com/DreamDrive/p/5430981.html

[改善Java代码] 推荐使用序列化实现对象的拷贝相关推荐

  1. java 编码实现内存拷贝_java提高篇(六)-----使用序列化实现对象的拷贝

    我们知道在Java中存在这个接口Cloneable,实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面比我们直接通过new生成对象来的快,特别是在大对象的生成上,使得性能的提升非常 ...

  2. 改善Java代码有哪些方法?

    前言 Java是一门优秀的面向对象的编程语言,针对遇到同样的一个问题会有很多中解法哪种实现方法是最好的呢,还需要不断的探究JDK的底层原理.我会例出Java改善的建议哦,希望大家可以在平时开发工作去使 ...

  3. java 代码解析工具_改善 Java 代码质量的工具与方法

    原标题:改善 Java 代码质量的工具与方法 我们可能见过上面的有关代码质量的图片,究竟如何衡量一段代码好坏? 代码质量是什么?为什么它很重要? 作家通过他的著作来讲述了一个清晰的.令人信服的故事.他 ...

  4. 使用序列化实现对象的拷贝(转载)

    文章出处:http://www.cnblogs.com/chenssy/p/3382979.html 实现Cloneable接口:实现该接口的类都会具备被拷贝的能力,同时拷贝是在内存中进行,在性能方面 ...

  5. java 防止拷贝_[改善Java代码]避免对象的浅拷贝

    建议43: 避免对象的浅拷贝 我们知道一个类实现了Cloneable接口就表示它具备了被拷贝的能力,如果再覆写clone()方法就会完全具备拷贝能力.拷贝是在内存中进行的,所以在性能方面比直接通过ne ...

  6. [改善Java代码]养成良好习惯,显式声明UID

    建议11: 养成良好习惯,显式声明UID 我们编写一个实现了Serializable接口(序列化标志接口)的类, Eclipse马上就会给一个黄色警告:需要增加一个Serial Version ID. ...

  7. [改善Java代码]非稳定排序推荐使用List

    我们知道Set与List的最大区别就是Set中的元素不可以重复(这个重复指的equals方法的返回值相等),其他方面则没有太大的区别了,在Set的实现类中有一个比较常用的类需要了解一下:TreeSet ...

  8. java 不可修改的集合对象_[改善Java代码]asList方法产生的List对象不可更改

    上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码: importjava.util.Arrays;importjava.util ...

  9. [改善Java代码]不推荐使用binarySearch对列表进行检索

    对一个列表进行检索时,我们使用的最多的是indexOf方法,它简单好用,而且也不会出错,虽然它只能检索到第一个符合条件的值,但是我们可以生成子列表后再检索.这样也就可以查找到所有符合条件的值了. Co ...

最新文章

  1. [c#基础]关于try...catch最常见的笔试题
  2. 聊聊、Zookeeper 客户端 Curator
  3. LeaFlet学习之结合turf.js生成简单的等值线demo
  4. [iPhoneアプリ]iEscaper2攻略その6|龍の水晶
  5. 浅析Java内存模型
  6. C/C++只做经典编程语言
  7. IOS的一些文件操作。(沙箱) 在Documents目录下创建文件
  8. python模块名不规范如何导入_如何强制Python的“导入”将名称视为模块,而不是函数?...
  9. 【iOS-Cocos2d游戏开发之六】对触屏事件追加讲解,解决无法触发ccTouchMoved事件[重要!]...
  10. 带货造假,买完不能换货?李佳琦、汪涵、李雪琴直播被中消协点名后这样回应...
  11. [转载] pandas dataframe 提取行和列
  12. 按键精灵定位坐标循环_按键精灵的控制命令居然恐怖到了这种程度
  13. 一个未完毕创业项目的思考——创业杂记
  14. Python-15 函数:我的地盘听我的
  15. ultrascale和arm区别_ZYNQ UltraScale+ MPSoc FPGA初学笔记
  16. 守护安全|AIRIOT城市天然气综合管理解决方案
  17. 结构化数据和非结构化数据的分析
  18. 数电实验三 数据选择器及其应用 任务一:用74151芯片采用降维的方法实现F=ABC+ABD+ACD+BCD; 任务二:用74151芯片采用降维方式实现F=BCD反+BC反+A反D;
  19. d3带箭头和点击事件的力导向关系图
  20. 数字电路实验 07 - | 计数器及其应用

热门文章

  1. pandas 读表格_pandas电子表格的读取(pandas中的read_excel)
  2. Vue项目中 css样式的作用域(深度作用选择器)
  3. python web开发 jQuery基础
  4. 天池 在线编程 输入流
  5. LeetCode 1562. 查找大小为 M 的最新分组
  6. LeetCode MySQL 1336. 每次访问的交易次数
  7. LintCode 1210. 升序子序列(DFS)
  8. LeetCode 937. 重新排列日志文件(自定义排序)
  9. python使方法执行10次_Python提升程序性能的七个手段
  10. python中_str_使用方法