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. java 面向对象(二十五):内部类:类的第五个成员

    内部类:类的第五个成员 1.定义: Java中允许将一个类A声明在另一个类B中,则类A就是内部类,类B称为外部类.2.内部类的分类:成员内部类(静态.非静态 ) vs 局部内部类(方法内.代码块内.构 ...

  2. 机器学习实战基础(九):sklearn中的数据预处理和特征工程(二) 数据预处理 Preprocessing & Impute 之 数据无量纲化

    1 数据无量纲化 在机器学习算法实践中,我们往往有着将不同规格的数据转换到同一规格,或不同分布的数据转换到某个特定分布的需求,这种需求统称为将数据“无量纲化”.譬如梯度和矩阵为核心的算法中,譬如逻辑回 ...

  3. bzoj3381[Usaco2004 Open]Cave Cows 2 洞穴里的牛之二*

    bzoj3381[Usaco2004 Open]Cave Cows 2 洞穴里的牛之二 题意: RMQ问题.序列长度≤25000,问题数≤25000. 题解: 倍增. 代码: #include < ...

  4. MSF查找提权exp

    0x01:介绍 在拿到一个反弹shell后,下一步可以用metaspolit的内置模块Local Exploit SuggesterLocal-exploit-suggester的功能就如它的名字一样 ...

  5. C++语法小记---string类

    string类 #include <iostream> #include <string> using namespace std; // 实现字符串右移, 例子hello & ...

  6. Linux cut 命令详解

    cut 命令在Linux和Unix中的作用是从文件中的每一行中截取出一些部分,并输出到标准输出中.我们可以使用 cut 命令从一行字符串中于以字节,字符,字段(分隔符)等单位截取一部分内容出来. 在本 ...

  7. [jvm] -- 内存模型篇

    内存模型 JDK1.6  JDK1.8  线程私有的: 程序计数器 虚拟机栈 本地方法栈 线程共享的: 堆 方法区 直接内存 (非运行时数据区的一部分) 程序计数器 线程私有 两个作用 字节码解释器通 ...

  8. Java中goto标签的使用

    编写此文仅为以后可以复习. 最近在自学Java核心技术(很好的书,推荐!!),也是第一次从上面了解了goto,或许只是浅层了解. 错误之处希望大佬们给予批评与建议!!谢谢!!! Java核心技术中就提 ...

  9. Python过滤掉numpy.array中非nan数据实例

    代码 需要先导入pandas arr的数据类型为一维的np.array import pandas as pd arr[~pd.isnull(arr)] 补充知识:python numpy.mean( ...

  10. linux日志朔源分析记录

    lastlog 记录用户最后一次登录情况 只有root最近登录过 lastlog -u 用户名或者uid uid 直接在passwd文件中的低三位可以看到 lastb 记录用户用户登录失败的用户记录, ...