JAVA序列化与反序列化内容
序列化操作:就是将JAVA对象转化为可以在网络上传输
JAVA中,当我们想将某一个对象持久化到磁盘、Redis等等,又或者想在两个进程之间传递对象时,必须将对象进行序列化操作和反序列化操作。 序列化操作:就是将JAVA对象转化为可以在网络上传输,在磁盘上可以保存的二进制内容。 反序列化操作:就是将保存的二进制数据转化为JAVA对象,从而可以在JVM进行使用。 一、JAVA中进行序列化的方式: 在JAVA中有两个方式进行对象的序列化和反序列化。 1.实现Serializable接口。(大部分使用) 2.实现Externalizable接口。(它是Serialization接口的子类) 当我们的类没有实现Serializable接口又或者子类时,不能进行序列化或者反序列化操作,不然抛出一个异常。 二、Serializable接口 1.当我们为某一个类实现了Serializable接口。可以进行序列化和反序列化操作。 2.当进行序列化操作时:(将对象写入到磁盘中) 会先调用其writeReplace方法。 然后会调用其writeObject方法。 注意事项: 其中wirteReplace方法可以是从父类继承过来的,Object的返回值,无参,任何访问级别 而writeObject必须是本类的,并且是私有的,无返回值,ObjectOutputStream参数 writeReplace的方法签名:ObjectwriteReplace()。 writeObject的访达签名:private void writeObject(ObjectOutputStream)。 其中writeReplace方法给我们了一种选择,可以让我们可以在序列化的时候写入其他的对象,而不是当前对象。因为该方法有一个返回值,它会将返回值进行最终的持久化操作。 当我们没有重写writeObject方法时,JAVA会自动将该类的全部非transient属性进行持久化。当我们重写了writeObject方法时,并且是空实现,JAVA就只会将类对象进行持久化,而不会将该类的任何对象进行持久化,相当于一个空对象。这时需要在writeObject方法中将我们自己将需要的数据写入到ObjectOutputStream对象中,即传递的参数。 默认的writeObject不会序列化transient字段内容。 writeObject方法的作用:按需要对哪些对象属性进行序列化。这时候,我们可以手动将transient字段进行序列化。就会强制将transient进行序列化。 例如:
执行结果:
在上面的例子中,我们在writeObject中序列化name和ss两个字段,并在readObject修改了读取的name字段值。 在writeReplace方法中,直接返回了当前对象。 从上面输出可以看出:先执行writeReplace,然后执行writeObject方法。 3.当进行反序列化操作时:(将磁盘数据写入到对象中) 会先调用readObject方法 然后调用readResolve方法 注意事项: 其中readResolve方法可以是从父类继承过来的,Object的返回值,无参,任何方法访问级别 而readObject必须是本类的,并且是私有的,无返回值,ObjectInputStream参数 readResolve的方法签名:ObjectreadResolve()。 readObject的访达签名:private void readObject(ObjectInputStream)。 在进行反序列化操作时,生成新的JAVA对象时,是不会调用其构造函数的。 在进行反序列化操作时,生成新的JAVA对象,primitive都是默认值,其他对象都是null,不会执行属性上的默认值赋值。 其中readResolve方法,同样也给了一种选择机会,在进行反序列化操作时,最终返回的对象内容是什么,因为readResolve方法有一个Object返回值内容。 当我们重写了writeObject方法时,一定要重写readObject方法,不然会抛出一个java.io.StreamCorruptedException不正确的流内容异常。我们可以原样的从ObjectInputStream获取我们写入的数据内容。 从上面的例子可以看出来我们在readObject可读取了写入的数据内容,并追加了“change”内容。 最后会调用readResolve方法,让我们确定最终的返回对象 在序列化的时候,如果将一个对象序列化多次。在反序列化的时候,反序列化的对象也是同一个。这是因为每一个序列化的对象都有一个对应的序列化编码号。 序列化算法: 所有序列化对象都有一个序列化编号。 当JAVA试图序列化某一个对象时,会先检查此对象是否已经序列化过,只有此对象从未被序列化过,才会将此对象序列化为字节输出,如果已经序列化过,直接输出序列化的编号即可。 当反序列化时,如果反序列化为对象时,就会将反序列化的对象进行缓存起来。如果反序列化为序号时,直接从缓存中的获取。 所以:将一个对象序列化多次。反序列化时只有第一个是反序列对象,后面的都是从缓存中获取的mssql 使用序列,所以都是同一个对象。 4.补充说明: 上面的四个方法的顺序为: writeReplace writeObject readObject readResolve 这四个方法可以在ObjectStreamClass中找到定义:
三、Externalizable实现序列化: 他和Serializable一样,可以在序列化和反序列化的时候进行方法的调用,完成最终写入的数据内容。 实现Externalizable接口时,序列化的类必须存在一个public无参的构造函数。因为在反序列化的时候,需要调用构造函数创建对象。 会执行类的字段初始化。 他有两个抽象方法:writeExternal和readExternal方法。 serializable方法调用路径为:writeReplace->writeObject->readObject->readResolve 而Externalizable的调用路径为:writeReplace->writeExternal->readExternal->readResolve 其中第一和第四个方法是一样的。第二和第三个方法是Externalization的抽象方法。 serializable与externalizable区别: 在使用Eternalization进行反序列操作时,会调用默认的构造函数,如果没有的话,就会抛出异常。也会执行字段上默认值的赋值。而serialization进行反序列操作时,不会调用默认的构造函数。也不会执行字段上的默认值,即字段为primitive,有JAVA自带的默认值,int为0等等,而引用类型为null。 Externalizable的性能比Serializable稍好一些。 (编辑:成都站长网) 【声明】本站内容均来自网络,其相关言论仅代表作者个人观点,不代表本站立场。若无意侵犯到您的权利,请及时与联系站长删除相关内容! |