Java序列化、反序列化-为什么要使用序列化?Serializable接口的作用?

news2024/12/23 6:51:38

什么是序列化和反序列化?

  • 把对象转换成字节序列
  • 把字节序列恢复成对象

结合OSI七层协议模型,序列化和反序列化是在那一层做的?

在OSI七层模型中,序列化工作的层级是表示层。这一层的主要功能包括把应用层的对象转换成一段连续的二进制串,或者反过来,把二进制串转换成应用层的对象。

为什么要使用序列化?

序列化的作用是将对象转换为可以存储或传输形式的过程,这样对象可以存储在内存或文件中(内存或文件实际上是以字节为单位的),我们要转换成机器能够认识的单位。比方说我们需要把一个对象传输到另一台机器

网络传输,跨机器,要转换成机器能识别的格式,反之

Serializable接口的作用

做标记,实现Serializable接口的类表示可以序列化,告诉程序实现了它的对象是可以被序列化的。如果对某个没有实现Serializable接口的类直接序列化将会报”NotSerializableException“错误。

这个时候有些人就会想:当对象中的某些信息,比方说密码或身份证,我不想暴露有没有什么办法?当然JDK已经给我们想到了这些问题,为了保障数据的安全性,当实现serialVersional接口实现序列化的时候可以使用transient或static关键字修饰某个字段,被修饰的字段就不会被序列化反序列时也不会被持久化和恢复,会被置成默认值

//因为序列化保存的是对象的状态,而 static 修饰的字段属于类的状态,因此可以证明序列化并
//不保存 static 修饰的字段。
public static Long cardId;

// transient临时修饰成员,阻止字段被序列化
//当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复,会被置成类型默认值
private transient String password;

注意:

普通对象序列化和反序列化返回的是两个不同的对象

枚举类型序列化的对象是static final的,不会回收,所以反序列化回来的对象和原来的对象是同一个

序列化和反序列化的方式有哪些?

  1. JDK自带序列化方式
  2. Kryo

JDK自带序列化方式

Student类
package org.example.SerializableTest;

import lombok.Data;

import java.io.Serializable;

@Data
public class Student implements Serializable {
    private static final long serialVersionUID = 1L;
    
    public Student(String name,Integer age,Integer score,Integer studentId,String password){
        this.name=name;
        this.age=age;
        this.score=score;
        this.studentId=studentId;
        this.password=password;
    }


    private String name;
    private Integer age;
    private Integer score;
    private Integer studentId;

    // transient瞬态修饰成员,不会被序列化
    //当对象被反序列化时,被transient修饰的变量值不会被持久化和恢复,会被置成类型默认值
    private transient String password;
}

序列化:
Student student = new Student("唐三", 18, 100, 001, "123456");
        try {
            FileOutputStream fos = new FileOutputStream("dlm.txt");
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            oos.writeObject(student);
            oos.close();
        } catch (IOException e) {
            e.printStackTrace();
}

反序列化:

通过输出文件中的对象我们可以发现用transient修饰的password字段被隐藏了,保证了信息的安全

在Student类中不知道大家有没有发现serialVersionUID这个字段,这个字段的作用用来验证版本的,对版本进行表示。在序列化的时候会记录将serialVersionUID

在反序列化的时候将serialVersionUID和本地实体类的serialVersionUID进行比较,如果一致则可以反序列化,否则则说明序列化版本不一致

serialVersionUID默认是“1L”,可以自动生成

Kryo

是一个支持序列化/反序列化的工具

KryoStudent类

package org.example.SerializableTest;

import lombok.Data;

@Data
class KryoStudent {
    public KryoStudent() {

    }

    public KryoStudent(String name, Integer age, Integer score, Integer studentId, String password) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.studentId = studentId;
        this.password = password;
    }

    private String name;
    private Integer age;
    private Integer score;
    private Integer studentId;
    private transient String password;

    @Override
    public String toString() {
        return "KryoStudent{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                ", studentId=" + studentId +
                ", password='" + password + '\'' +
                '}';
    }
}
package org.example.SerializableTest;

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.objenesis.strategy.StdInstantiatorStrategy;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;

public class KryoDemo {
    public static void main(String[] args) throws FileNotFoundException {
        //创建一个 Kryo 对象
        Kryo kryo = new Kryo();
        //将对象进行注册
        kryo.register(KryoStudent.class);

        KryoStudent object = new KryoStudent("唐三", 18, 100, 001, "123456");


        //序列化
        Output output = new Output(new FileOutputStream("dlm.txt"));
        //将 Java 对象序列化为二进制流
        kryo.writeObject(output, object);
        output.close();

        Input input = new Input(new FileInputStream("dlm.txt"));
        //将二进制流反序列化为 Java 对象
        KryoStudent object2 = kryo.readObject(input, KryoStudent.class);
        System.out.println(object2);
        input.close();
    }


    //反序列化
    public void setSerializableObjectStudent() throws FileNotFoundException {
        Output output = new Output(new FileOutputStream("dlm.txt"));
        Kryo kryo = new Kryo();
        kryo.setReferences(false);
        kryo.setRegistrationRequired(false);
        kryo.setInstantiatorStrategy(new StdInstantiatorStrategy());
        kryo.register(KryoStudent.class);

    }
}
Kryo方式有什么缺点吗?
  1. 不是线程安全的,每个线程都有自己的Kryo对象、输入和输出实例
  2. 只支持Java实现


既然JDK和Kryo都可以进行序列化和反序列化,那分别用JDK和Kryo提供的序列化和反序列化方式对10000个对象进行转换,从时间上我们来看一下它的性能

JDK和Kryo性能对比

Student类

import lombok.Data;

import java.io.Serializable;

@Data
public class Student implements Serializable {
    public Student(String name, Integer age, Integer score, Integer studentId, String password){
        this.name=name;
        this.age=age;
        this.score=score;
        this.studentId=studentId;
        this.password=password;
    }


    private String name;
    private Integer age;
    private Integer score;
    private Integer studentId;

    // transient瞬态修饰成员,不会被序列化
    private transient String password;
}

KryoStudent类

import lombok.Data;

@Data
class KryoStudent {
    //Kryo不支持包含无参构造器类的反序列化,所以需要把无参构造器显示出来。
    public KryoStudent() {

    }

    public KryoStudent(String name, Integer age, Integer score, Integer studentId, String password) {
        this.name = name;
        this.age = age;
        this.score = score;
        this.studentId = studentId;
        this.password = password;
    }

    private String name;
    private Integer age;
    private Integer score;
    private Integer studentId;
    private transient String password;

    @Override
    public String toString() {
        return "KryoStudent{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", score=" + score +
                ", studentId=" + studentId +
                ", password='" + password + '\'' +
                '}';
    }
}

JDK序列化和反序列化

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.junit.Test;

import java.io.*;
import java.util.ArrayList;

public class test5 {
    //序列化
    @Test
    public void test1() throws Exception {
        long time = System.currentTimeMillis();
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("dlm.txt"));
        for (int i = 0; i < 10000; i++) {
            oos.writeObject(new Student("唐三", 18, 100, i, "123456"));
        }
        oos.close();
        System.out.println("JDK序列化消耗的时间" + (System.currentTimeMillis() - time));
    }

    //反序列化
    @Test
    public void test2() throws Exception {
        long time = System.currentTimeMillis();
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("dlm.txt"));
        Student student = null;
        try {
            while (null != (student = (Student) ois.readObject())) {

            }
        } catch (EOFException e) {

        }
        System.out.println("JDK反序列化消耗的时间" + (System.currentTimeMillis() - time));
    }
}

Kryo序列化和反序列化

import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.KryoException;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import org.junit.Test;

import java.io.*;
import java.util.ArrayList;

public class test5 {

    //序列化
    @Test
    public void test1() throws Exception {
        long time = System.currentTimeMillis();
        Kryo kryo = new Kryo();
        //将对象进行注册
        kryo.register(KryoStudent.class);
        Output output = new Output(new FileOutputStream("dlm.txt"));

        //存储10000个对象
        for (int i = 0; i < 10000; i++) {
            kryo.writeObject(output, new KryoStudent("唐三", 18, 100, i, "123456"));
        }

        output.close();
        System.out.println("Kryo序列化消耗的时间" + (System.currentTimeMillis() - time));
    }

    //反序列化
    @Test
    public void test2() throws Exception {
        long time = System.currentTimeMillis();
        Kryo kryo = new Kryo();
        kryo.register(KryoStudent.class);
        Input input = new Input(new FileInputStream("dlm.txt"));
        KryoStudent student = null;

        //反序列化文件中的对象
        try {
            while (null != (student = kryo.readObject(input, KryoStudent.class))) {

            }
        } catch (KryoException e) {

        }
        input.close();
        System.out.println("Kryo反序列化消耗的时间" + (System.currentTimeMillis() - time));
    }
}

结果为:

从输出结果上我们发现时间上有很大的不同,Kryo序列化和反序列化相比于JDK都快很多,那为什么会产生这样的结果呢?

  1. Kryo依赖于字节码生成机制(底层使用了ASM库)
  2. Kryo序列化时,只将对象的信息、对象属性值的信息等进行序列化,没有将类field的描述信息进行序列化,这样就比JDK自己的序列化结果要小很多,而且速度肯定更快。
  3. Kryo序列化出的结果是其自定义的、独有的一种格式,因此像redis这样可以存储二进制数据的存储引擎可以直接将Kryo序列化出来的数据存进去也可以选择转换成String的形式存储在其他存储引擎中(性能有损耗)

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1320407.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

5.5 DataFrame.rolling()创建滚动窗口对象

DataFrame.rolling创建滚动窗口对象 一、介绍二、代码一、介绍 DataFrame.rolling() 是 pandas 中用于创建滚动窗口对象的函数,它可以对时间序列或其他类型的数据进行滚动计算。下面是该函数的一些参数说明: DataFrame.rolling(window, min_periods=None, center=False, win_…

Flink系列之:自定义函数

Flink系列之&#xff1a;自定义函数 一、自定义函数二、概述三、开发指南四、函数类五、求值方法六、类型推导七、自动类型推导八、定制类型推导九、确定性十、内置函数的确定性十一、运行时集成十二、标量函数十三、表值函数十四、聚合函数十五、表值聚合函数 一、自定义函数 …

Windows使用VNC Viewer远程桌面Ubuntu【内网穿透】

文章目录 前言1. ubuntu安装VNC2. 设置vnc开机启动3. windows 安装VNC viewer连接工具4. 内网穿透4.1 安装cpolar【支持使用一键脚本命令安装】4.2 创建隧道映射4.3 测试公网远程访问 5. 配置固定TCP地址5.1 保留一个固定的公网TCP端口地址5.2 配置固定公网TCP端口地址5.3 测试…

微信小程序背景图片设置

问题 :微信小程序通过css:background-image引入背景图片失败 [渲染层网络层错误] pages/wode/wode.wxss 中的本地资源图片无法通过 WXSS 获取&#xff0c;可以使用网络图片&#xff0c;或者 base64&#xff0c;或者使用<image/>标签 解决方法微信小程序在使用backgroun…

每日一题:LeetCode-LCR 016. 无重复字符的最长子串

每日一题系列&#xff08;day 15&#xff09; 前言&#xff1a; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f308; &#x1f50e…

[Kubernetes]3. k8s集群Service详解

在上一节讲解了k8s 的pod,deployment,以及借助pod,deployment来部署项目,但会存在问题: 每次只能访问一个 pod,没有负载均衡自动转发到不同 pod访问还需要端口转发Pod重创后IP变了,名字也变了针对上面的问题,可以借助Service来解决,下面就来看看Service怎么使用 一.Service详…

SpringBoot中使用@Async实现异步调用

SpringBoot中使用Async实现异步调用 什么是异步调用?异步调用对应的是同步调用&#xff0c;同步调用指程序按照定义顺序依次执行&#xff0c;每一行程序都必须等待上 一行程序执行完成之后才能执行&#xff1b;异步调用指程序在顺序执行时&#xff0c;不等待异步调用的语句返…

Python 实现:OCR在图片中提取文字(基于Gradio实现)

Paddle OCR PaddleOCR 基于深度学习技术实现的&#xff0c;使用十分简单。 先看效果 可以看出来识别效果还是不错的&#xff0c;里面的“湿”字识别成了繁体字。如果不是连体字&#xff0c;就不会出现这个问题。 1.测试环境 操作系统&#xff1a;Win10 Python&#xff1a;3…

ROS机器人入门

http://www.autolabor.com.cn/book/ROSTutorials/ 1、ROS简介 ROS 是一个适用于机器人的开源的元操作系统。其实它并不是一个真正的操作系统&#xff0c;其 底层的任务调度、编译、寻址等任务还是由 Linux 操作系统完成&#xff0c;也就是说 ROS 实际上是运 行在 Linux 上的次级…

xv6 文件系统(下)

〇、前言 计算机崩溃后如何恢复&#xff0c;是一个很重要的话题。对于内存中的数据无关痛痒&#xff0c;开机后重新载入就能解决问题&#xff1b;但是对于持久化存储设备&#xff0c;当你尝试修改一个文件&#xff0c;突然断电当你重新打开文件后&#xff0c;这个文件的状态是…

Java基础回顾——面向对象编程

文章目录 面向对象基础方法构造方法默认构造方法多构造方法 方法重载继承多态抽象类接口静态字段和静态方法包作用域内部类 写在最后 https://www.liaoxuefeng.com/wiki/1252599548343744/1255943520012800 面向对象编程Object-Oriented Programming&#xff0c;简称OOP&#…

06. Python模块

目录 1、前言 2、什么是模块 3、Python标准库模块 3.1、os模块 3.2、datetime 模块 3.3、random模块 4、自定义模块 4.1、创建和使用 4.2、模块命名空间 4.3、作用域 5、安装第三方依赖 5.1、使用 pip 安装单个依赖 5.2、从 requirements.txt 安装依赖 5.3、安装指…

Python:(Sentinel-1)如何解析SNAP输出的HDF5文件并输出为GeoTIFF?

博客已同步微信公众号&#xff1a;GIS茄子&#xff1b;若博客出现纰漏或有更多问题交流欢迎关注GIS茄子&#xff0c;或者邮箱联系(推荐-见主页). Python&#xff1a;&#xff08;Sentinel-1&#xff09;如何解析SNAP输出的HDF5文件并输出为GeoTIFF&#xff1f; 01 前言 最近…

【NI-RIO入门】使用LabVIEW进行数据采集测量

于ni kb摘录 选择合适的编程模式 CompactRIO系统具有至少两个用户可选模式。某些CompactRIO型号具有附加的用户可选模式&#xff0c;可以在实时NI-DAQmx中进行编程。请参考本文以判断您的CompactRIO是否能够使用实时NI-DAQmx。将目标添加到项目后&#xff0c;将提示您选择要使…

TestSSLServer4.exe工具使用方法简单介绍(查SSL的加密版本SSL3或是TLS1.2)

一、工具使用方法介绍 工具使用方法参照&#xff1a;http://www.bolet.org/TestSSLServer/ 全篇英文看不懂&#xff0c;翻译了下&#xff0c;能用到的简单介绍如下&#xff1a; 将下载的TestSSLServer4.exe工具放到桌面上&#xff0c;CMD命令行进入到桌面目录&#xff0c;执…

Gitee基础知识

目录 1-gitee 1.1gitee介绍 1.2git与gitee的关系 1.3在国内为什么选择Gitee 2-注册与创建远程仓库 2.1注册 2.2创建远程仓库 2.3配置ssh公钥 2.3.1公钥的生成方法&#xff1a; 2.3.2 在gitee中配置公钥 2.3.4验证公钥 3-添加与推送远程仓库master 3.1基本命令…

78-C语言-完数的判断,以及输出其因子

简介&#xff1a;一个数如果恰好等于它的因子之和&#xff0c;这个数就称为完数&#xff0c;C语言编程找出1000之内的所有完数&#xff0c;并输出其因子。因子可以整除该数字的数&#xff0c; 如6的因子&#xff1a;1 2 3&#xff0c;6%10 6%20 6%30 解释全在注…

20 5G中高速列车通信:设计相关元素以减轻高移动性带来的影响

文章目录 一 、物理层设计1 DMRS2 CSI 和SRS3 PTRS4 多天线配置 二 初始接入三 目前面临困难 解决问题&#xff1a;列车高速移动&#xff0c;会使信道相干时间较短、多普勒频移和多普勒扩展较大等问题。为了在列车高速移动中解决这些问题&#xff0c;这篇文章概括了5G关键技术&…

掌动智能浅谈云网络流量分析的主要过程

在云计算时代&#xff0c;网络流量分析成为确保网络安全和性能的重要环节。随着企业和组织将应用和服务迁移到云平台&#xff0c;对云网络流量进行深入的分析变得至关重要。本文将介绍云网络流量分析的主要过程&#xff0c;以帮助读者更好地理解如何有效地监控和管理云环境中的…

MySQL进阶|MySQL中的事务(一)

文章目录 数据库事务MySQL中的存储引擎InnoDB存储引擎架构什么是事务事务的状态总结 数据库事务 MySQL 事务主要用于处理操作量大&#xff0c;复杂度高的数据。比方我想要删除一个用户&#xff08;销户&#xff09;以及这个用户的个人信息、订单信息以及其他信息&#xff0c;这…