《Effective Java读书笔记》--序列化

狂风中的少年 提交于 2019-12-20 10:33:35

【推荐】2019 Java 开发者跳槽指南.pdf(吐血整理) >>>

谨慎地实现Serializable

实现Serializable有以下几点风险

  • 实现Serializable的类一旦发布,则“改变这个类的实现”的灵活性将大大降低。
  • 增加了错误和安全漏洞的可能性。
  • 测试负担会增加。

为了继承而设计的类应该很少实现Serializable,接口也应该很少会扩展它。

保护性地编写readObject方法

不严格的说,readObject是一个“用字节流作为唯一参数”的构造函数"。所以在写readObject时,就想象自己正在编写一个构造函数。
例如,在一个类的构造函数中,对参数的有效性做了检查,并且也做了保护性拷贝的话,readObject中也应该实现该逻辑。Period类(参考 http://my.oschina.net/u/1453800/blog/263037#OSC_h3_2)的readObject可以写成这样:

private void readObject(ObjectInputStream s) throws IOException,
			ClassNotFoundException {
		s.defaultReadObject();
		start = new Date(start.getTime());
		end = new Date(end.getTime());

		if (start.compareTo(end) > 0) {
			throw new InvalidObjectException(start + "after" + end);
		}
	}



值得注意的是,这样实现后,start和end都不能再定义成final了。不过下文会介绍readResolve方法,可以作为保护性readObject的替代选择,并且保证start和end还能继续定义成final。

在readObject中,无论是直接方式还是间接方式,都不要调用类中可被改写的方法。

必要时提供一个readResolve方法

readResolve有两个用法:

  •  用来实现singletor的序列化
  • 作为保护性的readObject方法的一种保守替代选择,它的好处有:减少代码冗余,也不需要考虑太多细节;消除了“序列化对于使用final域的人为限制”。

Peroid类的readResolve方法实现如下:

private Object readResolve() throws ObjectStreamException {
		return new Period(start, end);
}

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!