Java的序列化

2023-11-13

写在前面

本文看下序列化和反序列化相关的内容。

源码

1:为什么,什么是序列化和反序列化

Java对象是在jvm的堆中的,而堆其实就是一块内存,如果jvm重启数据将会丢失,当我们希望jvm重启也不要丢失某些对象,或者是需要将某些对象传递到其他服务器(rpc有没有!!!)时就需要使用到序列化和反序列化,因为序列化就是将Java对象转换为文件,而反序列化就是加载文件并生成对象在堆中。
在这里插入图片描述

2:Java的序列化和反序列化

Java想要序列化和反序列化,必须实现java.io.Serializable接口,并给变量serialVersionUID赋值,该值用来标识Java类文件的版本。如下序列化和反序列化的例子:

@SneakyThrows
private static void javaDeserialize() {
    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream("d:\\test\\xxx.obj"));
    Student student = (Student) objectInputStream.readObject();
    System.out.println("java反序列化student完成");
    System.out.println(student);
}

@SneakyThrows
private static void javaSerialize() throws IOException {
    Student student = new Student();
    student.setName("张三");
    student.setAge(99);
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream("d:\\test\\xxx.obj"));
    // 如果没有实现java.io.Serializable接口将会抛出异常java.io.NotSerializableException
    objectOutputStream.writeObject(student);
    objectOutputStream.close();
    System.out.println("java序列化student完成");
}

java序列化的问题:

1:无法跨平台
    如Java对象序列化的结果反序列化为python的对象,这样就限制了其不适合某些使用场景,如rpc的场景中就无法使用这种序列化方式,因为rpc需要支持异构的系统
2:序列化的文件大
    这样占用磁盘大,网络传输速度慢,占用带宽,反序列化的速度也慢,这样就限制了其不适合某些使用场景,如rpc,rpc需要尽量快的序列化和反序列化速度,以提高性能
3:序列化的速度慢
    还是因为其序列化结果的内容多

以上的问题我们可以使用专门的序列化框架来解决,如hessian。

3:hessian的序列化和反序列化

dubbo 默认使用的是该序列化方式,将来可能会优化成性能更优的序列化方式如kryo,fst等。

hessian支持语言无关的序列化和反序列化,并且速度更快,序列化的结果更小,如下:

private void hessianSerialize() {
    Student stu = new Student("hessian",1);
    byte[] obj = serialize(stu);
    System.out.println("hessian serialize result length = "+obj.length);
    byte[] obj2 = serialize2(stu);
    System.out.println("hessian2 serialize result length = "+obj2.length);
    byte[] other = jdkSerialize(stu);
    System.out.println("jdk serialize result length = "+other.length);
    Student student = deserialize2(obj2);
    System.out.println("deserialize result entity is "+student);
}

具体看文章头源码。
运行结果如下:

hessian serialize result length = 65
hessian2 serialize result length = 59
jdk serialize result length = 101
deserialize result entity is Student(name=hessian, age=1)

可以看到结果的大小jdk序列化<hessian序列化<hessian2序列化,所以如果工作中有这种需求,建议使用hessian2。

4:arvo的序列化和反序列化

使用步骤如下:

1:定义.avsc描述文件
2:通过avro-tool.jar,以.avsc描述文件作为输入生成pojo
3:通过avro.jar的API进行序列化(生成.avro文件)和反序列化

首先我们需要定义IDL,命名为User.avsc:

{
    "namespace": "dongshi.daddy.seriablize.avro",
    "type": "record",
    "name": "User",
    "fields": [
        {"name": "name", "type": "string"},
        {"name": "id", "type": "int"},
        {"name": "salary", "type": "int"},
        {"name": "age", "type": "int"},
        {"name": "address", "type": "string"}
    ]
}

接着通过avro-tools.jar生成pojo,如下:

$ java -jar avro-tools-1.8.2.jar compile schema User.avsc res
Input files to compile:
  User.avsc
log4j:WARN No appenders could be found for logger (AvroVelocityLogChute).
log4j:WARN Please initialize the log4j system properly.
log4j:WARN See http://logging.apache.org/log4j/1.2/faq.html#noconfig for more info.

然后我们将生成的User.java文件拷贝到classpath的dongshi.daddy.seriablize.avro目录,接着就可以执行序列化和反序列化了,首先执行序列化:

@Test
public void testAvroSerialize() throws Exception {
// 声明并初始化User对象
    // 方式一
    User user1 = new User();
    user1.setName("wqbin");
    user1.setId(1);
    user1.setSalary(1000);
    user1.setAge(20);
    user1.setAddress("beijing");

    // 方式二 使用构造函数
// Alternate constructor
    User user2 = new User("wang", 2, 1000, 19, "guangzhou");

// 方式三,使用Build方式
// Construct via builder
    User user3 = User.newBuilder()
            .setName("bin")
            .setId(3)
            .setAge(21)
            .setSalary(2000)
            .setAddress("shenzhen")
            .build();
    String userDir = System.getProperty("user.dir");
    System.out.println("userDir is: " + userDir);
    String path = userDir + "/User.avro"; // avro文件存放目录
    DatumWriter<User> userDatumWriter = new SpecificDatumWriter<User>(User.class);
    DataFileWriter<User> dataFileWriter = new DataFileWriter<User>(userDatumWriter);
    dataFileWriter.create(user1.getSchema(), new File(path));
// 把生成的user对象写入到avro文件
    dataFileWriter.append(user1);
    dataFileWriter.append(user2);
    dataFileWriter.append(user3);
    dataFileWriter.close();
}

生成文件如下:
在这里插入图片描述

接着执行反序列化:

@Test
public void testAvroDeserialize() throws Exception {
    DatumReader<User> reader = new SpecificDatumReader<User>(User.class);
    DataFileReader<User> dataFileReader = new DataFileReader<User>(new File(System.getProperty("user.dir") + "/User.avro"), reader);
    User user = null;
    while (dataFileReader.hasNext()) {
        user = dataFileReader.next();
        System.out.println(user);
    }
}

输出如下内容则为成功:

{"name": "wqbin", "id": 1, "salary": 1000, "age": 20, "address": "beijing"}
{"name": "wang", "id": 2, "salary": 1000, "age": 19, "address": "guangzhou"}
{"name": "bin", "id": 3, "salary": 2000, "age": 21, "address": "shenzhen"}

Process finished with exit code 0

5:kryo的序列化和反序列化

kryo是底层使用了ASM字节码技术,所以其只能使用在基于JVM的语言上,如Java,scala,kotlin等,接下来看下其如何使用。

  • 首先引入pom:
<dependency>
    <groupId>com.esotericsoftware</groupId>
    <artifactId>kryo</artifactId>
    <version>5.2.0</version>
</dependency>
  • 序列化:
@Test
public void testKrypSerialize() throws Exception {
    Kryo kryo = new Kryo();
    kryo.register(SomeClass.class);

    SomeClass someClass = new SomeClass();
    someClass.value = "dongshidaddy";
    Output output = new Output(new FileOutputStream(userDir + "/someCls.bin"));
    kryo.writeObject(output, someClass);
    output.close();
}

运行后:
在这里插入图片描述

  • 反序列化
@Test
public void testKrypDeserialize() throws Exception {
    Kryo kryo = new Kryo();
    kryo.register(SomeClass.class);

    Input input = new Input(new FileInputStream(userDir + "/someCls.bin"));
    SomeClass someClassFromBin = kryo.readObject(input, SomeClass.class);
    System.out.println(someClassFromBin.value);
}

运行后:

dongshidaddy

Process finished with exit code 0

6:fst的序列化和反序列化

java的序列化和反序列化方式,性能优秀(jdk原生序列化速度的10倍,序列化结果体积1/3左右),如果有序列化的需求可以考虑使用。看下如何使用。

  • 引入pom
<dependency>
    <groupId>de.ruedigermoeller</groupId>
    <artifactId>fst</artifactId>
    <version>2.04</version>
</dependency>
  • 序列化和反序列化
// fst序列化和反序列化
@Test
public void testFstSerializeAndDescrialize() {
    dongshi.daddy.seriablize.fst.User bean = new dongshi.daddy.seriablize.fst.User();
    bean.setUsername("xxxxx");
    bean.setPassword("123456");
    bean.setAge(1000000);
    byte[] byteBean = configuration.asByteArray(bean);
    System.out.println("序列化的字节大小是:" + byteBean.length);
    // 反序列化
    dongshi.daddy.seriablize.fst.User resultBean = (dongshi.daddy.seriablize.fst.User) configuration.asObject(byteBean);
    System.out.println("fst反序列化的结果是:" + resultBean);
}

输出如下内容则为成功:

序列化的字节大小是:68
fst反序列化的结果是:User(username=xxxxx, age=1000000, password=123456)

Process finished with exit code 0

写在后面

巨人的肩膀

再来认识一下 Java 序列化

Hessian序列化实例

Avro从入门到入土

深入浅出序列化(2)——Kryo序列化

Kryo 和 FST 序列化

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

Java的序列化 的相关文章

随机推荐

  • 【Hello Algorithm】最大线段重合及加强堆

    本篇博客简介 介绍加强堆 加强堆 最大线段重合问题 加强堆 计算时间复杂度的技巧 一般来说 我们在刷算法的时候都要求C C 语言在1到2s之内完成 java这种语言在2到4秒之内完成 而与之对应的指令条数就是 十的八次方 左右 不会超过一个
  • android 刷机后熄屏断网

    情况说明 我的黑鲨1代刷机后 部署了Linux系统 但是只要熄屏后过一会儿就无法访问网络了 尝试了修改电量管理 关闭省电模式等 均无效 经过很久很久的测试 终于找到了原因 Android6 0或更高版本系统有一个Doze模式和App Sta
  • centos虚拟机服务器手把手搭建

    虚拟机服务对于开发人员来说 并不陌生 熟悉项目环境搭建 服务部署 运维集成 前期准备 1 下载一个VMware Workstation 工具 链接 https pan baidu com s 1lh68j846lxMfKVGtUlMNXA
  • Android 使用motion 动画如何使用

    MotionLayout 是 Android 中的一个强大的布局容器 它可以用来创建复杂的动画和过渡效果 允许你在布局中定义多个状态 并在这些状态之间进行平滑的动画过渡 以下是使用 MotionLayout 创建动画的基本步骤 1 添加依赖
  • 演化博弈论基本概念

    文章目录 混合策略 符号 混合策略的空间几何 策略组合的表示 混合策略收益函数 最优反应 最佳反应集合 混合策略 符号 标准博弈可以写成 G I S
  • 智慧园区参观纪要

    首都国企开放日期间 云梯联盟举办了 深入走进创新主体 活动 昨天参观了牡丹集团旗下的智慧园区 现在做一个简单的纪要 1 国企战略转型经历的四个阶段 第一个阶段是初创时期实施 一体化 战略 发展园区服务业 第二个阶段是起步时期实施 一体两翼
  • USART与UART的区别

    USART universal synchronous asynchronous receiver and transmitte 通用同步异步收发器 USART是一个串行通信设备 可以灵活地与外部设备进行全双工数据交换 UART unive
  • apt-get install 错误解决

    E Could not get lock var lib dpkg lock open 11 Resource XXX unavailable E Unable to lock the XXX directory var lib dpkg
  • 如何删除git submodules

    Stage the gitmodules changes git add gitmodules Delete the relevant section from git config Remove the submodule files f
  • shell 清理日志文件内容

    一般日志文件都是 按照yyyy MM dd 格式划分的文件 bin bash function read dir ls date date Y m d for file in ls 1 do if d 1 file then read di
  • HBase-10 Region的分裂策略

    Region的分裂策略 1 region 分裂策略 ConstantSizeRegionSplitPolicy IncreasingToUpperBoundRegionSplitPolicy SteppingSplitPolicy KeyP
  • delphi怎么通过企业微信自建应用接收用户发送的信息

    如果你想在 Delphi 中使用企业微信自建应用接收用户发送的信息 你需要先了解企业微信自建应用的相关接口文档 然后 你可以使用 Delphi 的网络库 比如 Indy 或 Synapse 发送 HTTP 请求来调用这些接口 并解析响应内容
  • 小程序-吸顶下拉框

    今天给大家带来的是在开发小程序过程中遇到一个下拉菜单 废话不多说先给大家上一波图 感谢崔老师 其实是萌萌的大汉 给与后期帮助与完善 一开始页面硬画出来的效果还不错 但是需求做到后面发现又有多个下拉框菜单 但是菜单的内容同 熟悉下拉框的同学都
  • unity跳过QuickTime播放视频的另一种方式

    本文转载自http blog csdn net awnuxcvbn article details 17618919 点击这里下载视频转换器 该转换器会把其他格式转化为ogv格式 直接被unity识别 不需要安装quicktime不需要重启
  • GitHub命令汇总(实用版)

    问题 在GitHub使用过程中用命令git clone下载和使用页面上download zip的下载有什么不一样 使用git clone下载的是一个仓库 使用download zip下载的是一个普通文件夹 还需要用git init初始化才能
  • thinkPHP6.0入门笔记(六)——模板继承

    thinkPHP6 0的模板继承 1 构建简易导航栏 2 thinPHP6 0模板继承 1 构建简易导航栏 bootstrap提供了很多样式 但是怎么说 很多样式直接使用还是有点别扭 这里在PC端自定义一个导航栏 HTML代码如下
  • Centos7 使用yum从第三方仓库安装Python3.8

    环境 CentOS Linux release 7 9 2009 起因 Centos 7 自带Python2 7 5版本 而默认的 YUM 安装的python3是 3 6版本 遂升级到3 8版本 install Python3 8 yum
  • 解决若依后台管理系统打包线上偶发性elementUI的icon会出现乱码的问题

    1 问题图片 本地运行环境下是没有问题的 打包线上环境就会出现乱码情况 这时候我们发会发现在浏览器上看样式content 乱码 百度了很多 也尝试了各种方法都没有用 最后看到这篇博文添加链接描述得以解决 2 解决方法 升级sass版本至1
  • Vue中的生命周期

    什么是生命周期 生命周期 1 又名 生命周期回调函数 生命周期函数 生命周期钩子 2 是什么 Vue在关键时刻帮我们调用的一些特殊名称的函数 3 生命周期函数的名字不可更改 但函数的具体内容是程序员根据需求编写的 4 生命周期函数中的thi
  • Java的序列化

    写在前面 本文看下序列化和反序列化相关的内容 源码 1 为什么 什么是序列化和反序列化 Java对象是在jvm的堆中的 而堆其实就是一块内存 如果jvm重启数据将会丢失 当我们希望jvm重启也不要丢失某些对象 或者是需要将某些对象传递到其他