Java对象的序列化和反序列化

限时加码!20+主流AI编程工具免费用 购周边加赠Coding Plan Lite,Claude Code、Cursor等即刻畅享,学习进阶更高效! 阅读详情

一、序列化和反序列化的概念

  把对象转换为字节序列的过程称为对象的序列化
  把字节序列恢复为对象的过程称为对象的反序列化
  对象的序列化主要有两种用途:
  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;
  2) 在网络上传送对象的字节序列。

  在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Session对象,当有 10万用户并发访问,就有可能出现10万个Session对象,内存可能吃不消,于是Web容器就会把一些seesion先序列化到硬盘中,等要用了,再把保存在硬盘中的对象还原到内存中。

  当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象。

二、JDK类库中的序列化API

  java.io.ObjectOutputStream代表对象输出流,它的writeObject(Object obj)方法可对参数指定的obj对象进行序列化,把得到的字节序列写到一个目标输出流中。
  java.io.ObjectInputStream代表对象输入流,它的readObject()方法从一个源输入流中读取字节序列,再把它们反序列化为一个对象,并将其返回。
  只有实现了Serializable和Externalizable接口的类的对象才能被序列化。Externalizable接口继承自 Serializable接口,实现Externalizable接口的类完全由自身来控制序列化的行为,而仅实现Serializable接口的类可以 采用默认的序列化方式 。
  对象序列化包括如下步骤:
  1) 创建一个对象输出流,它可以包装一个其他类型的目标输出流,如文件输出流;
  2) 通过对象输出流的writeObject()方法写对象。

  对象反序列化的步骤如下:
  1) 创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
  2) 通过对象输入流的readObject()方法读取对象。

对象序列化和反序列范例:

  定义一个Person类,实现Serializable接口

import java.io.Serializable;

/**
 * <p>ClassName: Person<p>
 * <p>Description:测试对象序列化和反序列化<p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午02:33:25
 */
public class Person implements Serializable {

    /**
     * 序列化ID
     */
    private static final long serialVersionUID = -5809782578272943999L;
    private int age;
    private String name;
    private String sex;

    public int getAge() {
        return age;
    }

    public String getName() {
        return name;
    }

    public String getSex() {
        return sex;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }
}

 

  序列化和反序列化Person类对象

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;
import java.text.MessageFormat;

/**
 * <p>ClassName: TestObjSerializeAndDeserialize<p>
 * <p>Description: 测试对象的序列化和反序列<p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午03:17:25
 */
public class TestObjSerializeAndDeserialize {

    public static void main(String[] args) throws Exception {
        SerializePerson();//序列化Person对象
        Person p = DeserializePerson();//反序列Perons对象
        System.out.println(MessageFormat.format("name={0},age={1},sex={2}",
                                                 p.getName(), p.getAge(), p.getSex()));
    }
    
    /**
     * MethodName: SerializePerson 
     * Description: 序列化Person对象
     * @author xudp
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void SerializePerson() throws FileNotFoundException,
            IOException {
        Person person = new Person();
        person.setName("gacl");
        person.setAge(25);
        person.setSex("男");
        // ObjectOutputStream 对象输出流,将Person对象存储到E盘的Person.txt文件中,完成对Person对象的序列化操作
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/Person.txt")));
        oo.writeObject(person);
        System.out.println("Person对象序列化成功!");
        oo.close();
    }

    /**
     * MethodName: DeserializePerson 
     * Description: 反序列Perons对象
     * @author xudp
     * @return
     * @throws Exception
     * @throws IOException
     */
    private static Person DeserializePerson() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Person.txt")));
        Person person = (Person) ois.readObject();
        System.out.println("Person对象反序列化成功!");
        return person;
    }

}

代码运行结果如下:

序列化Person成功后在E盘生成了一个Person.txt文件,而反序列化Person是读取E盘的Person.txt后生成了一个Person对象

 三、serialVersionUID的作用

  s​e​r​i​a​l​V​e​r​s​i​o​n​U​I​D​:​ ​字​面​意​思​上​是​序​列​化​的​版​本​号​,凡是实现Serializable接口的类都有一个表示序列化版本标识符的静态变量

1 private static final long serialVersionUID

  实现Serializable接口的类如果类中没有添加serialVersionUID,那么就会出现如下的警告提示

  

  用鼠标点击就会弹出生成serialVersionUID的对话框,如下图所示:

  

  serialVersionUID有两种生成方式:

  采用这种方式生成的serialVersionUID是1L,例如:

1 private static final long serialVersionUID = 1L;

  采用这种方式生成的serialVersionUID是根据类名,接口名,方法和属性等来生成的,例如:

1 private static final long serialVersionUID = 4603642343377807741L;

  添加了之后就不会出现那个警告提示了,如下所示:

  

  扯了那么多,那么serialVersionUID(序列化版本号)到底有什么用呢,我们用如下的例子来说明一下serialVersionUID的作用,看下面的代码:

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;
import java.io.Serializable;

public class TestSerialversionUID {

    public static void main(String[] args) throws Exception {
        SerializeCustomer();// 序列化Customer对象
        Customer customer = DeserializeCustomer();// 反序列Customer对象
        System.out.println(customer);
    }

    /**
     * MethodName: SerializeCustomer 
     * Description: 序列化Customer对象
     * @author xudp
     * @throws FileNotFoundException
     * @throws IOException
     */
    private static void SerializeCustomer() throws FileNotFoundException,
            IOException {
        Customer customer = new Customer("gacl",25);
        // ObjectOutputStream 对象输出流
        ObjectOutputStream oo = new ObjectOutputStream(new FileOutputStream(
                new File("E:/Customer.txt")));
        oo.writeObject(customer);
        System.out.println("Customer对象序列化成功!");
        oo.close();
    }

    /**
     * MethodName: DeserializeCustomer 
     * Description: 反序列Customer对象
     * @author xudp
     * @return
     * @throws Exception
     * @throws IOException
     */
    private static Customer DeserializeCustomer() throws Exception, IOException {
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream(
                new File("E:/Customer.txt")));
        Customer customer = (Customer) ois.readObject();
        System.out.println("Customer对象反序列化成功!");
        return customer;
    }
}

/**
 * <p>ClassName: Customer<p>
 * <p>Description: Customer实现了Serializable接口,可以被序列化<p>
 * @author xudp
 * @version 1.0 V
 * @createTime 2014-6-9 下午04:20:17
 */
class Customer implements Serializable {
    //Customer类中没有定义serialVersionUID
    private String name;
    private int age;

    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

运行结果:

序列化和反序列化都成功了。

下面我们修改一下Customer类,添加多一个sex属性,如下:

class Customer implements Serializable {
    //Customer类中没有定义serialVersionUID
    private String name;
    private int age;

    //新添加的sex属性
    private String sex;
    
    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public Customer(String name, int age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

 

  然后执行反序列操作,此时就会抛出如下的异常信息:

1 Exception in thread "main" java.io.InvalidClassException: Customer; 
2 local class incompatible: 
3 stream classdesc serialVersionUID = -88175599799432325, 
4 local class serialVersionUID = -5182532647273106745

  意思就是说,文件流中的class和classpath中的class,也就是修改过后的class,不兼容了,处于安全机制考虑,程序抛出了错误,并且拒绝载入。那么如果我们真的有需求要在序列化后添加一个字段或者方法呢?应该怎么办?那就是自己去指定serialVersionUID。在TestSerialversionUID例子中,没有指定Customer类的serialVersionUID的,那么java编译器会自动给这个class进行一个摘要算法,类似于指纹算法,只要这个文件 多一个空格,得到的UID就会截然不同的,可以保证在这么多类中,这个编号是唯一的。所以,添加了一个字段后,由于没有显指定 serialVersionUID,编译器又为我们生成了一个UID,当然和前面保存在文件中的那个不会一样了,于是就出现了2个序列化版本号不一致的错误。因此,只要我们自己指定了serialVersionUID,就可以在序列化后,去添加一个字段,或者方法,而不会影响到后期的还原,还原后的对象照样可以使用,而且还多了方法或者属性可以用。

  下面继续修改Customer类,给Customer指定一个serialVersionUID,修改后的代码如下:

class Customer implements Serializable {
    /**
     * Customer类中定义的serialVersionUID(序列化版本号)
     */
    private static final long serialVersionUID = -5182532647273106745L;
    private String name;
    private int age;

    //新添加的sex属性
    //private String sex;
    
    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    /*public Customer(String name, int age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }*/

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

  重新执行序列化操作,将Customer对象序列化到本地硬盘的Customer.txt文件存储,然后修改Customer类,添加sex属性,修改后的Customer类代码如下:

class Customer implements Serializable {
    /**
     * Customer类中定义的serialVersionUID(序列化版本号)
     */
    private static final long serialVersionUID = -5182532647273106745L;
    private String name;
    private int age;

    //新添加的sex属性
    private String sex;
    
    public Customer(String name, int age) {
        this.name = name;
        this.age = age;
    }
    
    public Customer(String name, int age,String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }

    /*
     * @MethodName toString
     * @Description 重写Object类的toString()方法
     * @author xudp
     * @return string
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        return "name=" + name + ", age=" + age;
    }
}

 

执行反序列操作,这次就可以反序列成功了,如下所示:

  

四、serialVersionUID的取值

  serialVersionUID的取值是Java运行时环境根据类的内部细节自动生成的。如果对类的源代码作了修改,再重新编译,新生成的类文件的serialVersionUID的取值有可能也会发生变化。
  类的serialVersionUID的默认值完全依赖于Java编译器的实现,对于同一个类,用不同的Java编译器编译,有可能会导致不同的 serialVersionUID,也有可能相同。为了提高serialVersionUID的独立性和确定性,强烈建议在一个可序列化类中显示的定义serialVersionUID,为它赋予明确的值

  显式地定义serialVersionUID有两种用途:
    1、 在某些场合,希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有相同的serialVersionUID;
    2、 在某些场合,不希望类的不同版本对序列化兼容,因此需要确保类的不同版本具有不同的serialVersionUID。

文章转自:https://www.cnblogs.com/xdp-gacl/p/3777987.html

谢谢分享!

Java序列化反序列化的详细说明 本文介绍了 Java 中三种常见的序列化反序列化方式:Java 内置序列化、JSON 序列化(使用 Jackson 库) XML 序列化(使用 JAXB 库)。Java 内置序列化通过实现 Serializable 接口实现,简单易用但性能较低且存在安全性问题。JSON 序列化使用 Jackson 库,具有跨语言支持、可读性强性能较好的优点,但需要额外依赖。XML 序列化使用 JAXB 库,适合处理复杂结构,但性能较低且可能需要额外配置。每种方式均提供了具体的实现代码输出示例,帮助开发者根据需求选择 阅读详情

相关推荐

Java序列化工作机制

跟着作者的65节课彻底搞懂Java并发原理专栏,一步步彻底搞懂Java并发原理。 作者简介:笔名seaboat,擅长工程算法、人工智能算法、自然语言处理、计算机视觉、架构、分布式、高并发、大数据搜索引擎等方面的技术,大多数编程语言都会使用,但更擅长Java、PythonC++。平时喜欢看书写作、运动、画画。崇尚技术自由,崇尚思想自由。出版书籍:《Tomcat内核设计剖析》、《图解数据结构与算法》、《图解Java并发原理》、《人工智能原理科普》。 关于序列化 JDK内置同步器的实现类经常会看到ja.

seaboat——a free boat on the sea.(公众号:远洋号) 803

Java基础学习总结——Java对象序列化反序列化

一、序列化反序列化的概念   把对象转换为字节序列的过程称为对象序列化。  把字节序列恢复为对象的过程称为对象反序列化。  对象序列化主要有两种用途:  1) 把对象的字节序列永久地保存到硬盘上,通常存放在一个文件中;  2) 在网络上传送对象的字节序列。   在很多应用中,需要对某些对象进行序列化,让它们离开内存空间,入住物理硬盘,以便长期保存。比如最常见的是Web服务器中的Sess...

weixin_33698823的博客 513

手把手教你用mitmproxy抓包抖音数据流(附Python脚本模板)

本文详细介绍了如何使用mitmproxy抓包抖音数据流,包括环境搭建、证书安装Python脚本模板。从mitmproxy配置到抖音API解析,提供完整的移动端数据流分析方案,帮助开发者快速掌握数据抓取技术,适用于应用优化、竞品分析安全审计等场景。

weixin_33670786的博客 271

对象序列化反序列化详解

Java对象序列化时参与序列化的内容包含以下几个方面:1.属性,包括基本数据类型、数组以及其他对象的引用; 2.类名。不能被序列化的内容有以下几个方面:1.方法。 2.有static修饰的属性。 3.有transient修饰的属性。在序列化过程中不仅保留当前类对象的数据,而且递归保存对象引用的每个对象的数据。将整个对象层次写入字节流中,这也就是序列化对象的“深复制”,即复制对象本身及引用的对象

小小默:进无止境 6649

java serialize_Java序列化(Serialize)反序列化(Deserialize)

对象序列化一、目的:将对象转换成与平台无关的二进制流,从而可以保存到磁盘或者进行网络传输,其它程序获 得这个二进制流后可以将其还原成对象序列化机制可以使对象可以脱离程序的运行而对立存在。————————————————————————————————————————二、是什么?序列化(Serialize)指将一个java对象写入IO流中,与此对应的是,对象反序列化(Deserialize)则...

weixin_34945060的博客 1849

Java创建对象的方式——反序列化创建对象

目录Java创建对象的几种方式反序列化创建对象思路代码示例 Java创建对象的几种方式 Java创建对象的方式共有4种。分别为: 1、通过new语句实例化一个对象。 2、通过反射机制创建对象。 3、通过clone()方法创建一个对象。 4、通过反序列化的方式创建对象。 思考:反序列化是怎么创建对象的呢? 反序列化创建对象 思路 反序列化创建对象的过程,需要将流转换为对象。那么,可以通过序列化,将对象的状态写在流里面,根据需要把该流读取出来重新构造一个相同的对象。 代码示例 首先创建一个Car类实现Seria

weixin_36894490的博客 4744

Java对象序列化反序列化

当两个进程在进行远程通信时,彼此可以发送各种类型的数据。无论是何种类型的数据,都会以二进制序列的形式在网络上传送。发送方需要把这个Java对象转换为字节序列,即Java对象序列号,才能在网络上传送;接收方则需要把字节序列再恢复为Java对象,即反序列化。 把Java对象转换为字节序列的过程称为对象序列化。把字节序列恢复为Java对象的过程称为对象反序列化对象序列化主要有两种用途

quanleilei123的专栏 2743

java如何反序列化对象_Java序列化反序列化

1. Java序列化反序列化(What)Java序列化(Serialize)是指将一个Java对象写入IO流中;Java反序列化(Deserialize)指的是从IO流中回复IO对象。2. 序列化的意义(Why)序列化机制可以将Java对象转换为数据流用来保存在磁盘上或者通过网络传输。这使得对象可以脱离程序独立存在。3. 如何进行序列化(How)为了使对象支持序列化机制,需要让它的类变成可序列化...

weixin_29482557的博客 683

java对象序列化反序列化

引言 在学习IO流时,我们会学到一个序列化流,反序列化流,相信不少小伙伴学到这个是有些懵的,今天就带大家来了解一下java对象序列化流与反序列化流 目录 一、什么是java对象序列化流与反序列化流 二、对象序列化 三、对象反序列化流 四、对象序列化中我们容易遇到的集合小问题 一、什么是java对象序列化流与反序列化流 - 对象序列化:就是将对象保存到磁盘中,或者在网络中传输对象 Java 提供了一种对象序列化的机制...

秋雨绵绵 1032

java反序列化对象,【JavaJava对象序列化反序列化

对象序列化对象序列化机制允许把内存中的Java对象转换成与平台无关的二进制流,从而可以保存到磁盘或者进行网络传输,其它程序获得这个二进制流后可以将其恢复成原来的Java对象序列化机制可以使对象可以脱离程序的运行而对立存在序列化的含义意义序列化序列化机制可以使对象可以脱离程序的运行而对立存在序列化(Serialize)指将一个java对象写入IO流中,与此对应的是,对象反序列化(Deseri...

weixin_33717595的博客 247

Java对象数组序列化反序列化

先创建一个Java Bean /**一个low的Java Bean*/ public class Box implements Serializable{ private int width; private int height; public Box(){ } public Box(int width,int height){ this.wid

剑尚未佩妥 5711

【老白学 Java对象反序列化

上篇文章中,老白弄清楚了什么是对象序列化,也学会了如何把对象写入文件中。本篇文章老白准备继续学习如何从文件中恢复对象,了解一下反序列化的过程中都发生了哪些事情。

枯木逢春犹再发,人无两度再少年 1153

java反序列化多个对象_Java对象序列化反序列化

序列化反序列化序列化 (Serialization)是将对象的状态信息转换为可以存储或传输的形式的过程。一般将一个对象存储至一个储存媒介,例如档案或是记亿体缓冲等。在网络传输过程中,可以是字节或是XML等格式。而字节的或XML编码格式可以还原完全相等的对象。这个相反的过程又称为反序列化Java对象序列化反序列化Java中,我们可以通过多种方式来创建对象,并且只要对象没有被回收我们都可以复...

weixin_35211615的博客 622

Java 对象序列化反序列化

Java 对象序列化反序列化 对象序列化解决的问题:如何去发送对象的内容及如何接收解析对象的内容 序列化:把Java对象转换为字节序列的过程 写对象 反序列化:把字节序列恢复为Java对象的过程 读对象 对象输入输出流类: 序列化步骤: 1、创建一个类,继承Serializable接口 (只有当类继承了Serializable接口才能序列化反序列化) 2、创建该类...

紫蝶侠的博客 223

【潜意识JavaJava对象序列化反序列化

简单来说,对象序列化是将 Java 对象转换为字节流的过程,以便将其存储到文件、数据库或通过网络传输。而反序列化则是相反的操作,将字节流重新转换回 Java 对象,恢复其在内存中的状态。想象你有一个精美的乐高模型,要暂时收起来或者送给远方的朋友。序列化就像是把这个模型拆分成一个个小块,打包成便于运输的包裹;反序列化则是收到包裹后,按照说明重新把这些小块组装成原来的乐高模型。在 Java 里,对象就如同乐高模型,字节流是包裹,通过序列化反序列化对象能在不同环境中实现存储与还原。

潜意识Java的博客 1033

Java对象序列化反序列化方法

Java中要序列化一个对象,必须与一定的对象I/O流联系起来,通过对象输出流将对象状态保存下来,再通过对象输入流将对象状态恢复。  java.io包中,提供了ObjectInputStreamObjectOutputStream将数据流功能扩展至可读写对象 。 在ObjectInputStream 中用readObject()方法可以直接读取一个对象, ObjectOutputStream

竹君子之家 1330

Java对象序列化反序列化

对象序列化反序列化

CoderX(远离Bug)的博客 1116

Java对象序列化反序列化操作

Java的IO流不仅可以对字符进行传输,也可以对对象进行传输,叫做对象序列化反序列化 序列化:将对象转为方便传输的流(对象写入文件) 反序列化:将流转换成对应的对象(把对象从文件中拿出) 注意:如果我们需要将对象序列化到文件,首先需要让需要序列化对象对应的类实现序列化接口Serializable,该接口中没有任何方法属性,仅仅只是一个标志,表示实现该接口的类是可以被序列化的;如果没有实现该接口就进行序列化,会报出NotSerializableException没有序列化的异常 import java

m0_48008264的博客 319

Java序列化】使用Java 自带的Serializer进行对象序列化反序列化

Java开发中,对象序列化反序列化是常见的需求。序列化是指将对象的状态转换为字节流,从而可以将其存储到文件中或通过网络进行传输。反序列化则是这个过程的逆操作,即将字节流重新转换为对象Java标准库提供了类来实现这些功能。本文将介绍如何使用这些类来实现一个简单的序列化工具类。

weixin_55939638的博客 1966
上一篇: java中几种Map在什么情况下使用,并简单介绍原因及原理
下一篇: java并发机制的学习—线程优先级
TofuCai
博客等级 码龄8年 16粉丝 43原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值