**一、什么是序列化 **

序列化是一种对象持久化的手段。类通过实现 java.io.Serializable 接口以启用其序列化功能。

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

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

《阿里巴巴Java开发手册》中对于序列化有以下规定 :

【强制】序列化类新增属性时,请不要修改 serialVersionUID 字段,避免反序列失败;如

果完全不兼容升级,避免反序列化混乱,那么请修改 serialVersionUID 值。

说明:注意 serialVersionUID 不一致会抛出序列化运行时异常。

序列化的场景

  • 当需要把内存中的对象状态保存到一个文件中或者数据库中时候;
  • 当需要使用套接字在网络上传送对象的时候;
  • 当需要通过RMI(远程方法调用,可以理解为Java对象之间的调用)传输对象的时候;
  • 当要跨进程跨网络传输对象的时候,这时候基本要序列化了。

二、如何序列化

2.1 Serializable 接口

Java类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法进行序列化或反序列化。

Serializable 只是一个空接口,接口没有任何的方法和字段,仅仅用于标识。 如果一个类没有实现这个接口,想要被序列化的话,就会抛出 java.io.NotSerializableException 异常。

2.2 Externalizable 接口

Externalizable 继承自 Serializable , 它更加灵活一点,它里面定义了 writeExternal()readExternal() 两个抽象方法分别用于序列化和反序列化使用。

通过这两个方法,程序猿决定需要序列化那些数据。如果对象中涉及到很少的属性需要序列化,大多数属性无需序列化,这种情况使用Externalizable 接口是比较灵活的。

2.3 transient 关键字

transient 关键字的作用是控制变量的序列化,在变量声明前加上该关键字,可以阻止该变量被序列化到文件中,在被反序列化后,transient 变量的值被设为初始值,如 int 型的是 0,对象型的是 null。

Tip: 自己查看 String 、Integer 等的源码,可以看到本身也是实现了 Serializable 的。

三、什么是 serialVersionUID

3.1 serialVersionUID 的 作用

serialVersionUID 是用来验证版本一致性的 。

序列化是将对象的状态信息转换为可存储或传输的形式的过程。

Java对象是保存在 JVM 的堆内存中的,如果 JVM堆不存在了,对象也就跟着随即消失。

而序列化提供了一种方案,可以在即使 JVM 停机的情况下也能把对象保存下来的方案。

把 Java 对象序列化成可存储或传输的形式(如二进制流),比如保存在文件中。

当再次需要这个对象的时候,从文件中读取出二进制流,再从二进制流中反序列化出对象。

虚拟机是否允许反序列化,不仅取决于类路径和功能代码是否一致,

一个非常重要的一点是两个类的序列化 ID 是否一致,这个所谓的序列化ID(serialVersionUID)。

在反序列化时,Jvm 会把传来的字节流中的 serialVersionUID 和本地相应实体类的 serialVersionUID 进行比较,

如果相同就认为一致,可以进行反序列化,否则出现 InvalidCastException 异常。

3.2 代码案例演示

public class Student implements Serializable {

    private static final long serialVersionUID = -303793456610254190L;

    private String name;

    private String address;

    private long id;

    public String getName() {
return name;
} public void setName(String name) {
this.name = name;
} public String getAddress() {
return address;
} public void setAddress(String address) {
this.address = address;
} public long getId() {
return id;
} public void setId(long id) {
this.id = id;
} @Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", address='" + address + '\'' +
", id=" + id +
'}';
} public static void main(String[] args) throws IOException, ClassNotFoundException { // 序列化
Student student = new Student();
student.setAddress("北京");
student.setId(001);
student.setName("小花"); ObjectOutputStream output = new ObjectOutputStream(new FileOutputStream(new File("E:\\data\\Student.txt")));
output.writeObject(student);
output.close();
System.out.println("序列化成功:" + student); // 反序列化
ObjectInputStream input = new ObjectInputStream(new FileInputStream(new File("E:\\data\\Student.txt")));
Student student2 = (Student) input.readObject();
input.close();
System.out.println("反序列化成功:" + student2);
}
}

执行上面的 Main 方法,控制台会打印以下信息:

序列化成功:Student{name='小花', address='北京', id=1}
反序列化成功:Student{name='小花', address='北京', id=1}

Tip : 如果将 Student 实现的 Serializable 接口去掉会报错如下

Exception in thread "main" java.io.NotSerializableException: com.example.demo.sample.Student
at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
at com.example.demo.sample.Student.main(Student.java:61)

3.4 如果修改了 serialVersionUID 会发生什么?

注释掉序列化的代码,修改 serialVersionUID ,再次执行了上面的反序列化代码后。(前提是已经执行成功过一次,已经有 Student.txt 文件了)会报错如下:

Exception in thread "main" java.io.InvalidClassException: com.example.demo.sample.Student; local class incompatible: stream classdesc serialVersionUID = -303793456610254190, local class serialVersionUID = -403793456610254190
at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1883)
at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1749)
at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2040)
at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1571)
at java.io.ObjectInputStream.readObject(ObjectInputStream.java:431)
at com.example.demo.sample.Student.main(Student.java:66)

3.5 transient:定义临时变量

transient关键字的作用:就是让某些被修饰的成员属性变量不被序列化。

在 Student 类中添加属性 ,在执行序列化的时候设置 age 为 18;

private transient int  age;

运行 Main 方法后,可以看到 age 属性并没有被序列化,因为反序列化显示的是 0;

序列化成功:Student{name='小花', address='北京', id=1, age=18}
反序列化成功:Student{name='小花', address='北京', id=1, age=0}

3.6 static & static-final

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

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

四、总结

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

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

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

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

理解 Java 序列化的更多相关文章

  1. 理解Java序列化

    前言 Java对象是在JVM中产生的,若要将其进行传输或保存到硬盘,就要将对象转换为可传输的文件流.而目前Java对象的转换方式有: 利用Java的序列化功能序列成字节(字节流),一般是需要加密传输时 ...

  2. 深入理解JAVA序列化

    如果你只知道实现 Serializable 接口的对象,可以序列化为本地文件.那你最好再阅读该篇文章,文章对序列化进行了更深一步的讨论,用实际的例子代码讲述了序列化的高级认识,包括父类序列化的问题.静 ...

  3. 理解Java序列化中的SerialVersionUid

    一.前言 SerialVersionUid,简言之,其目的是序列化对象版本控制,有关各版本反序列化时是否兼容.如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClass ...

  4. 通俗理解java序列化

    1 序列化是干什么的呢? 搬家的 简单说就是为了保存在内存中的各种对象的状态(也就是实例变量,不是方法),并且可以把保存的对象状态再读出来.虽然你可以用你自己的各种各样的方法来保存object sta ...

  5. 【转】通俗理解Java序列化与反序列化

    一.序列化和反序列化的概念 把对象转换为字节序列的过程称为对象的序列化. 把字节序列恢复为对象的过程称为对象的反序列化. 对象的序列化主要有两种用途: 1) 把对象的字节序列永久地保存到硬盘上,通常存 ...

  6. Java序列化与反序列化

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

  7. [转] Java序列化与反序列化

    原文地址:http://blog.csdn.net/wangloveall/article/details/7992448 Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java ...

  8. Java序列化的几种方式以及序列化的作用

    Java序列化的几种方式以及序列化的作用 本文着重讲解一下Java序列化的相关内容. 如果对Java序列化感兴趣的同学可以研究一下. 一.Java序列化的作用    有的时候我们想要把一个Java对象 ...

  9. java序列化与反序列化(转)

    Java序列化与反序列化是什么?为什么需要序列化与反序列化?如何实现Java序列化与反序列化?本文围绕这些问题进行了探讨. 1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列 ...

随机推荐

  1. 使用nano编辑器进行查找和替换

    笔者自己常用的是vim.这里nano的使用场景就是刚安装好Ubuntu系统,想要替换更新源,这时候还没装上vim.所以,学一下如何用nano查找和替换,可以解决这个小问题. 首先sudo nano / ...

  2. pycharm windows 远程修改服务器代码

    配置过程 本机环境 操作系统:win10 IDE:Pycharm 远程服务器 操作系统:ubuntu 4.4.0 配置了ssh,可以使用ssh进行远程登陆 配置Deployment 首先,在pycha ...

  3. iview select下拉框的蜜汁小坑

    前言 最近使用iview的select下拉选择器,遇到一个很神奇的问题:选中下拉框里面的一个值,但是再去点下拉框的时候就只剩刚才选中的数据了.感觉应该是插件把刚才选中的数据当做的搜索条件,所以需要做的 ...

  4. Who Saw My Blog

    I found that my blog has visitors!!! I wonder who has watched my blog and what did they feel at that ...

  5. sequel 远程连接 MySQL 连接错误Can't connect to MySQL server on (61)

    Mac sequel Pro链接时报错Can’t connect to MySQL server on ‘xx.xx.xx.xx’ (61). PS. win版Navicat 报错Can’t conn ...

  6. Cent OS 7下安装 mongodb

    1.下载MongoDB 安装包 wget https://fastdl.mongodb.org/linux/mongodb-linux-x86_64-3.6.8.tgz 2.解压并安装 .tgz 3. ...

  7. 用JOptionPane类实现各种对话框

    用JOptionPane类实现各种对话框 运行结果: 下面部分参考: JOptionPane类提示框的一些常用的方法 - - ITeye博客  http://847353020-qq-com.itey ...

  8. layui表单提交使用form.on('submit(sub)',function (){}) 使用ajax请求时回调不执行的原因及解决方法

    ayui使用官方的表单模块form.on('submit(sub)',function (){}) 提交,使用ajax请求向后台请求一个执行结果,根据结果进行处理,出现回调无法执行,并且页面出现了刷新 ...

  9. HTML-参考手册: HTML 颜色名

    ylbtech-HTML-参考手册: HTML 颜色名 1.返回顶部 1. HTML 颜色名 目前所有浏览器都支持以下颜色名. 141个颜色名称是在HTML和CSS颜色规范定义的(17标准颜色,再加1 ...

  10. HTML-参考手册: HTML 事件属性

    ylbtech-HTML-参考手册: HTML 事件属性 1.返回顶部 1. HTML 事件属性 全局事件属性 HTML 4 的新特性之一是可以使 HTML 事件触发浏览器中的行为,比方说当用户点击某 ...