点击上方 好好学java ,选择 星标 公众号

重磅资讯、干货,第一时间送达
今日推荐:干掉 Navicat:这个 IDEA 的兄弟真香!个人原创100W+访问量博客:点击前往,查看更多

我们都知道,新建一个对象的时候实现 Serializeable 接口,但为什么要这么做?什么时候这样子做?这样子做会不会出现幺蛾子?阿粉一个三连差点把自己都问懵逼了……

那接下来,大家就和阿粉一起简单了解一下这个知识点吧……

序列化的定义是:将一个对象编码成一个字节流(I/O);而与之相反的操作被称为反序列化。

序列化的目的是为了方便数据的传递以及存储到磁盘上(把一个Java对象写入到硬盘或者传输到网路上面的其它计算机,这时我们就需要将对象转换成字节流才能进行网络传输。对于这种通用的操作,就出现了序列化来统一这些格式)。

附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,笔者这几年及春招的总结,github 1.1k star,拿去不谢!

下载方式

1. 首先扫描下方二维码

2. 后台回复「Java面试」即可获取

简单来说序列化就是一种用来处理对象流的机制。将对象转化成字节序列后可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。

使用场景:所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。比如 Redis 将对象当做字符串存储的时候,如果对象实现了序列化,则只需要将对象直接存储即可(java会自动将对象转换成序列化后的字节流);否则需要自己将对象转换成 json 字符串存储,不过 json 字符串相对更加节省内存空间一些。

通常建议:程序创建的每个JavaBean类都实现 Serializeable 接口。但是实现 Serializeable 接口也需要小心谨慎。正如《Effective Java》中第 74 条提到的那样:

如何实现序列化

在 Java 中,只要一个类实现了 java.io.Serializable 接口,它就可以被序列化(枚举类也可以被序列化)。

例如:每个枚举类型都会默认继承类java.lang.Enum,而Enum类实现了Serializable接口,所以枚举类型对象都是默认可以被序列化的。

// DeletedEnum 类,表示删除状态
@Getter
@AllArgsConstructor
public enum DeletedEnum {NO_DELETED(0,"未删除"),DELETED(1,"已删除");public final Integer status;public final String name;
}

下图是 java.lang.Enum 类:

而一个普通的类想实现序列化,只需要实现 Serializable 接口即可:

@Data
public class User implements Serializable {//序列化版本号private static final long serialVersionUID = 1111013L;transient private String name;private int age;public static void main(String[] args) {User user = new User();user.setAge(12);user.setName("小路飞");System.out.println(user);}
}

输出结果如下:

User(name=小路飞, age=12)

那为什么一个类实现了 Serializable 接口,它就可以被序列化呢?

这是因为它使用 ObjectOutputStream 来持久化对象到文件中,使用了 writeObject 方法,该方法又调用了如下方法:

    /*** Underlying writeObject/writeUnshared implementation.*/private void writeObject0(Object obj, boolean unshared) throws IOException {……// remaining casesif (obj instanceof String) {writeString((String) obj, unshared);} else if (cl.isArray()) {writeArray(obj, desc, unshared);} else if (obj instanceof Enum) {writeEnum((Enum<?>) obj, desc, unshared);} else if (obj instanceof Serializable) {writeOrdinaryObject(obj, desc, unshared);} else {if (extendedDebugInfo) {throw new NotSerializableException(cl.getName() + "\n" + debugInfoStack.toString());} else {throw new NotSerializableException(cl.getName());}}……}

从上述代码可知,如果被写对象的类型是String,或数组,或 Enum,或 Serializable,那么就可以对该对象进行序列化,否则将抛出 NotSerializableException。

:String 类型的对象、枚举类型的对象、数组对象,都是默认可以被序列化的,并生成默认的序列化版本号。

我看网上的资料都有讲使用 Externalizable 接口和使用 transient 关键字来实现序列化的方法,但阿粉感觉用的不多,所以在这里就不过多的赘述了,况且它们其实都是基于 Serializable 接口实现的序列化。

如何自动生成序列化版本号

idea IDE

安装 serialVersionUID 插件即可。

eclipse

一般来说有两种生成方式:

  • 一个是默认的1L,比如:private static final long serialVersionUID = 1L;

  • 一个是根据类名、接口名、成员方法及属性等来生成一个64位的哈希字段。实现序列化后,类名上会出现黄色波浪下划线,选择第一项,添加已生成的串行版本标识即可自动生成一个。

序列化版本号的用处

在 java.io.Serializable 的文档中的解释是这样的:

大致意思是如下

因为反序列化必须拥有 class 文件,但随着项目的升级,class 文件也会升级,序列化怎么保证升级前后的兼容性呢?

序列化运行时与每个可序列化的类关联一个版本号,称为 serialVersionUID,在反序列化期间使用该版本号来验证序列化对象的发送者和接收者是否已加载了该对象的与序列化兼容的类。如果接收方已为该对象加载了一个与相应发送方类具有不同的 serialVersionUID 的类,则反序列化将导致 InvalidClassException。可序列化的类可以通过声明一个名为 serialVersionUID 的字段来显式声明其自己的 serialVersionUID,该字段必须是静态的,最终的且类型为 long:

ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;

只要版本号相同,即使更改了序列化属性,对象也可以正确被反序列化回来。

@Data
public class User implements Serializable {//序列化版本号    private static final long serialVersionUID = 1111013L;private String name;private int age;
}

如果反序列化使用的 class 的版本号与序列化时使用的不一致,反序列化会报 InvalidClassException 异常。

如果可序列化的类未明确声明 serialVersionUID ,则序列化运行时将根据该类的各个方面为该类计算默认的 serialVersionUID 值,如Java(TM)对象序列化规范中所述。但是,强烈建议所有可序列化的类显式声明 serialVersionUID 值,因为默认的 serialVersionUID 计算对类详细信息高度敏感,而类详细信息可能会根据编译器的实现而有所不同,因此可能在反序列化期间导致意外的 InvalidClassExceptions。

而且,默认值不利于 jvm 间的移植,可能class文件没有更改,但不同 jvm 可能计算的规则不一样,这样也会导致无法反序列化。

因此,为了保证不同Java编译器实现之间的 serialVersionUID 值一致,可序列化的类必须声明一个显式的 serialVersionUID 值。强烈建议显式 serialVersionUID 声明在可能的情况下使用 private 修饰符,因为此类声明仅适用于立即声明的类 serialVersionUID字段作为继承成员不起作用。

最后,使用默认机制在序列化对象时,不仅会序列化当前对象,还会对该对象引用的其它对象也进行序列化,同样地,这些其它对象引用的另外对象也将被序列化,以此类推。所以,如果一个对象包含的成员变量是容器类对象,而这些容器所含有的元素也是容器类对象,那么这个序列化的过程就会较复杂,开销也较大。

参考

  • https://www.cnblogs.com/kubixuesheng/p/10350523.html

  • https://stackoverflow.com/questions/285793/what-is-a-serialversionuid-and-why-should-i-use-it

  • https://juejin.im/post/5ce3cdc8e51d45777b1a3cdf

  • 《Effective Java》中文版第二版

最后,再附上我历时三个月总结的 Java 面试 + Java 后端技术学习指南,笔者这几年及春招的总结,github 1.1k star,拿去不谢!

下载方式

1. 首先扫描下方二维码

2. 后台回复「Java面试」即可获取

我把序列化玩成了这样,吊锤了一波面试官相关推荐

  1. android 修改充电图标,更换图标、修改充电音...这个软件把iPhone玩成了安卓

    原标题:更换图标.修改充电音...这个软件把iPhone玩成了安卓 TASTER科技|快捷指令 9月17日,苹果推送IOS 14正式版,在无数用户升级到IOS 14之后,iPhone充电提示音火了! ...

  2. # linux mini版 玩成DVD版(哈哈哈哈)

    linux mini版 玩成了DVD版 文章目录 linux mini版 玩成了DVD版 Less查看文件: 停止ping命令:按CTRL+c或CTRL+z 查看现在所在的文件路径的地址 pwd 查找 ...

  3. 阿里研究院花几年心得终成趣谈网络协议,附技术官讲解

    苦且绕不过去.经过多次放弃之后,我发现在我的职业生涯中,网络这一关无论如何也绕不过去.本来觉得写Java程序时可以依赖别人的库,所以就不用关心这么多底层的技术了,但是到后来才发现,服务数量一多,吞吐量 ...

  4. 【059期】面试官问:序列化是什么,为什么要序列化,如何实现?

    >>号外:关注"Java精选"公众号,回复"面试资料",免费领取资料!"Java精选面试题"小程序,3000+ 道面试题在线刷, ...

  5. 面试官问你斐波那契数列的时候不要高兴得太早 搞懂C语言函数指针 搜索引擎还可以这么玩? 那些相见恨晚的搜索技巧...

    面试官问你斐波那契数列的时候不要高兴得太早 前言 假如面试官让你编写求斐波那契数列的代码时,是不是心中暗喜?不就是递归么,早就会了.如果真这么想,那就危险了. 递归求斐波那契数列 递归,在数学与计算机 ...

  6. 面试官:如何实现一个高性能的,短链接生成服务?(附源码)

    点击上方"搜云库技术团队",选择"设为星标" 回复"1024"或"面试题"获取4T学习资料 面试官:你平时是否留意过一些 ...

  7. 面试官:请实现一个通用函数把 callback 转成 promise

    1. 前言 大家好,我是若川.最近组织了源码共读活动,感兴趣的可以加我微信 ruochuan12 参与,或者在公众号:若川视野,回复"源码"参与,每周大家一起学习200行左右的源码 ...

  8. 奇葩面试大赏:四年没见的前女友成了我的面试官

    看着正常人,实则奇葩魂. 面试,是每一个职场人都难以绕开的话题.无论你是初出茅庐的应届毕业生,还是久经沙场的职场老将,都或多或少有过一些印象深刻的面试经历. 我们在面试过程中自我迭代的同时,也不断刷新 ...

  9. 完爆面试官!java工程师成神之路pdf

    正文 二叉树 由 n( n > 0)个有限节点组成一个具有层次关系的集合,看起来就像一个倒挂的树,因此称这样的数据结构为树. 一个节点的子节点个数叫做度,通俗的讲就是树叉的个数.树中最大的度叫做 ...

最新文章

  1. 面试题编程题11-python 生成随机数
  2. 女鬼之阴魂不散(C#版)
  3. 共享单车,信息安全应未雨绸缪
  4. 设置本地Nexus存储库并从Maven部署WAR文件
  5. Hive近百个常规函数详解
  6. 第六章 副词(Les adverbes )
  7. 手把手教你怎样运用手机群控软件赚钱-手游工作室篇
  8. Activiti7工作流引擎介绍
  9. 数字经济发展现状_(我的)数字媒体的现状
  10. 利用Cam对Hopenet网络模型进行可视化
  11. java oracle 时间查询_Oracle 日期查询
  12. 阿里的互联网三高架构是真的牛!腾讯百度根本模仿不来
  13. 输入框事件监听(三):blur与change的差异
  14. 7.12 10.6-10.10
  15. 工具及方法 - 如何保护眼睛
  16. OOM问题原理解析(四):Bitmap压缩方案总结
  17. 怎么样玩转信息研究方法指南学习笔记
  18. 工欲善其事!有这些工具你才能修出一张完美的照片
  19. 食物链(Food Chain POJ 1182)
  20. \\wsl.localhost 无法访问

热门文章

  1. 翻译:如何用Cocos2d来开发简单的IPhone游戏教程
  2. javascript 学习笔记(四) 倒计时程序
  3. vba 单元格 一系例操作
  4. 从表达式到函数:表面的简洁
  5. Bluetooth GAP介绍
  6. C++ Primer 5th笔记(chap 19 特殊工具与技术)typeid
  7. EOS 共识机制 (3)DPOS+BFT
  8. 6. Qt 信号与信号槽 (7)-QMetaObject:: activate
  9. 数学建模——TOPSIS综合评价模型Python代码
  10. 删除“已禁用输入法”托盘图标