使用情况
当遍历一个图形时,可能会遇到不支持可序列化接口的对象。在此情况下,将抛出NotSerializableException,并将标识不可序列化对象的类。
在序列化和反序列化过程中需要特殊处理的类必须使用下列准确签名来实现特殊方法:
private void writeObject(java.io.ObjectOutputStream out)
throws IOException
private void readObject(java.io.ObjectInputStream in)
throws IOException,ClassNotFoundException;
writeObject方法负责写入特定类的对象的状态,以便相应的readObject方法可以还原它。通过调用out.defaultWriteObject可以调用保存Object的字段的默认机制。该方法本身不需要涉及属于其超类或子类的状态。状态是通过使用writeObject方法或使用DataOutput支持的用于基本数据类型的方法将各个字段写入ObjectOutputStream来保存的。
readObject方法负责从流中读取并还原类字段。它可以调用in.defaultReadObject来调用默认机制,以还原对象的非静态和非瞬态字段。defaultReadObject方法使用流中的信息来分配流中通过当前对象中相应命名字段保存的对象的字段。这用于处理类发展后需要添加新字段的情形。
将对象写入流时需要指定要使用的替代对象的可序列化类,应使用准确的签名来实现此特殊方法:
ANY-ACCESS-MODIFIER Object writeReplace()throws ObjectStreamException;
此writeReplace方法将由序列化调用,前提是如果此方法存在,而且它可以通过被序列化对象的类中定义的一个方法访问。因此,该方法可以拥有私有(private)、受保护的(protected)和包私有(package-private)访问。子类对此方法的访问遵循java访问规则。
在从流中读取类的一个实例时需要指定替代的类应使用的准确签名来实现此特殊方法。
ANY-ACCESS-MODIFIER Object readResolve()throws ObjectStreamException;
此readResolve方法遵循与writeReplace相同的调用规则和访问规则。
序列化运行时使用一个称为serialVersionUID的版本号与每个可序列化类相关联,该序列号在反序列化过程中用于验证序列化对象的发送者和接收者是否为该对象加载了与序列化兼容的类。如果接收者加载的该对象的类的serialVersionUID与对应的发送者的类的版本号不同,则反序列化将会导致InvalidClassException。可序列化类可以通过声明名为"serialVersionUID"的字段(该字段必须是静态(static)、最终(final)的long型字段)显式声明其自己的serialVersionUID:
ANY-ACCESS-MODIFIER static final long serialVersionUID=42L;
如果可序列化类未显式声明serialVersionUID,则序列化运行时将基于该类的各个方面计算该类的默认serialVersionUID值,如“Java(TM)对象序列化规范”中所述。不过,强烈建议所有可序列化类都显式声明serialVersionUID值,原因计算默认serialVersionUID对类的详细信息具有较高的敏感性,根据编译器实现的不同可能千差万别,这样在反序列化过程中可能会导致意外的InvalidClassException。因此,为保证serialVersionUID值跨不同java编译器实现的一致性,序列化类必须声明一个明确的serialVersionUID值。还强烈建议使用private修改器显示声明serialVersionUID(如果可能),原因是这种声明仅应用于立即声明类--字段作为继承成员没有用处。
实现java.io.Serializable接口的类是可序列化的。没有实现此接口的类将不能使它们的任一状态被序列化或逆序列化。
序列化类的所有子类本身都是可序列化的。这个序列化接口没有任何方法和域,仅用于标识序列化的语意。允许非序列化类的子类型序列化,子类型可以假定负责保存和恢复父类型的公有的、保护的和(如果可访问)包的域的状态。只要该类(即父类)有一个无参构造子,可初始化它的状态,那么子类型就可承担上述职责;如果该类没有无参构造函数,在这种情况下申明一个可序列化的类是一个错误。此错误将在运行时被检测。
例如:Integer实现了Serializable,所以可以把一个Integer的对象用IO写到文件里,之后再可以从文件里读出,如你开始写入的时候那个对象的intValue()是5的话,那读出来之后也是5。这一点体现了用序化类的作用,即用来传送类的对象。
当一个JavaBean在构造工具内被用户化,并与其它Bean建立连接之后,它的所有状态都应当可被保存,下一次被load进构造工具内或在运行时,就应当是上一次修改完的信息。为了能做到这一点,要把Bean的某些字段的信息保存下来,在定义Bean时要使它实现Java.io.Serializable接口。例如:public class Button implements Java.io.Serializable{……}
实现了序列化接口的Bean中字段的信息将被自动保存。若不想保存某些字(这里的Bean中字段的信息将被自动保存是什么意思?这个自动保存是怎么实现的?)
段的信息则可在这些字段前冠以transient或static关键字,transient和static变量的信息是不可被保存的。通常,一个Bean所有公开出来的属性都应当是被保存的,也可有选择地保存内部状态。Bean开发者在修改软件时,可以添加字段,移走对其它类的引用,改变一个字段的private、protected或public状态,这些都不影响类的存储结构关系。然而,当从类中删除一个字段,改变一个变量在类体系中的位置,把某个字段改成transient/static,或原来是transient/static,现改为别的特性时,都将引起存储关系的变化。
所谓的Serializable,就是java提供的通用数据保存和读取的接口。至于从什么地方读出来和保存到哪里去都被隐藏在函数参数的背后了。这样子,任何类型只要实现了Serializable接口,就可以被保存到文件中,或者作为数据流通过网络发送到别的地方。也可以用管道来传输到系统的其他程序中。这样子极大的简化了类的设计。只要设计一个保存一个读取功能就能解决上面说得所有问题。
特性
1、Java的RMI(remote method invocation).RMI允许象在本机上一样操作远程机器上的对象。当发送消息给远程对象时,就需要用到serializaiton机制来发送参数和接收返回直。
2、Java的JavaBeans.Bean的状态信息通常是在设计时配置的。Bean的状态信息必须被存起来,以便当程序运行时能恢复这些状态信息。这也需要serializaiton机制。[1]