美文网首页
Serializable接口

Serializable接口

作者: 取名废同学 | 来源:发表于2018-11-30 17:33 被阅读0次

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

    一、什么是序列化?
    【将对象的状态信息转换为可以存储或传输的形式的过程,在序列化期间,对象将其当前状态写入到临时存储区或持久性存储区,之后,便可以通过从存储区中读取或反序列化对象的状态信息,来重新创建该对象】

    序列化将数据分解成字节流,以便存储在文件中或在网络上传输。
    反序列化就是打开字节流并重构对象。

    二、什么情况下需要序列化?
    【当我们需要把对象的状态信息通过网络进行传输,或者需要将对象的状态信息持久化,以便将来使用时都需要把对象进行序列化】

    三、Serializable主要用来支持两种主要的特性:
    1、Java的RMI(remote method invocation),RMI允许像在本机上一样操作远程机器上的对象,当发送消息给远程对象时,就需要用到序列化机制来发送参数和接受返回值。
    2、Java的JavaBean,Bean的状态信息通常是在设计时配置的,Bean的状态信息必须被保存下来,以便当程序运行时能恢复这些状态信息,这也需要序Serializable机制。

    只需要了解被序列化的类需要实现 Serializable 接口,使用 ObjectInputStream 和 ObjectOutputStream 进行对象的读写。

    四、常出现的情景
    1、两个类A B代码完全相同,试图通过网络传递对象数据,A 端将对象 C 序列化为二进制数据再传给 B,B 反序列化得到 C。但一直反序列化不成功。

    解决:虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID = 1L)。虽然两个类的功能代码完全一致,但是序列化 ID 不同,他们无法相互序列化和反序列化。

    !!!!!!
    序列化 ID 在 Eclipse 下提供了两种生成策略,
    (1)固定的 1L(一般这么做。可以确保代码一致时反序列化成功)

    private static final long serialVersionUID = 1L;
    

    (2)一个是随机生成一个不重复的 long 类型数据(作用是:通过改变序列化 ID 可以用来限制某些用户的使用。)

    2、Facade外观模式:
    Client 端通过 Façade Object 才可以与业务逻辑对象进行交互。而客户端的 Façade Object 不能直接由 Client 生成,而是需要 Server 端生成,然后序列化后通过网络将二进制对象数据传给 Client,Client 负责反序列化得到 Façade 对象。

    即 服务端(生成Facade object)序列化 ----->客户端(反序列化,得到Facade对象,可用其与业务逻辑对象交互)

    该模式可以使得 Client 端程序的使用需要服务器端的许可,同时 Client 端和服务器端的 Façade Object 类需要保持一致。当服务器端想要进行版本更新时,只要将服务器端的 Façade Object 类的序列化 ID 再次生成,当 Client 端反序列化 Façade Object 就会失败,也就是强制 Client 端从服务器端获取最新程序。

    3、一个类实现了序列化,并且有其静态变量。
    但序列化保存的是对象的状态,静态变量属于类的状态,因此 序列化并不保存静态变量。

    4、父类的序列化与transient:
    父类不实现序列化,子类实现序列化,则将子类对象反序列化后输出父类定义的某变量的数值,该变量数值与序列化时的数值不同。

    原因:一个java对象的构造必须先有父对象,再有子对象,反序列化也是,父类没有实现序列化,则虚拟机不会序列化父类。

    解决:
    a、父类也实现序列化
    b、为父类创造默认的无参的构造方法,在父类无参构造方法中对父类进行变量初始化。则反序列化时,构造父对象时只能调用父类无参构造函数为默认父对象,如果不先在无参构造函数中初始化变量,则父类变量值都会是默认声明值,如0,null。

    所以,使变量不被序列化的方法有
    a、Transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。
    b、可以将不需要被序列化的字段抽取出来放到父类中,子类实现序列化,父类不实现,则父类的字段数据将不会被序列化。

    5、对敏感字段加密
    服务端给客户端发送序列化对象数据,并在序列化时进行加密,客户端用解密密钥,在反序列化时,对密码读取,保证了序列化对象的数据安全。

    在序列化过程中,虚拟机会试图调用对象类里的 writeObject 和 readObject 方法,进行用户自定义的序列化和反序列化,如果没有这样的方法,则默认调用是 ObjectOutputStream 的 defaultWriteObject 方法以及 ObjectInputStream 的 defaultReadObject 方法。用户自定义的 writeObject 和 readObject 方法可以允许用户控制序列化的过程,比如可以在序列化的过程中动态改变序列化的数值。基于这个原理,可以在实际应用中得到使用,用于敏感字段的加密工作。

    如RMI技术。

    相关文章

      网友评论

          本文标题:Serializable接口

          本文链接:https://www.haomeiwen.com/subject/bauhcqtx.html