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

序列化是一种对象持久化的手段。类通过实现 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. mysql的安裝

    记得上学的时候,“研究”过一次mysql,找了篇文章,在课堂上念了.至今已经10余年,居然没再碰过数据库,自以为做嵌入式不用数据库,回头一看,却已经out许久... 上网下到最新的mysql5.5,从 ...

  2. 在idea下开发出现404错误

    用idea开发时,我们一般要设置project strucure里的Modules-Sources,里面对应的有Sources,tests,Resources,Test Resources, Excl ...

  3. CDN技术之--内容缓存工作原理

    有CDN前的网站服务技术–硬件扩展:高成本,灵活性和可扩展性比较差–镜像技术(mirroring):镜像服务器安装有一个可以进行自动远程备份的软件,每隔一定时间,各个镜像服务器就会到网站的源服务器上去 ...

  4. [CSP-S模拟测试]:赤(red)(WQS二分+DP)

    题目传送门(内部题38) 输入格式 每个输入文件包含多组测试数据.选手应当处理到文件结束($EOF$) 每一组数据包括$3$行. 第$1$行包含三个正整数$n,a,b$,表示有$n$只猫,$gyz$有 ...

  5. angularjs &登录跳转

    如果要使用$location,$stateParams,那么必须有相应形参controller: function ($rootScope, $http, $scope, $state,$locati ...

  6. symantec SMG 抓包

    1.使用putty连接SMG,先用admin账号登陆 执行set-support  , 设置一个密码. 2.重新打开一个putty连接SMG,使用support账号登陆.用我们刚才设置的密码. 3.开 ...

  7. 关于最近练习PYTHON代码的一点心得

    做测试以来,一直想学习代码,以前也断断续续的学习过,不过都是练习一些基础语法,学习的是菜鸟教程,但是效果不大. 最近在练习CODEWAR里做练习题,慢慢强化自己对一些基本语法的理解,熟悉基本的内置函数 ...

  8. STM32 系统架构

    这里所讲的 STM32 系统架构主要针对的 STM32F103 这些非互联型芯片 STM32 主系统主要由四个驱动单元和四个被动单元构成. 四个驱动单元是: 内核 DCode 总线; 系统总线;通用  ...

  9. kali开启禁止或删除ssh 开机启动

    开启禁止或删除ssh 开机启动 # update-rc.d ssh enable #//开机启动 # update-rc.d ssh disable #//禁止开机启动 # update-rc.d - ...

  10. Git与GitHub同步

    如何通过Git Bash实现本地与远端仓库——GitHub的同步 1.下载安装Git:下载网址 2.在自己的github上新建一个repository 例如我这里新建了一个叫test的reposito ...