一文带你彻底理解Java序列化和反序列化

Java序列化是什么?

Java序列化是指把Java对象转换为字节序列的过程,Java反序列化是指把字节序列恢复为Java对象的过程。

反序列化: 客户端重文件,或者网络中获取到文件以后,在内存中重构对象。

序列化: 对象序列化的最重要的作用是传递和保存对象的时候,保证对象的完整性和可传递性。方便字节可以在网络上传输以及保存在本地文件。

为什么需要序列化和反序列化

实现分布式

核心在于RMI,可以利用对象序列化运行远程主机上的服务,实现运行的时候,就像在本地上运行Java对象一样。

实现递归保存对象

进行序列化的时候,单单并不是保存一个对象,而是递归的保存一整个对象序列,即递归保存,通过反序列化,可以递归的得到一整个对象序列。

序列信息可以永久保存

用于序列化的信息,可以永久保存为文件,或者保存在数据库中,在使用的时候,再次随时恢复到内存中,实现内存中的类的信息可以永久的保存。

数据格式统一

比照Linux的一切皆文件的思想,同时Java也是这样的思想,让数据格式尽可能的统一,让对象,文件,数据,等等许许多多不同的格式,都让其统一,以及保存。实现数据可以完整的传输和保存。然后进行反序列化还原,即,对象还是对象,文件还是文件。

实现Java序列化和反序列化

要进行反序列化需要实现一个接口。即 Serializabei接口。

代码如下

需要转化的类

package common.lang;

import java.io.Serializable;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public class User1 implements Serializable{

 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;
 }

 @Override
 public String toString() {
  return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
         .append("name", name)
         .append("age", age)
         .toString();
 }
}

进行序列化,以及反序列化

package common.lang;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo1 {

 public static void main(String[] args) throws Exception, IOException {
  //初始化对象
  User1 user = new User1();
  user.setName("yaomy");
  user.setAge(23);
  System.out.println(user);
  //序列化对象到文件中
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template"));
  oos.writeObject(user);
  oos.close();
  //反序列化
  File file = new File("template");
  ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
  User1 newUser = (User1)ois.readObject();
  System.out.println(newUser.toString());
 }
}

另一个序列化接口 Externalizable

继续实现Externalizable接口

package common.lang;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public class User1 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;
 }

 @Override
 public String toString() {
  return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
         .append("name", name)
         .append("age", age)
         .toString();
 }
 @Override
 public void writeExternal(ObjectOutput out) throws IOException {
  // TODO Auto-generated method stub

 }
 @Override
 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
  // TODO Auto-generated method stub

 }
}

进行序列化以及反序列化

package common.lang;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo1 {

 public static void main(String[] args) throws Exception, IOException {
  //初始化对象
  User1 user = new User1();
  user.setName("yaomy");
  user.setAge(23);
  System.out.println(user);
  //序列化对象到文件中
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template"));
  oos.writeObject(user);
  oos.close();
  //反序列化
  File file = new File("template");
  ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
  User1 newUser = (User1)ois.readObject();
  System.out.println(newUser.toString());
  ois.close();
 }
}

查看输出的结构

common.lang.User1@6ef64f64[
name=yaomy
age=23
]
common.lang.User1@184c9860[
name=<null>
age=0
]

根据输出的结果可以看到,对User1进行序列化然后再反序列化之后对象的属性都恢复成了默认值,即,之前那个对象的状态没有被持久保存下来,这就是Externalization和Serialization接口的区别,其中前者接口会被恢复成为默认值,后者接口不会恢复默认值。

如果需要恢复,这里就需要重写两个抽象方法,分别是writeExternal与readExternal两个抽象方法。

package common.lang;

import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;

import org.apache.commons.lang3.builder.ToStringBuilder;
import org.apache.commons.lang3.builder.ToStringStyle;

public class User1 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;
 }

 @Override
 public String toString() {
  return new ToStringBuilder(this, ToStringStyle.MULTI_LINE_STYLE)
         .append("name", name)
         .append("age", age)
         .toString();
 }
 @Override
 public void writeExternal(ObjectOutput out) throws IOException {
  out.writeObject(name);
  out.writeInt(age);

 }
 @Override
 public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
  name = (String)in.readObject();
  age = in.readInt();

 }
}
package common.lang;

import java.io.File;
import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableDemo1 {

 public static void main(String[] args) throws Exception, IOException {
  //初始化对象
  User1 user = new User1();
  user.setName("yaomy");
  user.setAge(23);
  System.out.println(user);
  //序列化对象到文件中
  ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("template"));
  oos.writeObject(user);
  oos.close();
  //反序列化
  File file = new File("template");
  ObjectInputStream ois = new ObjectInputStream(new FileInputStream(file));
  User1 newUser = (User1)ois.readObject();
  System.out.println(newUser.toString());
  ois.close();
 }
}

输出的结果

common.lang.User1@6cd66725[
name=yaomy
age=23
]
common.lang.User1@19160e64[
name=yaomy
age=23
]

静态变量的序列化

实例

public class Test implements Serializable {

 private static final long serialVersionUID = 1L;

 public static int staticVar = 5;

 public static void main(String[] args) {
  try {
   //初始时staticVar为5
   ObjectOutputStream out = new ObjectOutputStream(
     new FileOutputStream("result.obj"));
   out.writeObject(new Test());
   out.close();

   //序列化后修改为10
   Test.staticVar = 10;

   ObjectInputStream oin = new ObjectInputStream(new FileInputStream(
     "result.obj"));
   Test t = (Test) oin.readObject();
   oin.close();

   //再读取,通过t.staticVar打印新的值
   System.out.println(t.staticVar);

  } catch (FileNotFoundException e) {
   e.printStackTrace();
  } catch (IOException e) {
   e.printStackTrace();
  } catch (ClassNotFoundException e) {
   e.printStackTrace();
  }
 }
}

代码阐述一下过程,在main方法中,对象序列化以后,修改静态变量的数值,再把序列化后的对象读取出来,此时输出的值为10.

理解如下: 打印的staticVar是从读取对象里获得的,打印10的原因是因为序列化时,不保存静态变量,只保存内存中的状态。此时修改静态变量的值,修改的是类中的值,输出的也是类中的值,和内存无关。

Transient关键字

Transient关键字,加上以后,可以阻止该变量被序列化到文件中,反序列化以后,变量的值设定为初始值。

以上就是一文带你彻底理解Java序列化和反序列化的详细内容,更多关于Java序列化和反序列化的资料请关注我们其它相关文章!

(0)

相关推荐

  • Java JDBC导致的反序列化攻击原理解析

    这篇文章主要介绍了Java JDBC导致的反序列化攻击原理解析,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 背景 上周BlackHat Europe 2019的议题<New Exploit Technique In Java Deserialization Attack>中提到了一个通过注入JDBC URL实现反序列化攻击的场景,简单分析一下. 分析 首先,当java应用使用MySQL Connector/J(官方的JDBC驱动,本文基于其

  • Java序列化反序列化原理及漏洞解决方案

    Java序列化 Java 提供了一种对象序列化的机制,该机制中,一个对象可以被表示为一个字节序列,该字节序列包括该对象的数据.有关对象的类型的信息和存储在对象中数据的类型. Java反序列化 反序列化就是将字节序列恢复为Java对象的过程 整个过程都是 Java 虚拟机(JVM)独立的,也就是说,在一个平台上序列化的对象可以在另一个完全不同的平台上反序列化该对象,因此可以实现多平台之间的通信.对象持久化存储,主要有如下几个应用场景. HTTP:多平台之间的通信,管理等 RMI:是 Java 的一

  • java 序列化与反序列化的实例详解

     1.Java序列化与反序列化 Java序列化是指把Java对象转换为字节序列的过程:而Java反序列化是指把字节序列恢复为Java对象的过程.  2.为什么需要序列化与反序列化 我们知道,当两个进程进行远程通信时,可以相互发送各种类型的数据,包括文本.图片.音频.视频等, 而这些数据都会以二进制序列的形式在网络上传送.那么当两个Java进程进行通信时,能否实现进程间的对象传送呢?答案是可以的.如何做到呢?这就需要Java序列化与反序列化了.换句话说,一方面,发送方需要把这个Java对象转换为字

  • JAVA序列化和反序列化的底层实现原理解析

    一.基本概念 1.什么是序列化和反序列化 (1)Java序列化是指把Java对象转换为字节序列的过程,而Java反序列化是指把字节序列恢复为Java对象的过程: (2)**序列化:**对象序列化的最主要的用处就是在传递和保存对象的时候,保证对象的完整性和可传递性.序列化是把对象转换成有序字节流,以便在网络上传输或者保存在本地文件中.序列化后的字节流保存了Java对象的状态以及相关的描述信息.序列化机制的核心作用就是对象状态的保存与重建. (3)**反序列化:**客户端从文件中或网络上获得序列化后

  • Java原生序列化和反序列化代码实例

    这篇文章主要介绍了Java原生序列化和反序列化代码实例,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友可以参考下 写一个Java原生的序列化和反序列化的DEMO. 需序列化的类: package com.nicchagil.nativeserialize; import java.io.Serializable; public class User implements Serializable { private static final long se

  • Java将对象写入文件读出_序列化与反序列化的实例

    Java类中对象的序列化工作是通过ObjectOutputStream和ObjectInputStream来完成的. 写入: File aFile=new File("e:\\c.txt"); Stu a=new Stu(1, "aa", "1"); FileOutputStream fileOutputStream=null; try { fileOutputStream = new FileOutputStream(aFile); Objec

  • Java IO流对象的序列化和反序列化实例详解

    Java-IO流 对象的序列化和反序列化 序列化的基本操作 1.对象序列化,就是将Object转换成byte序列,反之叫对象的反序列化. 2.序列化流(ObjectOutputStream),writeObject 方法用于将对象写入输出流中: 反序列化流(ObjectInputStream),readObject 方法用于从输入流中读取对象. 3.序列化接口(Serializeable) 对象必须实现序列化接口,才能进行序列化,否则会出现异常.这个接口没有任何方法,只是一个标准. packag

  • 详解Java 序列化与反序列化(Serialization)

    一.什么是?为什么需要? 序列化(Serialization)是将对象的状态信息转化为可以存储或者传输的形式的过程,反序列化则为其逆过程. 内存的易失性:传输需要:一些应用场景中需要将对象持久化下来,以便在需要的时候进行读取. 二.JDK提供的API java.io.ObjectOutputStream类的 writeObject(Object obj)方法 java.io.ObjectInputStream类的readObject()方法 对于Serializable,如果没有重写 write

  • Java对象的XML序列化与反序列化实例解析

    上一篇文章我们介绍了java实现的各种排序算法代码示例,本文我们看看Java对象的xml序列化与反序列化的相关内容,具体如下. XML是一种标准的数据交换规范,可以方便地用于在应用之间交换各类数据.如果能在Java对象和XML文档之间建立某种映射,例如Java对象的XML序列化和反序列化,那么就可以使Java的对象方便地与其他应用进行交换. java.beans包里面有两个类XMLEncoder和Decoder,分别用于将符合JabaBeans规范的Java对象以XML方式序列化和反序列化.以下

  • java中fastjson生成和解析json数据(序列化和反序列化数据)

    本文讲解2点: 1. fastjson生成和解析json数据 (举例:4种常用类型:JavaBean,List<JavaBean>,List<String>,List<Map<String,Object>) 2.通过一个android程序测试fastjson的用法. fastjson简介: Fastjson是一个Java语言编写的高性能功能完善的JSON库.fastjson采用独创的算法,将parse的速度提升到极致,超过所有json库,包括曾经号称最快的jack

随机推荐