面试问你java中的序列化怎么答?

记得好久之前写代码的时候,每次新建一个实体都会下意识的继承Serializable接口,大部分人都知道这是对对象的序列化,但是大家真的知道序列化吗?这篇文章就简单的说下java中的序列化,让你更多的理解java这门语言。前端

关于上篇文章说的,在应用登陆前使用第三方的人机验证,若是第三方的产品忽然出现故障,没法使用,这种情况咱们应该怎么应对,在团队中咱们也讨论过这种状况,咱们的方案就是客户端不直接的请求第三方,而是由后端服务器充当一个中介的角色,起转发做用,这样在第三方出现问题,咱们服务器端会作处理,这也是不把鸡蛋放在同一个篮子里的思想。java

接下来,简单的说下序列化,json

将数据对象转换为二进制流的过程就称为对象的序列化(Serialization),反过来,将二进制流转换为对象就是反序列化(Deserializable)。序列化的用处是什么呢?共两点:后端

一、数据持久化:在不少应用中,须要对好多对象进行序列化,存到物理硬盘,较长时间的保存,好比,Session对象,当有数万用户并发访问的时候,就会有数万的Session对象,内存会承受很大的压力,这个时候,就会把一些对象先序列化到硬盘中,须要使用的时候再还原到内存中。序列化对象要保留充分的信息,用来恢复数据对象,可是为了节约存储空间和网络带宽,序列化出的二进制流要尽量小。安全

二、网络传输:当两个进程在互相通讯的时候,就会进行数据传输,不论是何种类型的数据,都必需要转成二进制流来传输,接受方收到后再转为数据对象。bash

重点来了,序列化在代码中是怎么实现的呢?如下介绍三种:服务器

一、java原生序列化:java类经过实现Serializable接口来实现。这个接口没有任何方法,只是标识,java序列化保留了对象的元数据,以及对象数据,兼容性最好,可是不支持跨语言,性能也通常。网络

public class BaseEntity implements Serializable {
    private static final long serialVersionUID = -7333816285916354999L;
    private Long id;
    public BaseEntity() {
    }
    public Long getId() {
        return this.id;
    }
    public void setId(Long id) {
        this.id = id;
    }
}
复制代码

实现这个接口,idea会给你一个警告,它会建议你设置一个serialVersionUID,若是你不设置,编译器会根据类的内部实现,包括类名、接口名、方法和属性来自动生成serialVersionUID 若是类的源码有修改,从新编译后这个值也会变化。架构

在修改类的时候,咱们要根据兼容性来决定是否修改serialVersionUID,若是是兼容性质的升级,不建议修改,由于可能会反序列化失败。若是是不兼容的,就须要修改,避免反序列化变得混乱。并发

java原生序列化,在反序列化的时候不会调用类的无参构造方法,而是调用native方法将属性赋值为对应类型的初始值。

最后,基于性能及兼容性,不推荐使用。

二、Hessian序列化:Hessian序列化是一种支持动态类型、跨语言、基于对象传输的网络协议,java对象序列化后的二进制流,能够被其余语言反序列化。它的特性:

自描述序列化类型,不依赖外部描述文件或接口定义,用一个字节表示经常使用的基础类型,极大缩短二进制流;

语言无关,支持脚本语言。

协议简单,比java原生的要高效。

须要注意一点:Hessian会把复杂对象全部属性存储在一个Map中进行序列化,因此在父类和子类含有相同字段的状况下,先序列化子类,后序列化父类,这样的结果是子类的同名属性会被父类覆盖掉。

如下是代码实现

/**
     * Hessian实现序列化
     *
     * @param TestClass
     * @return
     * @throws IOException
     */
    private static byte[] serialize(TestClass TestClass) {
        ByteArrayOutputStream byteArrayOutputStream = null;
        HessianOutput hessianOutput = null;
        try {
            byteArrayOutputStream = new ByteArrayOutputStream();
            // Hessian的序列化
            hessianOutput = new HessianOutput(byteArrayOutputStream);
            hessianOutput.writeObject(TestClass);
            return byteArrayOutputStream.toByteArray();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try {
                byteArrayOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
            try {
                hessianOutput.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    }
复制代码

三、JSON序列化:

JSON是一种轻量级的数据交换格式,这种序列化方式就是讲数据对象转换为JSON字符串。在序列化的过程当中舍弃了类型信息。反序列化是只有在提供了类型信息的状况下才能完成。

public static <T> T fromJson(String json, Class<T> type) {
        if (json != null && !json.equals("")) {
            try {
                return getObjectMapper().readValue(json, type);
            } catch (Exception var3) {
                var3.printStackTrace();
                return null;
            }
        } else {
            return null;
        }
    }
复制代码

相信大部分读者的公司和前端和客户端数据的交互格式都是JSON吧,由于JSON的这种格式可读性较好,并且也方便调试。

序列化一般会用于网络传输数据对象,而对象中经常会含有敏感数据,因此黑客经常会攻击这点,攻击手段一般是利用反序列化过程构造恶意代码,怎么应对这种状况呢?可使用transient关键字来修饰这个属性,这样在反序列化以后该属性就会为空,若是必定要传递的话,可使用对称加密或非对称加密独立传输,在数据传输的问题上,咱们必定要具有安全意识。

但愿看完这篇文章的你能有所收获。

分享如下本身的思考:“对于用户来讲,系统太灵活是他们的负担,意味着他们要作更多的选择,对于技术人员来讲,架构灵活能够应对更多的运营策略。怎样折中,是个问题。”

这样的分享我会一直持续,你的关注、转发和点赞是对我最大的支持,感谢。

关注公众号,最新文章会出如今那里哦

相关文章
相关标签/搜索