为什么不建议使用 Java 自带的序列化?

点击关注公众号,Java干货及时送达

作者:rickiyang
出处:www.cnblogs.com/rickiyang/p/11074232.html

谈到序列化我们自然想到 Java 提供的 Serializable 接口,在 Java 中我们如果需要序列化只需要继承该接口就可以通过输入输出流进行序列化和反序列化。

但是在提供很用户简单的调用的同时他也存在很多问题:

1、无法跨语言

当我们进行跨应用之间的服务调用的时候如果另外一个应用使用c语言来开发,这个时候我们发送过去的序列化对象,别人是无法进行反序列化的因为其内部实现对于别人来说完全就是黑盒。

2、序列化之后的码流太大

这个我们可以做一个实验还是上一节中的Message类,我们分别用java的序列化和使用二进制编码来做一个对比,下面我写了一个测试类:

@Test
public void testSerializable(){
    String str = "哈哈,我是一条消息";
    Message msg = new Message((byte)0xAD,35,str);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        ObjectOutputStream os = new ObjectOutputStream(out);
        os.writeObject(msg);
        os.flush();
        byte[] b = out.toByteArray();
        System.out.println("jdk序列化后的长度: "+b.length);
        os.close();
        out.close();


        ByteBuffer buffer = ByteBuffer.allocate(1024);
        byte[] bt = msg.getMsgBody().getBytes();
        buffer.put(msg.getType());
        buffer.putInt(msg.getLength());
        buffer.put(bt);
        buffer.flip();

        byte[] result = new byte[buffer.remaining()];
        buffer.get(result);
        System.out.println("使用二进制序列化的长度:"+result.length);

    } catch (IOException e) {
        e.printStackTrace();
    }
}

输出结果为:

我们可以看到差距是挺大的,目前的主流编解码框架序列化之后的码流也都比java序列化要小太多。Java 核心技术系列教程和示例整理好了:https://github.com/javastacks/javastack

3、序列化效率

这个我们也可以做一个对比,还是上面写的测试代码我们循环跑100000次对比一下时间:

@Test
public void testSerializable(){
    String str = "哈哈,我是一条消息";
    Message msg = new Message((byte)0xAD,35,str);
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    try {
        long startTime = System.currentTimeMillis();
        for(int i = 0;i < 100000;i++){
            ObjectOutputStream os = new ObjectOutputStream(out);
            os.writeObject(msg);
            os.flush();
            byte[] b = out.toByteArray();
            /*System.out.println("jdk序列化后的长度: "+b.length);*/
            os.close();
            out.close();
        }
        long endTime = System.currentTimeMillis();
        System.out.println("jdk序列化100000次耗时:" +(endTime - startTime));

        long startTime1 = System.currentTimeMillis();
        for(int i = 0;i < 100000;i++){
            ByteBuffer buffer = ByteBuffer.allocate(1024);
            byte[] bt = msg.getMsgBody().getBytes();
            buffer.put(msg.getType());
            buffer.putInt(msg.getLength());
            buffer.put(bt);
            buffer.flip();

            byte[] result = new byte[buffer.remaining()];
            buffer.get(result);
            /*System.out.println("使用二进制序列化的长度:"+result.length);*/
        }
        long endTime1 = System.currentTimeMillis();
        System.out.println("使用二进制序列化100000次耗时:" +(endTime1 - startTime1));

    } catch (IOException e) {
        e.printStackTrace();
    }
}

结果为:

结果为毫秒数,这个差距也是不小的。另外,关注公众号Java技术栈,在后台回复:面试,可以获取我整理的 Java 系列面试题和答案,非常齐全。

结合以上我们看到:

目前的序列化过程中使用 Java 本身的肯定是不行,使用二进制编码的话又的我们自己去手写,所以为了让我们少搬砖前辈们早已经写好了工具让我们调用,目前社区比较活跃的有 google 的 Protobuf 和 Apache 的 Thrift。



关注Java技术栈看更多干货

获取 Spring Boot 实战笔记!

Java中,Protocol Buffer(protobuf)在处理数据序列化与反序列化时表现优异,特别是在性能和数据大小方面。对于性能对比,我们可以参考《Protocol Buffer与Java序列化性能对比》这份资料,它详细分析了protobufJava序列化的性能差异。 参考资源链接:[Protocol Buffer与Java序列化性能对比](https://wenku.csdn.net/doc/6a9sgqz80h) Protobuf通过定义.proto文件来描述数据结构,然后使用protoc编译器生成特定编程语言的源代码。这个过程中生成的类提供了高效的序列化和反序列化方法,这些方法在内部使用了二进制编码,这种编码方式比起Java自带序列化机制更加紧凑和高效。因此,使用protobuf序列化的数据通常比使用Java序列化的数据要小,这直接降低了网络传输的负担,并减少了存储需求。 此外,protobuf序列化和反序列化过程非常迅速,特别适合处理大量数据,如在网络通信或者大规模数据存储系统中。这种高效率是由于protobuf的编码和解码过程被优化过,能够更快地处理字节流。 跨平台和跨语言的兼容性是protobuf的另一个显著优势。开发者可以在多种语言间共享.proto文件,生成对应语言的数据交换格式。而Java序列化虽然能够处理多种数据类型,并且操作简便,但它生成的序列化数据是特定于Java的,难以与其他语言直接兼容。 在安全性方面,Java序列化由于其复杂性和对反射的使用,更容易受到安全威胁,如反序列化攻击。而protobuf由于其简洁的二进制格式和明确的数据协议,通常被认为更加安全。 综上所述,protobuf在性能、数据大小、跨平台兼容性以及安全性方面相较于Java自带序列化机制有着明显的优势。在选择序列化框架时,如果项目对性能有较高要求,那么protobuf是一个值得考虑的选项。对于那些对兼容性和易用性有更高需求的内部系统,Java自带序列化机制可能更适合。 参考资源链接:[Protocol Buffer与Java序列化性能对比](https://wenku.csdn.net/doc/6a9sgqz80h)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值