谨慎的使用 Serializable 接口(74)

编程入门 行业动态 更新时间:2024-10-25 14:26:04

<a href=https://www.elefans.com/category/jswz/34/1768244.html style=谨慎的使用 Serializable 接口(74)"/>

谨慎的使用 Serializable 接口(74)

2019独角兽企业重金招聘Python工程师标准>>>

  • 序列化带来的直接开销非常低,但是长期开销是实实在在的

实现 Serializable 接口最大的代价就是

  • 一旦一个类发布,大大降低了改变其实现的灵活性
  • 因为此时,它的字节流编码就变成了其导出API的一部分
  • 如果不设计一种自定义序列化形式,仅仅使用默认序列化,
    • 那么私有和包级私有实例,都变成导出api的一部分
    • 不符合最低限度访问域的准则
    • 默认序列化可能出现新老版本序列化和反序列化不兼容
      • 仍然保留老接口,会带来别的问题、隐患
    • 仔细设计一种高质量的序列化形式,长期使用,初始付出的成本是值得的
  • 序列化会使得类的演变受到限制
    • 流的唯一标识符有关(序列版本UID)
      • private static final long serialVersionUID = 1L;
      • 如果不定义该标识符,会在运行时,调用一个复杂的过程自动生成
        • 而且内部改变,会导致,自动计算id 值改变,序列化兼容被打破
          • 导致InvalidClassException

实现 Serializable 第二个代价:

  • 增加了出现 BUG、安全漏洞的可能性
    • 对象是构造器创建的
    • 序列化机制是语言之外的对象创建机制
      • 反序列化机制都是一个隐藏的构造器
        • 该构造器相对于真正的构造器,约束条件往往被忽略
      • 默认序列化机制的反序列化过程的约束关系很容易遭到破坏、非法访问

第三个代价:

  • 随着类发行新的版本、相关测试负担也增加了
    • 一个可序列化的类被修订后,要检查,在新版本序列化一个类,在老版本是否可以反序列化,反之亦然
    • 测试工作量乘积增长

实现Serializable 确实带来了益处:

  • 比如一些值类:Date、BigInteger 可以实现Serializable
  • 活动实体类:Thread pool 一般不实现Serializable

为了继承而设计的类、接口,尽可能少的实现 Serializable 接口

  • 但是如果专门设计参与到某个框架的类,该框架要求必须实现Serializable 时例外
  • 为了继承而设计的类,实现了Serializable 接口的有
    • Throwable类:RMI异常,可以从服务端传到客户端
    • Component :GUI 可以被发送保存和恢复
    •  HttpServlet抽象类:会话状态可以被缓存
  • 如果实现带有实例域的类,实例域被初始化成默认值会违背约束条件
    • 就必须添加下文中的方法

如果一个专门为了继承而设计的类不是可序列化的,

  • 就不可能编写出可序列化的子类。
  • 特别是,如果超类没有提供可访问的无参构造器,子类也不可能做到可序列化。
  • 因此,对于为继承而设计的不可序列化的类,你应该考虑提供一个无参构造器。

内部类不应该实现Serializable。

  • 它们使用编译器产生的合成域来保存指向外围实例的引用,
  • 以及保存来自外围作用域的局部变量的值。
  • 因此,内部类的默认序列化形式是定义不清楚的。
  • 然而,静态成员类却是可以实现Serializable接口。

千万不要认为实现Serializable接口会很容易。

  • 除非一个类在用了一段时间之后就会被抛弃,
    • 否则,实现Serializable接口就是个很严肃的承诺,必须认真对待。
  • 如果一个类是为了继承而设计的,则更加需要加倍小心。
    • 对于这样的类而言,在“允许子类实现Serializable接口”或“禁止子类实现Serializable接口”两者之间的一个折衷设计方案是,
      • 提供一个可访问的无参构造器,这种设计方案允许(但不要求)子类实现Serializable接口。
      • 至于为什么需要父类有一个无参的构造器,
        • 是因为子类先序列化自身的时候先调用父类的无参的构造器。 
        • 实例:
          • private void writeObject(java.io.ObjectOutputStream out) throws IOException{ out.defaultWriteObject();//先序列化对象 out.writeInt(parentvalue);//再序列化父类的域 } private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException{ in.defaultReadObject();//先反序列化对象 parentvalue=in.readInt();//再反序列化父类的域 } 
            

             

转载于:

更多推荐

谨慎的使用 Serializable 接口(74)

本文发布于:2024-03-08 18:31:52,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1721829.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:谨慎   接口   Serializable

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!