首页 > 编程语言 >每日一道面试题:Java中序列化与反序列化

每日一道面试题:Java中序列化与反序列化

时间:2024-01-28 21:44:07浏览次数:30  
标签:面试题 Java name age new 序列化 public String

写在开头

哈喽大家好,在高铁上码字的感觉是真不爽啊,小桌板又拥挤,旁边的小朋友也比较的吵闹,影响思绪,但这丝毫不影响咱学习的劲头!哈哈哈,在这喧哗的车厢中,思考着这样的一个问题,Java中的对象是如何在各个方法,或者网络中流转的呢?
通过这个问题便引出了我们今天的主人公:序列化与反序列化

序列化:所谓的序列化就是将Java对象或数据结构转为字节序列的过程,以便于存储到数据库、内存、文件系统或者网络传输。
反序列化:而反序列化就是序列化的逆向操作将字节流转为Java对象的过程。

序列化的基本实现(JDK)

这样一看序列化是不是非常有用?毋容置疑,这是一个无形中都会用到的知识点!那么想要在Java中实现序列化该如何做呢?继续往下看。
其实只要做到2点,就可以实现基本的序列化功能:序列流(ObjectInputStream 和 ObjectOutputStream)、实现了 Serializable 接口(一个标识型接口,没有具体的方法,仅是一种通知,告诉JVM这个对象需要序列化)

【示例代码】

/**
 * 测试序列化,反序列化
 * @author ConstXiong
 * @date 2019-06-17 09:31:22
 */
public class TestSerializable implements Serializable {
 
    private static final long serialVersionUID = 5887391604554532906L;
    
    private int id;
    
    private String name;
 
    public TestSerializable(int id, String name) {
        this.id = id;
        this.name = name;
    }
    
    @Override
    public String toString() {
        return "TestSerializable [id=" + id + ", name=" + name + "]";
    }
 
    @SuppressWarnings("resource")
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //序列化
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("TestSerializable.obj"));
        oos.writeObject("测试序列化");
        oos.writeObject(618);
        TestSerializable test = new TestSerializable(1, "JavaBuild");
        oos.writeObject(test);
        
        //反序列化
        ObjectInputStream ois = new ObjectInputStream(new FileInputStream("TestSerializable.obj"));
        System.out.println((String)ois.readObject());
        System.out.println((Integer)ois.readObject());
        System.out.println((TestSerializable)ois.readObject());
    }
}

输出:

测试序列化
618
TestSerializable [id=1, name=JavaBuild]

这种实现方式是JDK自带的,方便好用,易于实现,代码逻辑不复杂,但它有着诸多的致命缺陷,导致很多大厂不会使用这种方式。

1、不支持跨语言调用 : 如果调用的是其他语言开发的服务的时候就不支持了。
2、性能差:相比于其他序列化框架性能更低,主要原因是序列化之后的字节数组体积较大,导致传输成本加大。
3、存在安全问题:序列化和反序列化本身并不存在问题。但当输入的反序列化的数据可被用户控制,那么攻击者即可通过构造恶意输入,让反序列化产生非预期的对象,在此过程中执行构造的任意代码。

序列化的其他实现方式(Kryo)

除了JDK自带的实现方式,国内外的大厂们推出过不好的开源且好用的序列化协议,比如Hessian、Kryo、Protobuf、ProtoStuff。

Hessian
一个轻量级的,自定义描述的二进制 RPC 协议。Hessian 是一个比较老的序列化实现了,并且同样也是跨语言的。Dubbo2.x 默认启用的序列化方式是 Hessian2 ,但是,Dubbo 对 Hessian2 进行了修改,不过大体结构差别不大。

Protobuf
自于 Google,性能优秀,支持多种语言,同时还是跨平台的。就是在使用中过于繁琐,因为你需要自己定义 IDL 文件和生成对应的序列化代码。这样虽然不灵活,但是,另一方面导致 protobuf 没有序列化漏洞的风险。不过后续谷歌推出了升级版,进行了很多缺陷的优化,诞生了ProtoStuff。

Kryo

目前使用最广泛,好评诸多的就是具有高性能、高效率和易于使用和扩展等特点的Kryo, 目前像Twitter、Groupon、Yahoo 以及多个著名开源项目(如 Hive、Storm)中都在使用这款序列化工具。
【示例代码】
1、引入相应的pom依赖库

<!-- 引入 Kryo 序列化工具 -->
<dependency>
     <groupId>com.esotericsoftware</groupId>
     <artifactId>kryo</artifactId>
     <version>5.4.0</version>
</dependency>

2、通过调用方法,通过二进制实现序列化与反序列化

public class KryoDemo {
    public static void main(String[] args) throws FileNotFoundException {
        Kryo kryo = new Kryo();
        kryo.register(KryoParam.class);

        KryoParam object = new KryoParam("JavaBuild", 123);

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

        Input input = new Input(new FileInputStream("logs/kryo.bin"));
        KryoParam object2 = kryo.readObject(input, KryoParam.class);
        System.out.println(object2);
        input.close();
    }
}

class KryoParam {
    private String name;
    private int age;

    public KryoParam() {
    }

    public KryoParam(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    @Override
    public String toString() {
        return "KryoParam{" +
                "name='" + name + '\'' +
                ", age=" + age +
                '}';
    }
}

序列化的细节知识点!

1、一般实现序列化接口后,还会有个serialVersionUID,它有什么作用?

答:SerialVersionUid 是为了序列化对象版本控制,告诉 JVM 各版本反序列化时是否兼容
如果在新版本中这个值修改了,新版本就不兼容旧版本,反序列化时会抛出InvalidClassException异常
仅增加了一个属性,希望向下兼容,老版本的数据都保留,就不用修改 删除了一个属性,或更改了类的继承关系,就不能不兼容旧数据,这时应该手动更新
SerialVersionUid

2、如果有些字段不想进行序列化怎么办?

答:对于不想进行序列化的变量,可以使用 transient 关键字修饰。transient
关键字的作用是:阻止实例中那些用此关键字修饰的的变量序列化;当对象被反序列化时,被 transient 修饰的变量值不会被持久化和恢复。

标签:面试题,Java,name,age,new,序列化,public,String
From: https://www.cnblogs.com/JavaBuild/p/17993444

相关文章

  • IBM java的分析工具(ga和ha)学习和整理
    IBMjava的分析工具(ga和ha)学习和整理背景前几天学习了整理了jca工具今天继续学习一下ga工具ga工具主要是分析gclog相关.可以很直观的进行gclog的分析和展示.除了mat之外还有一个比较轻量级的内存dump分析工具ha.想着一起学习和分析一下.ga工具的相关学习下载:https......
  • C#对象二进制序列化优化:位域技术实现极限压缩
    目录1.引言2.优化过程2.1.进程对象定义与初步分析2.2.排除Json序列化2.3.使用BinaryWriter进行二进制序列化2.4.数据类型调整2.5.再次数据类型调整与位域优化3.优化效果与总结1.引言在操作系统中,进程信息对于系统监控和性能分析至关重要。假设我们需要开发一个监控程序,该......
  • git笔试面试题
     收集整理几个git相关的笔试面试题 1、你们公司版本是如何管理的?细说一下 2、如何创建分支? 3、gitclone、gitpull、gitfetch、gitpush的区别是? 4、merge和rebase的区别是? 5、gitpull和gitpull--rebase的区别是? 6、代码提交到本地仓库后,发现提交日志写错了,如何修改? ......
  • 用Java语言实现一个观察者模式
    观察者模式(也被称为发布/订阅模式),提供了避免组件之间紧密耦合的另一种方法,它将观察者和被观察的对象分开。在该模式中,一个对象通过添加一个方法(该方法允许另一个对象,即观察者注册自己)使本身变得可观察。当可观察的对象更改时,它会将消息发送到已注册的观察者。这些观察者收到消......
  • 深入了解Java中的ArrayList
    Java中的ArrayList是一个常用的动态数组类,它提供了便捷的操作方法和灵活的大小调整能力。在本篇博客中,我们将深入了解ArrayList的特性、常见用法和一些注意事项。ArrayList概述:ArrayList是Java集合框架中的一个类,它实现了List接口,并继承了AbstractList类。它基于数组实现,可以动......
  • JS 面试题: 将class转为function
     关于类-需知知识点:1、ES6提供了更接近传统语言的写法,引入了Class(类)这个概念,作为对象的模板。通过class关键字,可以定义类基本上,ES6的class可以看作只是一个语法糖,它的绝大部分功能,ES5都可以做到,新的class写法只是让对象原型的写法更加清晰、更像面向对象编程的语......
  • [职场] 面试题:Java语言技术的应用有哪些?
    小伙伴们面试时,特别是和代码相关的岗位,面试时可能会遇见关于Java语言技术的应用这个问题,那么我们应该如何作答呢?一起来看看答案吧!答案:1、Android,应用许多的Android,应用都是Java程序员开发者开发。虽然Androidi运用了不同的JVMl以及不同的封装方式,但是代码还是用Java语言所编写。......
  • JavaScript 实现点击爱心效果
    可放在网页任何位置,以下是代码:<script>(function(e,t){functionr(){s=s.filter((e)=>{e.alpha<=0?(t.body.removeChild(e.el),e=null):(e.y--,e.scale+=.004,e.alpha-=.013,e.el.style.cssText=`left:${e.x}px;top:${e.y}px;opac......
  • JavaScript 实现浏览器级别的弹窗提示
    可放在网页任何位置,以下是代码:1.每次打开都会弹出提示<script>//在页面加载时触发警告框window.onload=function(){alert('这是浏览器级别的弹窗提示!');};</script> 2.打开只弹出一次,刷新网页不会弹出,清理浏览器缓存会再次弹出<script>/......
  • Java常见容器类总结,实际应用场景归纳
    前言大家好,我是chowley,今天来总结一下Java中的常见容器类,和他们对应的使用场景。在Java中,容器类是一组用于存储和操作对象的类库,它们有着了不同的数据结构和实现原理,以满足开发过程中各种需求。本文将总结Java中常见的容器类,并通过实际应用场景进行归纳,帮助大家更好地理解和选择......