一定义以及相关概念

互联网的产生带来了机器间通讯的需求,而互联通讯的双方需要采用约定的协议,序列化和反序列化属于通讯协议的一部分。通讯协议往往采用分层模型,不同模型每层的功能定义以及颗粒度不同,例如: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序列化系列教程(上)的更多相关文章

  1. Java序列化系列教程(下)

    一引言 将 Java 对象序列化为二进制文件的 Java 序列化技术是 Java 系列技术中一个较为重要的技术点,在大部分情况下,开发人员只需要了解被序列化的类需要实现 Serializable 接口 ...

  2. 阿里 Java 手册系列教程:为啥强制子类、父类变量名不同?

    摘要: 原创出处 https://www.bysocket.com 「公众号:泥瓦匠BYSocket 」欢迎关注和转载,保留摘要,谢谢! 目录 父子类变量名相同会咋样? 为啥强制子类.父类变量名不同? ...

  3. 推介一个学习JAVA的系列教程-狗鱼IT教程

    介绍一个学JAVA的零基础学习JAVA的网站,推介一个学习JAVA的系列教程-狗鱼IT教程 下面是java的系教程: 1、[java教程]Java 教程 2、[java教程]Java 简介 3、[ja ...

  4. Java NIO系列教程(七) selector原理 Epoll版的Selector

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

  5. Java NIO系列教程(三) Channel之Socket通道

    目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> 在<Java NIO系列教程(二) Ch ...

  6. Java NIO系列教程(二) Channel通道介绍及FileChannel详解

    目录: <Java NIO系列教程(二) Channel> <Java NIO系列教程(三) Channel之Socket通道> Channel是一个通道,可以通过它读取和写入 ...

  7. Java NIO系列教程(十一) Java NIO 与 IO

    Java NIO系列教程(十一) Java NIO与IO 当学习了 Java NIO 和 IO 的 API 后,一个问题马上涌入脑海: 我应该何时使用 IO,何时使用 NIO 呢?在本文中,我会尽量清 ...

  8. Java NIO系列教程(三-十二) Buffer

    原文链接     作者:Jakob Jenkov     译者:airu     校对:丁一 Java NIO中的Buffer用于和NIO通道进行交互.如你所知,数据是从通道读入缓冲区,从缓冲区写入到 ...

  9. Java NIO系列教程(八)JDK AIO编程

    目录: Reactor(反应堆)和Proactor(前摄器) <I/O模型之三:两种高性能 I/O 设计模式 Reactor 和 Proactor> <[转]第8章 前摄器(Proa ...

随机推荐

  1. configparser logging

    configparser模块 # 该模块适用于配置文件的格式与windows ini文件类似,可以包含一个或多个节(section),每个节可以有多个参数(键=值). import configpar ...

  2. STM32——通用定时器基本定时功能

    STM32——————通用定时器基本定时功能                                                                           1.  ...

  3. 06-看图理解数据结构与算法系列(AVL树)

    AVL树 AVL树,也称平衡二叉搜索树,AVL是其发明者姓名简写.AVL树属于树的一种,而且它也是一棵二叉搜索树,不同的是他通过一定机制能保证二叉搜索树的平衡,平衡的二叉搜索树的查询效率更高. AVL ...

  4. url方法使用与单例模式

    一.url方法使用 from django.contrib import admin from django.urls import path, include from django.conf.ur ...

  5. python基础示例

    7.写代码 (1)实现用户输入用户名和密码,当用户名为 seven 且 密码为 123 时,显示登陆成功,否则登陆失败! _name = "seven" _pwd = " ...

  6. Apache Ambari 2.7.3.0 离线安装

    1. 准备 (内存 3G 硬盘 40G) 0)设置ssh无密码 ssh-keygencat id_rsa.pub >> authorized_keyschmod 700 ~/.sshchm ...

  7. Python接口测试之unittest框架(五)

    Test-driven development(TDD)开发模式在今天已经不是什么新奇的事了,它的开发思维是在开发一个产品功能的时候,先 编写好该功能的测试代码,在编写开发比如,比如要写二个数相除的函 ...

  8. myeclipse通过数据表生成jpa或hibernate实体---https://blog.csdn.net/partner4java/article/details/8560289

    myeclipse通过数据表生成jpa或hibernate实体-----https://blog.csdn.net/partner4java/article/details/8560289

  9. 添物不花钱学JavaEE(基础篇)-综述

    JavaEE由一堆基础标准组成.JavaEE开发一般需要如下工具和掌握如下内容: Java环境 Eclipse或其他开发工具 Tomcat容器或类似软件 Jsp/Servlet/Web/JDBC的掌握 ...

  10. 全文搜索(A-3)-用户建模

    用户模型可以分为静态模型.动态模型.混合推荐用户模型. 静态模型往往通过显式方式收集用户偏好信息: 动态模型通过隐式方式收集用户偏好信息: 基于内容的用户系统的推荐模型: 关键字匹配,空间向量模型 协 ...