1、序列化的概念,意义以及使用场景

序列化:

将对象写入到IO流中,也就是把Java对象转换为字节序列的过程

反序列化:

从IO流中恢复对象*,也就是把字节序列恢复为Java对象的过程

意义:

序列化机制允许将实现序列化的Java对象转换位字节序列,这些字节序列可以保存在磁盘上,或通过网络传输,以达到以后恢复成原来的对象。序列化机制使得对象可以脱离程序的运行而独立存在。

使用场景:

(1)永久性保存对象,保存对象的字节序列到本地文件或者数据库中;、

(2)通过序列化以字节流的形式使对象在网络中进行传递和接收;

(3)通过序列化在进程间传递对象;

所有可在网络上传输的对象都必须是可序列化的,比如RMI(remote method invoke,即远程方法调用),传入的参数或返回的对象都是可序列化的,否则会出错;所有需要保存到磁盘的java对象都必须是可序列化的。通常建议:程序创建的每个JavaBean类都实现Serializeable接口。

2、好处

其实好处是根据使用场景来的;

(1)实现了数据的持久化,通过序列化可以把数据永久地保存到硬盘上

(2)利用序列化实现远程通信,即在网络上传送对象的字节序列。

3、Java中实现序列化的俩种方式

3.1 使用Serializable接口实现序列化

定义一个对象类 Student

package com.example.main;

import java.io.*;

/**
* @author lin
* @version 1.0
* @date 2020/7/11 22:04
* @Description TODO
*/
public class Student implements Serializable {
   /**
    * 序列化版本号
    */
   private static final long serialVersionUID = 1111013L;
   private String name;
   private String gender;    public String getName() {
       return name;
  }    public void setName(String name) {
       this.name = name;
  }    public String getGender() {
       return gender;
  }    public void setGender(String gender) {
       this.gender = gender;
  }    @Override
   public String toString() {
       return "Student{" +
               "name='" + name + '\'' +
               ", gender='" + gender + '\'' +
               '}';
  }    /**
    * 序列化方法
    */
   private static void serializeStudent() {
       try {
           Student student = new Student();
           student.setName("张无忌");
           student.setGender("男");
           // 对象 序列化 到 文件中
           ObjectOutputStream os = new ObjectOutputStream(new FileOutputStream("D://student"));
           os.writeObject(student);
           os.close();
           System.out.println("序列化完成");
      } catch (IOException e) {
           e.printStackTrace();
      }
  }    /**
    * 反序列化方法
    */
   private static void deSerializeStudent() {
       try {
           ObjectInputStream is = new ObjectInputStream(new FileInputStream("D://student"));
           Student stu = (Student) is.readObject();
           System.out.println("反序列化成功:" + stu.toString());
           is.close();
      } catch (IOException | ClassNotFoundException e) {
           e.printStackTrace();
      }
  }    public static void main(String[] args) {
       serializeStudent();
       deSerializeStudent();
  }
}

运行结果如下:

序列化完成
反序列化成功:Student{name='张无忌', gender='男'}

3.2 使用Externalizable接口实现序列化

定义一个Person类

package com.example.main;

import java.io.*;

/**
* @author lin
* @version 1.0
* @date 2020/7/11 22:18
* @Description TODO
*/
public class Person implements Externalizable {
   private String name;
   private int age;    public String getName() {
       return name;
  }    public void setName(String name) {
       this.name = name;
  }    public int getAge() {
       return age;
  }    public void setAge(int age) {
       this.age = age;
  }    public Person(String name, int age) {
       this.name = name;
       this.age = age;
  }    public Person() {
  }    @Override
   public String toString() {
       return "Person{" +
               "name='" + name + '\'' +
               ", age=" + age +
               '}';
  }    @Override
   public void writeExternal(ObjectOutput out) throws IOException {
       //将name反转后写入二进制流
       StringBuffer reverse = new StringBuffer(name).reverse();
       System.out.println(reverse.toString());
       out.writeObject(reverse);
       out.writeInt(age);
  }    @Override
   public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
       //将读取的字符串反转后赋值给name实例变量
       this.name = ((StringBuffer) in.readObject()).reverse().toString();
       System.out.println(name);
       this.age = in.readInt();
  }    public static void main(String[] args) throws Exception {
       ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("Person.txt"));
       ObjectInputStream ois = new ObjectInputStream(new FileInputStream("Person.txt"));
       oos.writeObject(new Person("brady", 23));
       Person ep = (Person) ois.readObject();
       System.out.println(ep);
  }
}

运行结果如下:

ydarb
brady
Person{name='brady', age=23}

两种序列化对比

实现Serializable接口 实现Externalizable接口
系统自动存储必要的信息 程序员决定存储哪些信息
Java内建支持,易于实现,只需要实现该接口即可,无需任何代码支持 必须实现接口内的两个方法
性能略差 性能略好

虽然Externalizable接口带来了一定的性能提升,但变成复杂度也提高了,所以一般通过实现Serializable接口进行序列化。

4、分析java序列化机制

4.1 serialVersionUID的作用

其目的是序列化对象版本控制,有关各版本反序列化时是否兼容。如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常。如果修改较小,比如仅仅是增加了一个属性,我们希望向下兼容,老版本的数据都能保留,那就不用修改;如果我们删除了一个属性,或者更改了类的继承关系,必然不兼容旧数据,这时就应该手动更新版本号,即SerialVersionUid。

4.2 静态变量的序列化

需要说一下,静态变量不会被序列化。因为静态变量在全局区,本来流里面就没有写入静态变量,我打印静态变量当然会去全局区查找,当我write read 同时使用时,内存中的静态变量变了,所以打印出来的也变了。

自行可以测试一下. 将变量 增加 static 静态变量

结果会出现两种情况:

(1)反序列输出的静态变量值没有变化:说明静态变量被序列化了。

(2)反序列输出的静态变量值变化了:说明静态变量没有被序列化了。

4.3 Transient 关键字作用

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

将Student类中的gender修改为 :

private transient String gender;

再次运行结果如下:

序列化完成
反序列化成功:Student{name='张无忌', gender='null'}

5、总结

java提供的序列化机制还是比较常用的,也是比较简单的。

1. 所有需要网络传输的对象都需要实现序列化接口,通过建议所有的javaBean都实现Serializable接口。
2. 对象的类名、实例变量(包括基本类型,数组,对其他对象的引用)都会被序列化;方法、类变量、transient实例变量都不会被序列化。
3. 如果想让某个变量不被序列化,使用transient修饰。
4. 序列化对象的引用类型成员变量,也必须是可序列化的,否则,会报错。
5. 反序列化时必须有序列化对象的class文件。
6. 当通过文件、网络来读取序列化后的对象时,必须按照实际写入的顺序读取。
7. 单例类序列化,需要重写readResolve()方法;否则会破坏单例原则。
8. 同一对象序列化多次,只有第一次序列化为二进制流,以后都只是保存序列化编号,不会重复序列化。
9. 建议所有可序列化的类加上serialVersionUID 版本号,方便项目升级。

发哥讲

如果你觉得文章还不错,就请点击右上角选择发送给朋友或者转发到朋友圈~

● 扫码关注公众号

19、Java 序列化的更多相关文章

  1. Java 序列化Serializable详解

    Java 序列化Serializable详解(附详细例子) Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连 ...

  2. 各种Java序列化性能比较

    转载:http://www.jdon.com/concurrent/serialization.html 这里比较Java对象序列化 XML JSON  Kryo  POF等序列化性能比较. 很多人以 ...

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

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

  4. java序列化---转

    Java 序列化Serializable详解(附详细例子) 1.什么是序列化和反序列化Serialization(序列化)是一种将对象以一连串的字节描述的过程:反序列化deserialization是 ...

  5. Java 序列化 序列化与单例模式 [ 转载 ]

    Java 序列化 序列化与单例模式 [ 转载 ] @author Hollis 本文将通过实例+阅读Java源码的方式介绍序列化是如何破坏单例模式的,以及如何避免序列化对单例的破坏. 单例模式,是设计 ...

  6. Protocol Buffer序列化对比Java序列化.

    初识 Protocol Buff是谷歌推出的一种序列化协议. 而Java序列化协议也是一种协议. 两者的目的是, 将对象序列化成字节数组, 或者说是二进制数据, 那么他们之间有什么差异呢. proto ...

  7. Java序列化框架性能比較

    博客: http://colobu.com jvm-serializers提供了一个非常好的比較各种Java序列化的的測试套件. 它罗列了各种序列化框架. 能够自己主动生成測试报告. 我在AWS c3 ...

  8. 深入学习 Java 序列化

    前言 对于Java的序列化,一直只知道只需要实现Serializbale这个接口就可以了,具体内部实现一直不是很了解,正好这次在重复造RPC的轮子的时候涉及到序列化问题,就抽时间看了下 Java序列化 ...

  9. 浅析若干Java序列化工具【转】

    在Java中socket传输数据时,数据类型往往比较难选择.可能要考虑带宽.跨语言.版本的兼容等问题.比较常见的做法有: 采用java对象的序列化和反序列化 把对象包装成JSON字符串传输 Googl ...

随机推荐

  1. Flask 基础组件(五):请求和响应

    from flask import Flask from flask import request from flask import render_template from flask impor ...

  2. Python之 爬虫(二十三)Scrapy分布式部署

    按照上一篇文章中我们将代码放到远程主机是通过拷贝或者git的方式,但是如果考虑到我们又多台远程主机的情况,这种方式就比较麻烦,那有没有好用的方法呢?这里其实可以通过scrapyd,下面是这个scrap ...

  3. Ethical Hacking - GAINING ACCESS(8)

    Server Side Attacks NeXpose - configure and launch a scan Configure and initialize the application. ...

  4. LESS实战::not与:hover混合使用

    举个例子,有个HTML是这样的. <div class="item light">A</div> <div class="item" ...

  5. IDM的“免费版”NDM免费的下载工具

    软件截图 软件介绍 免费小巧的多线程下载工具,支持断点续传,支持浏览器扩展,嗅探下载音视频文件. 和IDM差不多,只不过是免费的 下载软件 Win 我提供的UCloud-OSS 官网下载 Mac 我提 ...

  6. Linux指令,更新中

    Linux指令 ls 列举文件. ls *.txt:列举所有txt后缀的文件夹. touch 创建文件. $ touch asd.txt fgh.txt $ touch love{1..10}shiy ...

  7. Oracle可视化工具连接

    Oracle可是化工具有很多,以下只列举sql developer和sql plus这两款连接方式 sql developer: SQL Develope启动后,需要创建一个数据库连接,只有创建了数据 ...

  8. mybatis连接池

    连接池 在 Mybatis 中,数据源 dataSource 共有三类,分别是: UNPOOLED : 不使用连接池的数据源.采用传统的 javax.sql.DataSource 规范中的连接池,My ...

  9. 【Vue组件通信】props、$ref、$emit,组件传值

    1.什么是组件通信 组件间如何通信,也就成为了vue中重点知识,组件通信,涉及到组件之间数据的传递.类似NET POST/GET参数传递. Vue基本的三种传递方式** (props.\(ref.\) ...

  10. Java 匿名对象、内部类

    一.匿名对象 1.概念 匿名对象是指创建对象时,只有创建对象的语句,却没有把对象地址值赋值给某个变量. public class Person{ public void eat(){ System.o ...