应用场景

定义实体类时会继承Serializable接口

import java.io.Serializable;

public class PK implements Serializable {
    private static final long serialVersionUID=1L;
}

作用

Serializable是一个对象序列化的接口。一个类只有实现了Serializable接口,它的对象才能被序列化。

序列化

定义

把对象转换为字节序列的过程称为对象的序列化;

把字节序列恢复为对象的过程称为对象的反序列化。

用途

当我们需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化。

网络上传输的都是二进制,不会直接传输对象。

我在开发过程中,实体并没有实现序列化,但我同样可以将数据保存到mysql、Oracle数据库中,为什么非要序列化才能存储呢?

int、long、boolean类型等,都是基本数据类型,数据库里面有与之对应的数据结构。从类声明来看,我们以为的没有进行序列化,其实是在声明的各个不同变量的时候,由具体的数据类型帮助我们实现了序列化操作。所以就算我们不实现serializable依旧可以正常操作。序列化操作用于存储时,一般是对于NoSql数据库。

实现

Serializable接口是一个空接口,相当于一个标识,通知jvm,我不对这个类做序列化了,你(jvm)帮我序列化就好了。

SerialVersionUID

对于JVM来说,要进行持久化的类必须要有一个标记,只有持有这个标记JVM才允许类创建的对象可以通过其IO系统转换为字节数据,从而实现持久化,而这个标记就是Serializable接口。而在反序列化的过程中则需要使用serialVersionUID来确定由那个类来加载这个对象,所以我们在实现Serializable接口的时候,一般还会要去尽量显示地定义serialVersionUID,如:

private static final long serialVersionUID = 1L; 

在反序列化的过程中,如果接收方为对象加载了一个类,如果该对象的serialVersionUID与对应持久化时的类不同,那么反序列化的过程中将会导致InvalidClassException异常。例如,在之前反序列化的例子中,我们故意将User类的serialVersionUID改为2L,如:

private static final long serialVersionUID = 2L; 

那么此时,在反序例化时就会导致异常,如下:

java.io.InvalidClassException: cn.wudimanong.serializable.User; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2     at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)     at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1880)     at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)     at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)     at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)     at cn.wudimanong.serializable.SerializableTest.readObj(SerializableTest.java:31)     at cn.wudimanong.serializable.SerializableTest.main(SerializableTest.java:44) 

如果我们在序列化中没有显示地声明serialVersionUID,则序列化运行时将会根据该类的各个方面计算该类默认的serialVersionUID值。但是,Java官方强烈建议所有要序列化的类都显示地声明serialVersionUID字段,因为如果高度依赖于JVM默认生成serialVersionUID,可能会导致其与编译器的实现细节耦合,这样可能会导致在反序列化的过程中发生意外的InvalidClassException异常。因此,为了保证跨不同Java编译器实现的serialVersionUID值的一致,实现Serializable接口的必须显示地声明serialVersionUID字段。

此外serialVersionUID字段地声明要尽可能使用private关键字修饰,这是因为该字段的声明只适用于声明的类,该字段作为成员变量被子类继承是没有用处的!有个特殊的地方需要注意的是,数组类是不能显示地声明serialVersionUID的,因为它们始终具有默认计算的值,不过数组类反序列化过程中也是放弃了匹配serialVersionUID值的要求。

Logo

为开发者提供学习成长、分享交流、生态实践、资源工具等服务,帮助开发者快速成长。

更多推荐