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

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

1. 概述

序列化:将Java对象转换为二进制数据流的过程

反序列化:将序列化过程生成的二进制字节流转化为Java对象的过程

主要目的:

  • 通过网络传输Java对象
  • 将Java对象保存在本地文件系统,数据库。

应用场景:

  • 远程RPC调用
  • 将对象存储到Redis缓存数据库

2. 具体实现

2.1 JDK 方式

ObjectOutputStream:内存中的对象—>存储中的文件、通过网络传输出去:序列化过程
ObjectInputStream:存储中的文件、通过网络接收过来 —>内存中的对象:反序列化过程

2.1.1 序列化步骤
  1. 创建类,实现接口:Serializable

  2. 当前类提供一个全局常量:serialVersionUID

    序列化号 serialVersionUID 属于版本控制的作用。序列化的时候 serialVersionUID 也会被写入二级制序列,当反序列化时会检查 serialVersionUID 是否和当前类的 serialVersionUID 一致

  3. 使用对象流ObjectOutputStream进行序列化

PS:

  • 序列化的对象内部如果有其他对象的引用,该对象也必须可序列化(实现Serializable,全局常量:serialVersionUID)
  • 不能序列化static和transient修饰的成员变量
2.1.2 序列化代码
//1. 创建可序列化对象
public class Person implements Serializable {//实现接口,该接口是一个声明式接口
//2. 声明全局变量
    private final static long serialVersionUID = 34L;//该数可以是任意数

    public String name;
    int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}
public class test {
    public static void main(String[] args) {
        ObjectOutputStream oos = null;
        try {
            //3. 通过对象流序列化对象
            //3.1 创建文件输入流对象传入构造器,指定对象序列化数据存储位置
            oos = new ObjectOutputStream(new FileOutputStream("object.dat"));

            oos.writeObject(new Person("jim",23));
            oos.flush();
        } catch (IOException e) {
            throw new RuntimeException(e);
        } finally {
            try {
                //不要忘记关闭资源哦!!!
                oos.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

反序列化方式不再赘述,直接贴代码!!!

public class test {
    public static void main(String[] args) {
        ObjectInputStream ois = null;

        try {
            //反序列化
            ois = new ObjectInputStream(new FileInputStream("object.dat"));
            Person person = (Person) ois.readObject();
            System.out.println(person.name);
        } catch (IOException e) {
            throw new RuntimeException(e);
        } catch (ClassNotFoundException e) {
            throw new RuntimeException(e);
        }finally {
            try {
                ois.close();
            } catch (IOException e) {
                throw new RuntimeException(e);
            }
        }
    }
}

But!!!学完这些东西,才发现发现~~~基本不用这种方式!

因为:

  • 不支持跨语言调用
  • 性能差:序列化之后的字节文件体积较大,要知道我们的网络资源有时候是很宝贵的,所以传输成本越低越好。

那么:有一些序列化框架十分优秀,可以帮助我们完成序列化和反序列化的操作

2.2 序列化框架

Kryo

首先,先贴上Kryo的GitHub地址kryo,学技术当然第一时间要看官方资料啦。具体的信息可以自行前往项目地址查看这里不再赘述。

Kryo 是一个高性能的序列化/反序列化工具,由于其变长存储特性并使用了字节码生成机制,拥有较高的运行速度和较小的字节码体积。

另外,Kryo 已经是一种非常成熟的序列化实现了,已经在 Twitter、Groupon、Yahoo 以及多个著名开源项目(如 Hive、Storm)中广泛的使用。

下面,对kryo进行简单使用。

(1)导入Kryo包

下面是Maven依赖,不使用maven和从源代码构建的方式请参考官网

<dependency>
   <groupId>com.esotericsoftware</groupId>
   <artifactId>kryo</artifactId>
   <version>5.3.0</version>
</dependency>

(2)快速使用

public class KryoTest {
        static public void main (String[] args) throws Exception {
            Kryo kryo = new Kryo();
            Person person = new Person("jim",23);
            
      		//Kryo 为了提供性能和减小序列化结果体积,提供注册的序列化对象类的方式。在注册时,会为该序列化类生成 int ID,后续在序列化时使用 int ID 唯一标识该类型。注册的方式如下:
            kryo.register(person.class);

            person object = new person();
            object.value = "Hello Kryo!";

            Output output = new Output(new FileOutputStream("file.bin"));
            kryo.writeObject(output, object);
            output.close();

            Input input = new Input(new FileInputStream("file.bin"));
            person object2 = kryo.readObject(input, person.class);
            System.out.println(person.name);
            input.close();
        }
        static public class person {
            String value;
        }
}

除了Kryo以外还有许多序列化框架:

  • FST:https://github.com/RuedigerMoeller/fast-serialization
  • Protobuf:https://github.com/protocolbuffers/protobuf
  • protoStuff:https://github.com/protostuff/protostuff
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值