序列化笔记
程序员文章站
2022-06-08 21:11:57
...
序列化:
将对象编码成一个字节流,以及从字节流编码中重新构造对象.
将一个对象编码成一个字节流称为序列化,相反的处理过程称为反序列化.
54:=======
实现序列化的代价:
1.一旦一个类发布,则改变这个类的灵活性将大大降低. 字节流编码变成了它的导出API的一部分.指:类自身的演变和类所在继承体系的演变(对子类序列化所加的影响).
2.它增加了错误(bug)和安全漏洞的可能性. 通常情况下对象是由构造方法来创建,序列化机制是一种语言之外的对象创建机制.
反序列化机制实际上是一个以字节流为入参的“隐藏的构造方法”, 要记住的是readObject方法和构造方法在逻辑上遵守的规则是一致的.
3.随着一个类的新版本的发行,相关的测试负担增加了.
55:====
考虑使用自定义的序列化形式:
1.若没有认真考虑默认序列化形式是否合适,则不要接受这种形式.
对于一个对象来说,理想的序列化形式应该只包含该对象所表示的逻辑数据,而逻辑数据与物理表示应该是独立的.
2.如果一个对象的物理表示等同于它的逻辑内容,则默认的序列化形式可能是合适的.如Person类,默认序列化是合理的.
3.即使你确定了默认序列化形式是合适的,通常你仍然要提供一个readObject方法以保证约束关系和安全性.
这也可以说是对入参的合法性检查. readObject要根据从字节流中获得的信息来构造对象,其本身就是一个构造方法.
4.当一个对象的物理表示与它的逻辑数据内容有实质性的区别时,使用默认序列化形式有4的问题. (类的逻辑表示表达类的一种用途,物理表示是实现逻辑表示的实现,不要让逻辑表示束缚在物理表示格式上)
4.1它使这个类的导出API永远的束缚在该类的内部表示上.
4.2它要消耗过多的空间.
4.3它要消耗过多的时间.
4.4它会引起栈溢出.
总而言之:当你决定要将一个类做成可序列化的时候,请仔细考虑应该采用什么样的序列化形式,只有当默认的序列化形式能够合理地描述状态的时候,你才使用默认的序列化形式,否则就设计一个自定义的序列化形式,通过它合理地描述对象的状态。你应该分配足够多的时间来设计一个类的序列化形式,就好像你分配足够多的时间来设计它的导出方法一样。正如你无法在将来的版本中去掉导出方法一样,你也不能去掉序列化形式中地域,它们必须被永久地保留下去,以确保序列化兼容性(serialization compalibility).选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面影响.
56。========
readObject方法与构造方法所受的约束相同.它相当于另一个公有的构造方法.不严格的说readObject 是一个"用字节流作为唯一参数"的构造方法.
当一个对象被反序列化的时候,对于客户不应该拥有的对象引用,如果哪个域包含了这样的对象引用,则必须要做保护性拷贝,这是非常重要的.(就像封装集合的作法:要么返回一个只读集合,要么返回一个保护性拷贝的集合,以保证对象内部的集合状态不会被外部修改)
57。======
必要时提供一个readResolve方法.
任何一个readResolve方法,不管是显式的还是默认的,它都会返回一个新建的实例,这个新建的实例不同于该类初始化时刻创建的实例。(一个Singleton如果实现了Serializable接口,则一定要提供一个readResolve方法,以保证在反序列化后实例仍然只有一个.)
readResolve方法不仅对于singleton对象是必要的,而且对于所有其他的实例受控的(instance-controlled)类也是必需的.另一个例子是类型安全枚举类型(typesafe enum),它的readResolve方法必须返回代表特定枚举常量的规范的实例(canonical instance).凭经验,如果你正在编写的可序列化的类没有包含公有的或者受保护的构造方法,那么请考虑它是否需要一个readResolve方法.
readResolve方法的第二个用法是,作为保护性的readObject方法的一种保守的替代选择.
readObject 是另一个构造方法,
readResolve是静态工厂方法
总而言之:无论是singleton还是instance-controlled的类,都要使用readResolve来保护"instance-control invariant"
从本质上讲,readResolve方法把readObject方法从一个事实上的公有构造方法变成一个事实上的公有静态工厂。对于那些禁止包外继承的类而言,readResovle方法作为保护性的readObject方法的一种替代选择,也是非常有用的.
将对象编码成一个字节流,以及从字节流编码中重新构造对象.
将一个对象编码成一个字节流称为序列化,相反的处理过程称为反序列化.
54:=======
实现序列化的代价:
1.一旦一个类发布,则改变这个类的灵活性将大大降低. 字节流编码变成了它的导出API的一部分.指:类自身的演变和类所在继承体系的演变(对子类序列化所加的影响).
2.它增加了错误(bug)和安全漏洞的可能性. 通常情况下对象是由构造方法来创建,序列化机制是一种语言之外的对象创建机制.
反序列化机制实际上是一个以字节流为入参的“隐藏的构造方法”, 要记住的是readObject方法和构造方法在逻辑上遵守的规则是一致的.
3.随着一个类的新版本的发行,相关的测试负担增加了.
55:====
考虑使用自定义的序列化形式:
1.若没有认真考虑默认序列化形式是否合适,则不要接受这种形式.
对于一个对象来说,理想的序列化形式应该只包含该对象所表示的逻辑数据,而逻辑数据与物理表示应该是独立的.
2.如果一个对象的物理表示等同于它的逻辑内容,则默认的序列化形式可能是合适的.如Person类,默认序列化是合理的.
3.即使你确定了默认序列化形式是合适的,通常你仍然要提供一个readObject方法以保证约束关系和安全性.
这也可以说是对入参的合法性检查. readObject要根据从字节流中获得的信息来构造对象,其本身就是一个构造方法.
4.当一个对象的物理表示与它的逻辑数据内容有实质性的区别时,使用默认序列化形式有4的问题. (类的逻辑表示表达类的一种用途,物理表示是实现逻辑表示的实现,不要让逻辑表示束缚在物理表示格式上)
4.1它使这个类的导出API永远的束缚在该类的内部表示上.
4.2它要消耗过多的空间.
4.3它要消耗过多的时间.
4.4它会引起栈溢出.
总而言之:当你决定要将一个类做成可序列化的时候,请仔细考虑应该采用什么样的序列化形式,只有当默认的序列化形式能够合理地描述状态的时候,你才使用默认的序列化形式,否则就设计一个自定义的序列化形式,通过它合理地描述对象的状态。你应该分配足够多的时间来设计一个类的序列化形式,就好像你分配足够多的时间来设计它的导出方法一样。正如你无法在将来的版本中去掉导出方法一样,你也不能去掉序列化形式中地域,它们必须被永久地保留下去,以确保序列化兼容性(serialization compalibility).选择错误的序列化形式对于一个类的复杂性和性能都会有永久的负面影响.
56。========
readObject方法与构造方法所受的约束相同.它相当于另一个公有的构造方法.不严格的说readObject 是一个"用字节流作为唯一参数"的构造方法.
当一个对象被反序列化的时候,对于客户不应该拥有的对象引用,如果哪个域包含了这样的对象引用,则必须要做保护性拷贝,这是非常重要的.(就像封装集合的作法:要么返回一个只读集合,要么返回一个保护性拷贝的集合,以保证对象内部的集合状态不会被外部修改)
57。======
必要时提供一个readResolve方法.
任何一个readResolve方法,不管是显式的还是默认的,它都会返回一个新建的实例,这个新建的实例不同于该类初始化时刻创建的实例。(一个Singleton如果实现了Serializable接口,则一定要提供一个readResolve方法,以保证在反序列化后实例仍然只有一个.)
public class Singleton implements Serializable { private static final Singleton SINGLETON= new Singleton(); private Singleton() {} public static Singleton getInstance() { return SINGLETON; } //该方法忽略掉被反序列化的对象,简单地返回该类初始化时刻创建的那个特殊的实例.因此此类的序列化形式并不需要包含任何实际的数据;所有的实例域都应该被标记为transient. private Object readResolve() throws IOException { return SINGLETON; } }
readResolve方法不仅对于singleton对象是必要的,而且对于所有其他的实例受控的(instance-controlled)类也是必需的.另一个例子是类型安全枚举类型(typesafe enum),它的readResolve方法必须返回代表特定枚举常量的规范的实例(canonical instance).凭经验,如果你正在编写的可序列化的类没有包含公有的或者受保护的构造方法,那么请考虑它是否需要一个readResolve方法.
readResolve方法的第二个用法是,作为保护性的readObject方法的一种保守的替代选择.
readObject 是另一个构造方法,
readResolve是静态工厂方法
总而言之:无论是singleton还是instance-controlled的类,都要使用readResolve来保护"instance-control invariant"
从本质上讲,readResolve方法把readObject方法从一个事实上的公有构造方法变成一个事实上的公有静态工厂。对于那些禁止包外继承的类而言,readResovle方法作为保护性的readObject方法的一种替代选择,也是非常有用的.