改善Java程序建议12

建议12:避免用序列化类在构造函数中为不变量赋值

一般来说,final标识的属性是不变量,也就是说只能赋值一次,不能重复赋值,但是在序列化类中有些不一样。

public class Person implemnets Serializable{
  private static final long serialVersionUID = 71282334L;
  //不变量
  public final String name = "混世魔王";
}

这个Person类(此时V1.0版本)被序列化,然后存储在磁盘上,在被反序列化时name属性会重新计算其值,(这与static变量不同,static变量压根就没有保存在数据流中),比如name属性修改成了“德天使”(版本升级为V2.0),那么反序列化对象的name值就是“德天使”。也就是说,如果final属性是一个直接量,在反序列化时就会重新计算。

接下来看另一种赋值方法:通过构造函数赋值。

public class Person implements Serializable {
  private static final long serialVersionUID = 91282334L;
  public final String name;
  public Person(){
    name = "混世魔王";
  }
}

然后进行序列化,然后在修改name="德天使",接着反序列化。结果name仍然是“混世魔王”。

** 这里涉及到反序列化的另一个规则:反序列化时构造函数不会执行**

反序列化的过程是这样的:JVM从数据流中获取一个Object对象,然后根据数据流中的类文件描述信息(在序列化时,保存到磁盘的对象文件中包含了类的描述信息,注意是类描述信息,不是类)查看,发现是final变量,需要重新计算,于是引用Person类中的name值,而此时JVM又发现name竟然没有复制,不能引用,于是它不在初始化,保持原值状态,所以仍然是“混世魔王”。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容

  • Spring Cloud为开发人员提供了快速构建分布式系统中一些常见模式的工具(例如配置管理,服务发现,断路器,智...
    卡卡罗2017阅读 134,958评论 19 139
  • importUIKit classViewController:UITabBarController{ enumD...
    明哥_Young阅读 3,885评论 1 10
  • 1. Java基础部分 基础部分的顺序:基本语法,类相关的语法,内部类的语法,继承相关的语法,异常的语法,线程的语...
    子非鱼_t_阅读 31,766评论 18 399
  • title: fedora安装virtualboxid: 22categories: linux的学习记录date...
    jeffleefree阅读 429评论 0 1
  • 余 异域 初相遇 有缘齐聚 今偏安一隅, 依然心丝万缕 独坐无言也自语 庸人自扰乱思绪 不如细听一曲 宫商角徵羽 ...
    晨雨曦阅读 170评论 0 0