序列化反序列化Demo-jdk、json、protobuf

demo

public static void main(String[] args) throws Exception {
        /***** jdk begin *****/
        File file = new File("D:/saloonCar.out");
        Car saloonCar = new Car("轿车", new BigDecimal("88888"));
        System.out.println("jdk原始对象-类型:" + saloonCar.getType() + ",价格:" + saloonCar.getPrice());
        OutputStream out = new FileOutputStream(file);
        ObjectOutputStream outputStream = new ObjectOutputStream(out);
        outputStream.writeObject(saloonCar);
        System.out.println("jdk对象序列化-file.length:" + file.length());
        InputStream input = new FileInputStream(file);
        ObjectInputStream inputStream = new ObjectInputStream(input);
        Car deJdkCar = (Car) inputStream.readObject();
        System.out.println("jdk对象反序列化-类型:" + deJdkCar.getType() + ",价格:" + deJdkCar.getPrice());
        System.out.println("----------");
        /***** jdk end *****/

        /***** json begin *****/
        Car car = new Car("SUV", new BigDecimal("99999"));
        System.out.println("json原始对象-类型:" + car.getType() + ",价格:" + car.getPrice());
        String jsonCar = JSONObject.toJSONString(car);
        System.out.println("json对象序列化-对象:" + jsonCar);
        Car deJsonCar = JSON.parseObject(jsonCar, Car.class);
        System.out.println("json对象反序列化-类型:" + deJsonCar.getType() + ",价格:" + deJsonCar.getPrice());
        System.out.println("----------");
        /***** json end *****/

        /***** protobuf begin *****/
        UserProto.user user = UserProto.user.newBuilder().setAge(22).setName("张三").build();
        System.out.println("protobuf原始对象-姓名:" + user.getName() + ",年龄:" + user.getAge());
        byte[] protobufUser = user.toByteArray();
        System.out.println("protobuf对象序列化-对象:" + protobufUser + ",长度:" + protobufUser.length);
        UserProto.user deProtobufUser = UserProto.user.parseFrom(protobufUser);
        System.out.println("protobuf对象反序列化-姓名:" + deProtobufUser.getName() + ",年龄:" + deProtobufUser.getAge());
        /***** protobuf end *****/
    }

demo所需对象:

public class Car implements Serializable {
    private String type;
    private BigDecimal price;
    ...省略构造、get、set、toString
}

结果:
在这里插入图片描述

jdk序列化

  • 不支持跨语言平台调用, 性能较差(序列化后字节数组体积大)
  • 需要实现java.io.Serializable接口
  • serialVersionUID版本控制的作用
    1、序列化的时候serialVersionUID也会被写入二进制序列
    2、反序列化时会检查serialVersionUID是否和当前类的serialVersionUID一致。不一致则会抛出InvalidClassException 异常(序列化之后给类增加字段再反序列化的时候就会报错)

为什么需要serialVersionUID?

1、ObjectOutputStream下有个ObjectOutputStreamClass类
在这里插入图片描述在这里插入图片描述在这里插入图片描述所以:
• 序列化过程若不指定serialVersionUID, JDK会生成默认的serialVersionUID, 同时设置到类的描述符中;
• 在反序列化过程中, 读取到的序列化对象流会和最新的类的serialVersionUID对
比, 若不相等, 则抛出InvalidClassExceptions异常;
• 在JDK序列化过程中尽量对序列化对象设置固定的serialVersionUID;

protobuf使用

1、优缺点

• 出自Google, 纯粹的展示层协议, 性能优秀, 支持跨语言
• 文件定义起来比较繁琐
• 标准的IDL和IDL编译器, 这使得其对工程师非常友好。
• 序列化数据非常简洁, 紧凑, 与XML相比, 其序列化之后的数据量约为xml的1/3到1/10。
• 解析速度非常快, 比对应的XML快约20-100倍
• 提供了非常友好的动态库, 使用非常简单, 反序列化只需要一行代码。

2、使用步骤

https://github.com/protocolbuffers/protobuf/releases
1、下载最新的编译器
2、配置环境变量
3、引入pom

        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java</artifactId>
            <version>${protobuf.version}</version>
        </dependency>
        <dependency>
            <groupId>com.google.protobuf</groupId>
            <artifactId>protobuf-java-util</artifactId>
            <version>${protobuf.version}</version>
            <scope>runtime</scope>
        </dependency>

4、编写proto文件

// 声明语法,不显示声明默认是2.0的语法。
syntax = "proto3";
// 指定模板类的包路径
option java_package = "com.test.basic.java.serialize.proto.dto";
// 指定模板类的名称,名称必须是有实际业务意义的
option java_outer_classname = "UserProto";

// 定义用户对象
message User {
  // 名字
  string name = 1;
  // 年龄
  int32 age = 2;
}

4、protoc –java_out=输出目录 目标proto文件路径

protoc --java_out=src/main/java src/main/java/com/test/basic/java/serialize/proto/User.proto

5、如上demo

各种序列化性能比较

常见序列化

1、二进制序列化

• JDK自带的序列化
• Hessian
• Kyro
Protobuf
• Thrift

2、文本序列化(可读性好, 性能较差)

• JSON
• XML

性能对比

在这里插入图片描述

空间开销

在这里插入图片描述

选型建议

1、 对于公司间的系统调用, 如果性能要求在100ms以上的服务,基于XML的SOAP协议是一个值得考虑的方案。
2、 基于Web browser的Ajax, 以及Mobile app与服务端之间的通讯,JSON协议是首选。 性能要求不太高, 或以动态类型语言为主, 或传输数据量很小的的运用场景, JSON也是非常不错的选择。
3、 对于调试环境比较困难的场景, 采用JSON或XML能够极大的提高调试效率, 降低开发成本。
4、 对性能和简洁性有极高要求的场景, Protobuf, Thrift, Avro之间具有一定的竞争关系。
5、 对于T级别数据的持久化场景, Protobuf和Avro是首要选择。 如果持久化后的数据存储在Hadoop子项目里, Avro会是更好的选择。
6、 对于持久层非Hadoop项目, 以静态类型语言为主的应用场景,Protobuf会更符合静态类型语言工程师的开发习惯。
7、 如果序列化之后需要支持不同的传输层协议, 或者需要跨防火墙访问的高性能场景, Protobuf可以优先考虑。
8、 对于都是JVM的环境, 且性能要求很高可以考虑Kryo

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李_杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值