优美格式地址:https://mp.weixin.qq.com/s/8tcHFjY1VawAkzdArkSzJQ

悟纤:师傅,最近我老是碰到一个异常:java.io.NotSerializableException

师傅:徒儿你这是没有序列化。

悟纤:序列化这是啥?为啥要序列化呢?

师傅:好了,咱们今天就来讲一讲。

为了提高访问速度,我们会使用到缓存,比如memcached来缓存一些不频繁变化的数据。这时候,将对象存到缓存管理器之后,那么可能就会遇到如上徒儿说的异常了。

BTW:别人是转角遇到爱,爱徒是转角遇到异常。

对于NotSerializableException在Java中很好解决,但是很多人却不知道这是why,今天师傅给你好好讲解一番,悟纤你可得长点心呐,把耳朵带上。

一、何为序列化

序列化:把对象转换为字节序列的过程。

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

这里的概念可能有点不好理解。我们得清楚,JVM是可以处理对象的,在不序列化的情况下,是以对象的状态在虚拟机中的,这时候,如果我们要将对象保存到缓存Memcached中的话,其中JVM有自己的进程,而Memcached也有自己的进程,两个不同进程之间要通讯,这就有话说了。

JVM对Memcached说:来我把这个对象传给你,你给我缓存一下,之后我需要的时候在找你要。

Memcached对JVM说:老兄,不行呐,我不懂得如何处理Java对象呐。

JVM对Memcached说:那我把对象处理为字节你总可以处理了吧。

Memcached说JVM说:这个可以有,那给我传字节,我也给你返回字节,你自己转换为对象吧。

JVM心里暗讽:你咋这么笨呐,好吧,优秀如你,我只能默默看着。

BTW:字节(Byte )是计算机信息技术用于计量存储容量的一种计量单位,作为一个单位来处理的一个二进制数字串,是构成信息的一个小单位。

「百度百科」:https://baike.baidu.com/item/字节/1096318?fr=aladdin

悟纤:那师傅都有什么情况需要进行序列化呐?

师傅:悟纤别急,听为师慢慢道来。

二、什么场景下需要序列化

当你想把内存中的对象状态保存到一个文件中或者数据库中时候;

当你想用套接字在网络上传送对象的时候;

当你想通过RMI(Remote Method Invocation:远程方法调用)传输对象的时候;

BTW:当要 跨进程跨网络传输对象的时候,这时候基本要序列化了。

悟纤:师傅,你这波BTW骚气外露耶。

师傅:(咳嗽)悟纤,你头又痒了吧。

下面举几个具体的场景:

(1)对象储存到缓存中(这个大家经常使用到吧,memcached.set(key,value))。

(2)把一个对象写到文件中(这个待会咱们会来写个小栗子)。

三、如何序列化

如何进行序列化呐?常见的有如下几种方式

3.1 Serializable接口

Serializable最常见就是实现这个序列化标识接口,说它是标识是因为它的接口源码中其实什么都没有定义,纯粹只是为了标识而使用,一个类只有实现了这个接口,我们才能对它进行序列化。

3.2Externalizable接口

Externalizable这个接口其实是继承了Serializable,它更加灵活一点,它里面定义了writeExternal和readExternal两个方法分别用于序列化和反序列化使用。通过这两个方法,我们可以自己决定需要序列化那些数据。如果对象中涉及到很少的属性需要序列化,大多数属性无需序列化,这种情况使用Externalizable接口是比较灵活的。

3.3 第三方序列化

也可以使用第三方的序列化进行操作,比如:hessian。

hessian它的一个最大特色就是跨语言,hessian提供了一整套的byte[]的写入规范。这样其他语言在实现hessian序列化的时候就可以参照这套的标准规范,从而达到不同语言之间的兼容效果,因此hessian的序列化都是围绕这byte数组来的。

四、Java序列化实操

接下来 为师 将安排2号技师 给大家来个激情的表演,请大家准备好纸巾。

2号技师要表演什么呢?她要表演将一个MeiMei对象,写到文件中,然后在成功的掏出来。

2号技师要开始了,大家准备好了没有。

环境说明

(1)JDK: 1.8
(2)OS:MAC

4.1 准备一个美眉

我们先准备一个美眉类,MeiMei.java:

package com.kfit;import java.io.Serializable;public class MeiMei implements Serializable{private static final long serialVersionUID = 1L;private long id;private String name;//美眉的名称private String cup;//你懂得public long getId() {return id;}public void setId(long id) {this.id = id;}public String getName() {return name;}public void setName(String name) {this.name = name;}public String getCup() {return cup;}public void setCup(String cup) {this.cup = cup;}@Overridepublic String toString() {return "MeiMei [id=" + id + ", name=" + name + ", cup=" + cup + "]";}
}

BTW:这个类没啥特殊之处,就是实现了接口Serializable。

4.2 开始表演

2号技师开始你的表演吧,舞台已经为你准备好了,这时候,只见2号技师,缓缓走上舞台,用她婀娜多姿的身材,开始了她精彩的表演......(想想都有点小激动 (๑>◡<๑) )

package com.kfit;import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;public class Test {public static void main(String[] args) throws IOException, ClassNotFoundException {/** 序列化.*/MeiMei mm = new MeiMei();mm.setId(2);mm.setName("2号技师");mm.setCup("36C");ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("/data/tmp/meimei.out")));output.writeObject(mm);output.close();System.out.println("序列化成功:"+mm);/** 反序列化*/ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("/data/tmp/meimei.out")));MeiMei mm2 = (MeiMei) input.readObject();input.close();System.out.println("反序列化成功:"+mm2);}}    

BTW:

(1)这里关注Main方法,就是将对象序列化和反序列化。

(2)ObjectOutputStream代表对象输出流,ObjectInputStream代表对象输入流。

(3)流执行之后记得close掉。

Run一下吧,观察控制台输出如下信息:

序列化成功:MeiMei [id=2,name=2号技师, cup=36C]
反序列化成功:MeiMei[id=2, name=2号技师, cup=36C]

如果将MeiMei的implements Serializable去掉就会报如下错:

Exception inthread "main" java.io.NotSerializableException: com.kfit.MeiMeiat java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)atjava.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)at com.kfit.Test.main(Test.java:22)

看,技师的衣服不能随便脱吧,这可闹大了。

4.3 扒开衣服看看

2号技师慢慢的将衣服….此处省略一万字。

Java对象写到文件之后,到底是什么东东呐,扒开meimei.out看下。

啥,你不知道怎么扒开,给你一个女的,你还不会了。

在Mac下可以使用Hex Fiend打开二进制文件,下载地址:

https://github.com/ridiculousfish/HexFiend/releases

另外一种简单的方式就是使用vi进行打开(这是Mac哦),主要两步操作(相信玩Mac的都能看得懂):

(1)首先以二进制方式编辑这个文件
vi -b /data/tmp/meimei.out
(2)使用xxd转换为16进制
:%!xxd

扒开之后,可以看到如下文本:

怎么样,好看吗,看不懂,看不懂就对了,衣服又不是你脱的,你怎么能看明白呐,这种事情还得自己来。

这就是字节,字节可以保存到文件中,也可以保存到数据库中,取出来字节之后,就可以在转换为原来的数据信息了。

4.4 serialVersionUID

美女,serialVersionUID这是啥,你干嘛带着,这是我的唯一标识,要脱衣服,就得有serialVersionUID,不然不让脱哦。

这个serialVersionUID有啥用呐:来验证版本一致性的。在反序列化时,jvm会把传来的字节流中的serialVersionUID和本地相应实体类的serialVersionUID进行比较,如果相同就认为一致,可以进行反序列化,否则出现InvalidCastException异常。

怎么来验证下是不是2号技师呐?只需要将脱衣服的代码删除即可:

//        MeiMei mm = new MeiMei();
//        mm.setId(2);
//        mm.setName("2号技师");
//        mm.setCup("36C");
//
//        ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("/data/tmp/meimei.out")));
//        output.writeObject(mm);
//        output.close();
//        System.out.println("序列化成功:"+mm);

BTW:将这段序列化的代码注释掉。(前提是已经执行成功过一次,已经有meimei.out文件了)

此时执行剩下的代码(也就是反序列化代码),会发现此时还是可以匹配到2号技师的,只见控制台打印如下信息:

反序列化成功:MeiMei[id=2, name=2号技师, cup=36C]

紧接着将MeiMei类中的serialVersionUID修改为2L。

这时候在摸一下,哦,不,口误是run一下,完了,2号技师丢了:

Exception in thread "main" java.io.InvalidClassException: com.kfit.MeiMei;local class incompatible: stream classdesc serialVersionUID = 1,
local class serialVersionUID = 2

BTW:由于serialVersionUID不一致,所以匹配失败,对象反序列化也失败了。

4.5 这部分不让摸:static

「内心世界:不敢写了,在写就要变成 黄色编程 了,聪明如你,自己领悟吧」

static静态变量不是对象状态的一部分,因此它不参与序列化。那么反序列化之后。我们可以这么理解,静态变量的话,不属于对象的特有的,谁都可以进行改变,所以序列化了之后,在反序列返回来可能就不是那个值了。

4.6 加钱就让:static-final

如果一个变量修饰为static final的话,这时候由于final定义的不可被改变,那么这时候这个属性就会被持久化了。

4.7 transient:定义临时变量

transient关键字的作用,简单地说,就是让某些被修饰的成员属性变量不被序列化。我们可以在MeiMei类添加一个属性:

private transient int age;

那么在序列化的设置age为18,这时候在运行:

序列化成功:MeiMei [id=2,name=2号技师, cup=36C, age=18]
反序列化成功:MeiMei[id=2, name=2号技师, cup=36C, age=0]

看到没有age并没有被序列化,因为反序列回来之后age为0了。

五、悟纤小结

今天师傅也讲了不少东西了,不知道悟纤你听懂了多少,你来给大家总结下吧:

(1)序列化和反序列化的定义:就是对象转换为字节和字节转换为对象的过程。

(2)为什么需要序列化:主要是为了跨进程跨网络的数据传输。

(3)序列化的方式:常用的就是实现接口Serializable

(4)如何让属性不序列化:只要将属性定义为transient即可。

好,不错,总结的差不多。今天能记住这些就够了,好了悟纤,继续赶路吧,西天还远着呐。

白龙马蹄朝西,驮着唐三藏跟着仨徒弟。

西天取经上大路,一走就是几万里。

白龙马脖铃儿急,颠簸唐玄奘小跑仨兄弟,

西天取经不容易,容易干不成大业绩。

我就是我,是颜色不一样的烟火。
我就是我,是与众不同的小苹果。

à悟空学院:http://t.cn/Rg3fKJD

学院中有Spring Boot相关的课程!点击「阅读原文」进行查看!

SpringBoot视频:http://t.cn/R3QepWG

Spring Cloud视频:http://t.cn/R3QeRZc

SpringBoot Shiro视频:http://t.cn/R3QDMbh

SpringBoot交流平台:http://t.cn/R3QDhU0

SpringData和JPA视频:http://t.cn/R1pSojf

SpringSecurity5.0视频:http://t.cn/EwlLjHh

Sharding-JDBC分库分表实战:http://t.cn/E4lpD6e

色谈Java序列化:女孩子慎入 - 第280篇相关推荐

  1. java邮件接收代码,JavaMail入门第四篇 接收邮件(示例代码)

    上一篇JavaMail入门第三篇 发送邮件中,我们学会了如何用JavaMail API提供的Transport类发送邮件,同样,JavaMail API中也提供了一些专门的类来对邮件的接收进行相关的操 ...

  2. java 读取邮件正文_JavaMail入门第五篇 解析邮件

    上一篇JavaMail入门第四篇 接收邮件中,控制台打印出的内容,我们无法阅读,其实,让我们自己来解析一封复杂的邮件是很不容易的,邮件里面格式.规范复杂得很.不过,我们所用的浏览器内置了解析各种数据类 ...

  3. java script 6 折线_Java入门第六篇:Java script(js)的事件

    [js中的事件分类] 1.鼠标事件 onclick.ondbclick.onmouseover.onmouseout 等 2.HTML事件: onload/onunload/onsubmit/onre ...

  4. 烦不烦,别再问我时间复杂度了:这次不色,女孩子进来吧

    相关历史文章(阅读本文之前,您可能需要先看下之前的系列?) 色谈Java序列化:女孩子慎入 - 第280篇 「内心世界:前面一篇文章,度没控制好,差点就变成 黄色编程 了,这篇应该怎么写呢,不要毁了我 ...

  5. kotlin和python哪个好_python替代品for一些java及kotlin功能(慎入啊慎入)

    python替代品for一些java及kotlin功能(慎入啊慎入) Stream API 在python2时代,那年头java 8还未流行,java6还没有内置map.filter.reduce三大 ...

  6. 谈过几任女朋友,发现了这些女孩子的心思小秘密

    本没打算写这样的话题,毕竟是因人而异,不过最近朋友们聊天开玩笑,总让我传授找女朋友经验,说实话,我真的没资格在感情问题上有多大发言权,但是也知道粉友不少是单身青年,就索性谈谈自己的一些看法,也许不少人 ...

  7. 转行学编程,女孩子适合web前端还是Java?

    纵观现阶段互联网web前端开发工程师的就业人员,女孩子从事这个行业的比例不大,由于这种想象的存在,当有女孩说想要学习web前端开发,想成为一个牛逼的程序员的时候,很多不一样的声音就出来了,说女生不适合 ...

  8. 成都女孩子报Java语言培训班怎么样_Java好就业吗?

    成都女孩子报Java语言培训班怎么样?大家一提到Java程序员刻板印象都是男程序员,事实上女生当Java程序员确实要少很多,但是这就证明了女孩子真的不适合学Java语言,当不了Java程序员了吗?其实 ...

  9. 如果编程语言是女孩子

    试想一下,当Java.C++.Python.Ruby.PHP.C#.JS等编程语言变成了动漫人物会是怎样的一幅场景呢?下面就一起看看在日本作家渡辺将人的笔下,各种编程语言都是哪类可爱的女孩子的吧! 究 ...

最新文章

  1. 让浏览器判断html为手机页面,判断是从手机端还是客户端访问的页面,判断浏览器类型...
  2. 这才是真的码“农”!Linux基金会要推广开源技术种菜了
  3. java获取gbk文件名 linux_Java读取linux系统中文文件名时候乱码,并显示文件不存在...
  4. php 组合模式,php设计模式(十三)透明组合模式
  5. stack overflow at line
  6. 【java】List 根据实体属性值搜索
  7. RichEdit控件的使用(未完)
  8. 自定义控件使用InnerDefaultProperty提示“内不允许包含文字内容”
  9. initwithcoder和 initwithframe 区别?
  10. 2.两数相加(leetcode-2)
  11. 系统安装:D-Link DWL-G122 USB无线网卡驱动安装配置
  12. 一键登录163邮箱方法
  13. Android开发-API指南-uses-feature(1)
  14. 主力吸筹猛攻指标源码_主力吸筹猛攻指标源码-通达信公式 -程序化交易(CXH99.COM)...
  15. Swagger2生成在线接口文档并导出pdf文件
  16. 鸿蒙系统能玩魔兽世界吗,《魔兽世界》7.0配置公布:仍不放弃XP
  17. idea翻译插件Translation Tkk错误
  18. C语言文件读写,相对路径,基本操作,秒懂
  19. 计算机中的域到底是什么意思?有什么用出?我们为什么要加入域?域和工作组有什么分别呢?
  20. windows md5sum

热门文章

  1. 【ps操作】图片裁切、校色、修复以及蒙版的使用
  2. oracle两个都下载地址,oracle 10.2.0.4下载地址
  3. android工程怎么连手机,android studio与手机连接调试步骤详解
  4. 百度地图多点路线规划_精选文章 | 工业解密:百度地图背后的路线时长预估模型!...
  5. 姑娘,你为什么要编程呢
  6. 【Python】小甲鱼课后习题第17、18、19讲--函数(上)
  7. 硬质聚氨酯(PUR)和聚异氰脲酯(PIR)泡沫产品保温材料英国UKCA认证- EN 14318-1
  8. Worthington 木瓜蛋白酶的说明及应用
  9. 【机器学习】深入剖析梯度提升决策树(GBDT)分类与回归
  10. 微星 Summit E16Flip Evo和 微星 Summit E14 Flip Evo区别对比 评测