Java序列化系列教程(上)
一定义以及相关概念
互联网的产生带来了机器间通讯的需求,而互联通讯的双方需要采用约定的协议,序列化和反序列化属于通讯协议的一部分。通讯协议往往采用分层模型,不同模型每层的功能定义以及颗粒度不同,例如:TCP/IP协议是一个四层协议,而OSI模型却是七层协议模型。在OSI七层协议模型中展现层(Presentation Layer)的主要功能是把应用层的对象转换成一段连续的二进制串,或者反过来,把二进制串转换成应用层的对象,这两个功能就是序列化和反序列化。一般而言,TCP/IP协议的应用层对应与OSI七层协议模型的应用层,展示层和会话层,所以序列化协议属于TCP/IP协议应用层的一部分。本文对序列化协议的讲解主要基于OSI七层协议模型。
序列化: 将数据结构或对象转换成二进制串的过程。
反序列化:将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程。
二应用场景2.1对象持久化
Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。在实际的生产场景中很多情况下会用到缓存,用到redis来实现缓存的都知道,在往缓存里放数据的时候不管是key还是value都要首先完成序列化,只有序列化后才能依靠redis来存放,当获取数据的时候要反序列化。
2.2对象网络传输
当在实际中使用RMI(远程方法调用)的时候,比如hession调用,dubbo调用,或在网络中传递对象时,都会用到对象序列化,和反序列化。
三如何实现序列化
在Java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化。首先定义一个User类。
1package com.duomeng.product;
2import java.io.*;
3public class User implements Serializable{
4 private static final long serialVersionUID = -6513548580766215238L;
5 public String name;
6 public String pawssWord;
7 public String getName() {
8 return name;
9 }
10 public void setName(String name) {
11 this.name = name;
12 }
13 public String getPawssWord() {
14 return pawssWord;
15 }
16 public void setPawssWord(String pawssWord) {
17 this.pawssWord = pawssWord;
18 }
19}
接着写一个测试类来完成序列化和反序列化的测试,就定义为UserTest.class
1package com.duomen.product;
2import java.io.*;
3public class UserTest {
4 public static void main(String[] args) {
5 User user = new User();
6 user.setName("duomeng");
7 user.setPawssWord("123qwe");
8 try {
9 //序列化
10 ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("user.obj"));
11 objectOutputStream.writeObject(user);
12 objectOutputStream.flush();
13 objectOutputStream.close();
14 //反序列化
15 ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("user.obj"));
16 User oldUser = (User) objectInputStream.readObject();
17 objectInputStream.close();
18 System.out.println("name = [" + oldUser.getName() + "]");
19 System.out.println("password = [" + oldUser.getPawssWord() + "]");
20 } catch (IOException e) {
21 e.printStackTrace();
22 } catch (ClassNotFoundException e) {
23 e.printStackTrace();
24 }
25 }
26}
如果没有什么的问题的,那么结果也一定不出所料的输出如下内容
1name = [duomeng]
2password = [123qwe]
四相关知识
1.通过ObjectOutputStream和ObjectInputStream对对象进行序列化及反序列化
2.一个类如果被实例化,那么这个类必须实现java.io.Serializable,否在在实例化的时候会抛出java.io.NotSerializableException异常,因为在序列化的过程中大概有如下的调用列writeObject ---> writeObject0 --->writeOrdinaryObject--->writeSerialData--->invokeWriteObject,可以看下一下writeObject0方法里的部分代码,如下
1// remaining cases
2 if (obj instanceof String) {
3 writeString((String) obj, unshared);
4 } else if (cl.isArray()) {
5 writeArray(obj, desc, unshared);
6 } else if (obj instanceof Enum) {
7 writeEnum((Enum<?>) obj, desc, unshared);
8 } else if (obj instanceof Serializable) {
9 writeOrdinaryObject(obj, desc, unshared);
10 } else {
11 if (extendedDebugInfo) {
12 throw new NotSerializableException(
13 cl.getName() + "\n" + debugInfoStack.toString());
14 } else {
15 throw new NotSerializableException(cl.getName());
16 }
17 }
3.虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,一个非常重要的一点是两个类的序列化 ID 是否一致(就是 private static final long serialVersionUID)如果不显示的指定序列化Id,那么在序列化的过程中jvm会根据当前的对象的类的属性和方法计算出一个serialVersionUID,同样当反序列化的时候也会根据目标类的属性和方法结算一个serialVersionUID,如果在序列化之后,对应的类的属性或者方法发生变化那么计算出来的serialVersionUID是不一样的,这样在反序列化的时候就会抛异常,反序列化失败,通常的做法是通过IDE来显示的生成,这样不仅可以防止修改类的属性或者方法导致反序列化失败,从而也可以依靠serialVersionUID的不同来对一些访问做限制,比如变化了serialVersionUID之后,那些不知道最新serialVersionUID的访问将会失败。
4.要想将父类对象也序列化,就需要让父类也实现java.io.Serializable接口,否则父类的属性并不能完成序列化。
五总结
在实际的应用当中序列化的实现还有很多,比如通常用到的json和xml也同样是一种序列化,就像开头所说的只要是将数据结构或对象转换成二进制串的过程就叫序列化,只要是将在序列化过程中所生成的二进制串转换成数据结构或者对象的过程就是反序列化。
Java序列化系列教程(上)的更多相关文章
- Java序列化系列教程(下)
一引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口 ...
- 阿里 Java 手册系列教程:为啥强制子类、父类变量名不同?
摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 父子类变量名相同会咋样? 为啥强制子类.父类变量名不同? ...
- 推介一个学习JAVA的系列教程-狗鱼IT教程
介绍一个学JAVA的零基础学习JAVA的网站,推介一个学习JAVA的系列教程-狗鱼IT教程 下面是java的系教程: 1、[java教程]Java 教程 2、[java教程]Java 简介 3、[ja ...
- Java NIO系列教程(七) selector原理 Epoll版的Selector
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
- Java NIO系列教程(三) Channel之Socket通道
目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> 在<Java NIO系列教程(二) Ch ...
- Java NIO系列教程(二) Channel通道介绍及FileChannel详解
目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> Channel是一个通道,可以通过它读取和写入 ...
- Java NIO系列教程(十一) Java NIO 与 IO
Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...
- Java NIO系列教程(三-十二) Buffer
原文链接 作者:Jakob Jenkov 译者:airu 校对:丁一 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到 ...
- Java NIO系列教程(八)JDK AIO编程
目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...
随机推荐
- java 编码乱码问题
Tomcat的server.xml 文件Connector标签加上URIEncoding="utf-8": <Connector port=" protocol=& ...
- BNUOJ 3278 Candies
Candies Time Limit: 1500ms Memory Limit: 131072KB This problem will be judged on PKU. Original ID: 3 ...
- mysql复制知识整理
主服务器(master)简称M,从服务器(slave)简称S 一.原理: M监听S的复制请求,S创建一个I/O线程以连接M并让它发送记录在其二进制日志中的语句,M接受到请求,创建一个Binlog ...
- noip模拟赛 卖书
分析:模拟题,只是有几个地方需要注意一下:第一个人必须支付5元,找零15元可以找一张10元一张5元,也可以找3张5元. #include <cstdio> #include <cst ...
- linux 文件系统 磁盘分区 格式化
1.du -sh test #查看文件或者目录的大小 2.cat file | wc -l #查看文件的行数 3.ls dirname | wc -l #查看文件个数 4.stat install.l ...
- hdu_1085_Holding Bin-Laden Captive!_201404261008
Holding Bin-Laden Captive! Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Ja ...
- node+mongodb+win7
一.安装mongodb,参照教程,注意要先启动mongod.exe,再启动mongd.exe.
- [bzoj2527][Poi2011]Meteors_整体二分_树状数组
Meteors bzoj-2527 Poi-2011 题目大意:题目链接. 注释:略. 想法: 首先答案可以离线,且具有单调性. 这里的单调性就是随着时间的推移,每个国家收集的陨石数增加. 不难想到整 ...
- SpringBoot常用注解总结
在SpringBoot框架中,注解做为一种隐式配置,极大的简化了之前xml文件的配置方式.SpringBoot中包含许多种类的注解,这里对在SpingBoot项目中经常使用到的一些注解的进行大致的归纳 ...
- 当遇到Mac的Excel或者Word老是重复崩溃的时候
打开Number,新建文件然后导出为Excel.之后再用Excel打开,一切都OK了.