色谈Java序列化:女孩子慎入 - 第280篇
优美格式地址: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篇相关推荐
- java邮件接收代码,JavaMail入门第四篇 接收邮件(示例代码)
上一篇JavaMail入门第三篇 发送邮件中,我们学会了如何用JavaMail API提供的Transport类发送邮件,同样,JavaMail API中也提供了一些专门的类来对邮件的接收进行相关的操 ...
- java 读取邮件正文_JavaMail入门第五篇 解析邮件
上一篇JavaMail入门第四篇 接收邮件中,控制台打印出的内容,我们无法阅读,其实,让我们自己来解析一封复杂的邮件是很不容易的,邮件里面格式.规范复杂得很.不过,我们所用的浏览器内置了解析各种数据类 ...
- java script 6 折线_Java入门第六篇:Java script(js)的事件
[js中的事件分类] 1.鼠标事件 onclick.ondbclick.onmouseover.onmouseout 等 2.HTML事件: onload/onunload/onsubmit/onre ...
- 烦不烦,别再问我时间复杂度了:这次不色,女孩子进来吧
相关历史文章(阅读本文之前,您可能需要先看下之前的系列?) 色谈Java序列化:女孩子慎入 - 第280篇 「内心世界:前面一篇文章,度没控制好,差点就变成 黄色编程 了,这篇应该怎么写呢,不要毁了我 ...
- kotlin和python哪个好_python替代品for一些java及kotlin功能(慎入啊慎入)
python替代品for一些java及kotlin功能(慎入啊慎入) Stream API 在python2时代,那年头java 8还未流行,java6还没有内置map.filter.reduce三大 ...
- 谈过几任女朋友,发现了这些女孩子的心思小秘密
本没打算写这样的话题,毕竟是因人而异,不过最近朋友们聊天开玩笑,总让我传授找女朋友经验,说实话,我真的没资格在感情问题上有多大发言权,但是也知道粉友不少是单身青年,就索性谈谈自己的一些看法,也许不少人 ...
- 转行学编程,女孩子适合web前端还是Java?
纵观现阶段互联网web前端开发工程师的就业人员,女孩子从事这个行业的比例不大,由于这种想象的存在,当有女孩说想要学习web前端开发,想成为一个牛逼的程序员的时候,很多不一样的声音就出来了,说女生不适合 ...
- 成都女孩子报Java语言培训班怎么样_Java好就业吗?
成都女孩子报Java语言培训班怎么样?大家一提到Java程序员刻板印象都是男程序员,事实上女生当Java程序员确实要少很多,但是这就证明了女孩子真的不适合学Java语言,当不了Java程序员了吗?其实 ...
- 如果编程语言是女孩子
试想一下,当Java.C++.Python.Ruby.PHP.C#.JS等编程语言变成了动漫人物会是怎样的一幅场景呢?下面就一起看看在日本作家渡辺将人的笔下,各种编程语言都是哪类可爱的女孩子的吧! 究 ...
最新文章
- 让浏览器判断html为手机页面,判断是从手机端还是客户端访问的页面,判断浏览器类型...
- 这才是真的码“农”!Linux基金会要推广开源技术种菜了
- java获取gbk文件名 linux_Java读取linux系统中文文件名时候乱码,并显示文件不存在...
- php 组合模式,php设计模式(十三)透明组合模式
- stack overflow at line
- 【java】List 根据实体属性值搜索
- RichEdit控件的使用(未完)
- 自定义控件使用InnerDefaultProperty提示“内不允许包含文字内容”
- initwithcoder和 initwithframe 区别?
- 2.两数相加(leetcode-2)
- 系统安装:D-Link DWL-G122 USB无线网卡驱动安装配置
- 一键登录163邮箱方法
- Android开发-API指南-uses-feature(1)
- 主力吸筹猛攻指标源码_主力吸筹猛攻指标源码-通达信公式 -程序化交易(CXH99.COM)...
- Swagger2生成在线接口文档并导出pdf文件
- 鸿蒙系统能玩魔兽世界吗,《魔兽世界》7.0配置公布:仍不放弃XP
- idea翻译插件Translation Tkk错误
- C语言文件读写,相对路径,基本操作,秒懂
- 计算机中的域到底是什么意思?有什么用出?我们为什么要加入域?域和工作组有什么分别呢?
- windows md5sum
热门文章
- 【ps操作】图片裁切、校色、修复以及蒙版的使用
- oracle两个都下载地址,oracle 10.2.0.4下载地址
- android工程怎么连手机,android studio与手机连接调试步骤详解
- 百度地图多点路线规划_精选文章 | 工业解密:百度地图背后的路线时长预估模型!...
- 姑娘,你为什么要编程呢
- 【Python】小甲鱼课后习题第17、18、19讲--函数(上)
- 硬质聚氨酯(PUR)和聚异氰脲酯(PIR)泡沫产品保温材料英国UKCA认证- EN 14318-1
- Worthington 木瓜蛋白酶的说明及应用
- 【机器学习】深入剖析梯度提升决策树(GBDT)分类与回归
- 微星 Summit E16Flip Evo和 微星 Summit E14 Flip Evo区别对比 评测