百度360必应搜狗淘宝本站头条
当前位置:网站首页 > 技术资源 > 正文

大厂面试系列-如何回答面试序列化和反序列化相关问题

lipiwang 2024-10-25 15:56 6 浏览 0 评论

什么是序列化与反序列化

在Java中所谓的序列化操作就是将Java中的对象以一连串的字节码保存到磁盘文件中的过程,也就是说可以是可以保存Java对象的某个状态。通常完成序列化的数据将在磁盘上永久进行保存。

而反序列化的操作就是将保存在磁盘上的Java字节码重新转换成Java对象的过程。

Java中如何实现序列化和反序列化操作

在Java中创建对象的方式有很多中,并且在学习垃圾回收机制的时候我们知道只要是没有被回收的对象我们都可以对该对象进行重复的利用。我们知道,在对象第一次被创建之后都是在Java堆内存中进行生成的,也就是说只有在JVM运行过程中,这些对象才是存在的,当JVM生命周期结束的时候,这些对象都将不复存在。

在一些实际开发过程中,我们需要将一些存在于JVM运行期间的对象永久的保存下来,这样方便在需要的时候把这些对象重新读取出来并且加载到JVM中运行使用。这个时候我们就需要采用序列化的方式对该对象进行持久化的存储。

对于对象的序列化操作,在Java中是提供了原生的支持,也就是说在Java语言内部就提供了关于序列化的有关操作。通过对象序列化的方式可以把对象的某个状态保存到字节数组中,在需要的时候将这些字节数组中的内容读取出来并使用。

这就涉及到了如何将字节数组中的对象内容与JVM中的活动对象进行转化的操作。

在很多RPC框架中就是通过序列化和反序列化的方式将对象通过网络以及其他传输方式进行一个远程调用RMI的操作。而这些操作无非就是利用了上面所说的要让JVM运行的对象进行持久化操作的想法。

JDK提供的序列化操作接口

在JDK中提供了相关的序列化的接口来实现对于Java对象的序列化存储的操作。

  • java.io.Serializable
  • java.io.Externalizable
  • ObjectOutput
  • ObjectInput
  • ObjectOutputStream
  • ObjectInputStream

下面我们就来依次介绍一下这些接口相关的内容。

Serializable

Serializable接口是Java提供用来标记使用序列化功能的接口,会看到这个接口没有任何的方法,也就是说它所完成的主要的功能就是用来标记某个类是否可以进行序列化操作,只有实现了这个接口的类才可以被序列化,而没有实现这个接口的类则不能进行序列化操作。如果一个类是可以被序列化的类,那么它的子类也将会变成可被序列化的类。

public interface Serializable {
}

如果在进行对象序列化的时候,对应的类不能被序列化的时候,这个时候就会抛出一个NotSerializableException异常。下面我们就来演示一个继承了Serializable接口实现的接口类的操作。

第一步、先来定一个继承了Serialzable接口的测试类

public class SerializableTest implements Serializable {
    private String id;
    private String name;
    private String param;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }
}

第二步、编写测试主类来测试相关内容

public class SerializableDemo1 {
    public static void main(String[] args) {
        //Initializes The Object
        SerializableTest serializableTest = new SerializableTest();
        serializableTest.setId("1231231");
        serializableTest.setName("Test");
        serializableTest.setParam("HelloWorld!");
        System.out.println(serializableTest);

        //Write Obj to File
        ObjectOutputStream oos = null;
        try {
            oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
            oos.writeObject(serializableTest);
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(oos);
        }

        //Read Obj from File
        File file = new File("tempFile");
        ObjectInputStream ois = null;
        try {
            ois = new ObjectInputStream(new FileInputStream(file));
            SerializableTest newObject = (SerializableTest) ois.readObject();
            System.out.println(newObject);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } finally {
            IOUtils.closeQuietly(ois);
            try {
                FileUtils.forceDelete(file);
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }
}

运行程序会看到在控制台有相关对象内容输出。到这里我们的序列化和反序列的操作就完成了,接下来我们来看一下关于Externalizable 接口的相关内容

Externalizable接口详解

Externalizable 是Java提供的另外一种序列化接口,其源码如下。会看到Externalizable接口也是继承了Serializable接口只不过在接口中提供了两个扩展方法。

public interface Externalizable extends java.io.Serializable {
    /**
     * The object implements the writeExternal method to save its contents
     * by calling the methods of DataOutput for its primitive values or
     * calling the writeObject method of ObjectOutput for objects, strings,
     * and arrays.
     *
     * @serialData Overriding methods should use this tag to describe
     *             the data layout of this Externalizable object.
     *             List the sequence of element types and, if possible,
     *             relate the element to a public/protected field and/or
     *             method of this Externalizable class.
     *
     * @param out the stream to write the object to
     * @exception IOException Includes any I/O exceptions that may occur
     */
    void writeExternal(ObjectOutput out) throws IOException;

    /**
     * The object implements the readExternal method to restore its
     * contents by calling the methods of DataInput for primitive
     * types and readObject for objects, strings and arrays.  The
     * readExternal method must read the values in the same sequence
     * and with the same types as were written by writeExternal.
     *
     * @param in the stream to read data from in order to restore the object
     * @exception IOException if I/O errors occur
     * @exception ClassNotFoundException If the class for an object being
     *              restored cannot be found.
     */
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

使用Externalizable 接口来进行序列化对象的时候,开发人员需要重写这两个方法,而这两个方法分别是读取了写入操作的扩展。

public class SerializableTest implements Externalizable {
    private String id;
    private String name;
    private String param;


    public String getId() {
        return id;
    }

    public void setId(String id) {
        this.id = id;
    }

    public String getName() {
        return name;
    }

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

    public String getParam() {
        return param;
    }

    public void setParam(String param) {
        this.param = param;
    }

    @Override
    public void writeExternal(ObjectOutput out) throws
    IOException {
        
    }

    @Override
    public void readExternal(ObjectInput in) throws 
                             IOException, ClassNotFoundException {

    }
}

实现对应操作内容,当然这里只是一个演示示例在实际开发过程中,要对流操作,对象存储操作等做好合理的安排。

public class ExternalizableDemo1 {
    
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        //Write Obj to file
        ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("tempFile"));
        SerializableTest serializableTest = new SerializableTest();
        serializableTest.setId("1231231");
        serializableTest.setName("Test");
        serializableTest.setParam("HelloWorld!");
        oos.writeObject(serializableTest);
        //Read Obj from file
        File file = new File("tempFile");
        ObjectInputStream ois =  new ObjectInputStream(new FileInputStream(file));
        SerializableTest newInstance = (SerializableTest) ois.readObject();
        //output
        System.out.println(newInstance);
    }
}

执行完上面的操作之后,会看到输出结果中并没有将我们设置的属性值进行存储,那是因为,在使用Externalizable进行序列化的时候,在读取对象时,会调用被序列化类的无参构造器去创建一个新的对象,然后再将被保存对象的字段的值分别填充到新对象中。所以,实现Externalizable接口的类必须要提供一个public的无参的构造器。并且必须要实现writeExternal和readExternal方法。如下,我们可以再次运行代码就会看到属性值也会被保存下来。

public void writeExternal(ObjectOutput out) throws IOException {
    out.writeObject(name);
    out.writeInt(age);
}

public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
    name = (String) in.readObject();
    age = in.readInt();
}

Serializable 和 Externalizable 有什么不同

通过查看源码我们知道其实Externalizable接口也是继承了Serializable接口来实现序列化操作,而前面内容中我们也介绍了Serializable接口实际上就是用来标记这个类是否可以被序列化或者是反序列化。

而Externalizable在继承了Serializable接口的基础上又定义了两个方法writeExternal和readExternal,当我们继承Externalizable接口进行序列化的时候,我们需要重新编写这两个方法中的内容,否则就会的到一个空对象。而在Externalizable接口的时候需要序列化的对象又必须去提供一个无参构造。并且在writeExternal和readExternal方法中对指定的属性进行序列化指定。

总结

整个的Java序列化的过程其实是为我们提供了一种新的Java扩展机制,是为了更好的整合各种资源使得开发效率得到更好的提升。并且现在的很多框架中对序列化和反序列化的使用也是非常广泛的。同时开发人员还定义了自己的序列化和反序列化的规则。极大的提升了代码安全以及开发效率。

相关推荐

前端 JavaScript 字符串中提取数字

varstr="4500元";varnum=parseInt(str);alert(num);//4500如果字符串前面有非数字字符,上面这种方法就不行了:var...

使用JavaScript如何获取网站网址(js如何获取浏览器信息)

在做网站开发时,我们有时候会获取当前页面的完整路径。在网页前端如何实现呢?请在网页脚本代码段中粘贴如下代码。functiongetRootPath(){//获取当前网址,...

java文本对比工具源码8(java比较文本相似度)

/***ParseatextualrepresentationofpatchesandreturnaListofPatch*objects.*@paramtextline...

JavaScript实现的9大排序算法(js排序方法)

笔试面试经常涉及各种算法,本文简要介绍常用的一些算法,并用JavaScript实现。1、插入排序1)算法简介插入排序(Insertion-Sort)的算法描述是一种简单直观的排序算法。它的工作原理是通...

使用函数化的Javascript代码编写方式

对于Javascript介绍想必大家都耳熟能详啦,基于函数化的编程语言,基于浏览器运行的编程语言,web开发语言,前端开发必备语言,blablabla...Javascript是一个非常灵...

Js基础31:内置对象(js内置对象是什么意思)

js里面的对象分成三大类:内置对象ArrayDateMath宿主对象浏览器提供的对象(如bom、dom等等)自定义对象开发人员自己定义的对象内置对象——所谓内置对象,就是JavaScript自...

js获取上传文件类型以及大小的方法

前端web上传文件时,需要在上传之前判断一下文件的类型以及文件的大小,HTML为前端的标记语言是无法做到这一点,只能使用javascript动态脚本代码来实现。js获取上传文件大小的方法示例代码:&...

黑客入门实践:如何绕过前端过滤上传文件

今天开始,我们就要开始学习具体的漏洞了,但是希望大家学完后,不要轻易"入侵"网站哦,当时测试环境下除外。今天的课程是关于“文件上传漏洞”,据安界网的老师介绍,文件上传漏洞仅次于命令执行...

Java文件上传细讲(java文件夹上传)

什么是文件上传?文件上传就是把用户的信息保存起来。为什么需要文件上传?在用户注册的时候,可能需要用户提交照片。那么这张照片就应该要进行保存。免费学习资料获取方式上传组件(工具)为什么我们要使用上传工具...

鸿蒙上实现“翻译”功能(鸿蒙宴全文翻译)

本章节我们来制作中文翻译成英文的实例(运行在HarmonyOS上),通过HTTP去配合API进行实现。需求分析如下:文字输入HTTP协议使用文字翻译控件介绍①HTTP数据请求官方文档请求...

JavaScript从入门到精通(javascript 入门教程)

前几天,我们学习了JavaScript的入门课程,但是要想做网站,仅仅学会入门是不够的,今后的几天,我将带领大家精通JavaScript,希望大家好好学习!JS内置对象String对象:字符串对象,提...

第15天|16天搞定前端,javascript语法篇(干货)

JavaScript是互联网上最流行的脚本语言,这门语言可用于HTML和web,可广泛用于服务器、PC、笔记本电脑、平板电脑和智能手机等设备。它是一个脚本语言,它是一个轻量级,但功能强大的编程...

通过js来实现打字效果(js如何输入)

有时候浏览网页经常会看见一些页面出现一些打字的效果,那么是怎么实现的呢?逻辑确定目标容器,在哪个容器进行输出确定输出内容,当前直接根据目标容器确定输出内容即可需要控制输出频率,因此需要循环输出完毕代码...

手把手教你学会一键还原混淆js原理

1.短变量名在以下示例代码中,我们将变量“customerName”替换为“a”:vara="JohnSmith";console.log(a);2.随机变量名在以下示例代码...

sql中常用的字符串函数详解(sql字符串函数有哪些)

在日常开发中遇到处理最多的可能字符串要算其中一个了,什么替换啊截取啊大小写转换啊、删除空格啊等等,这些操作我们可以在前端操作,也可以直接在数据库的sql中操作,那么我们来看一下sql中处理字符串的...

取消回复欢迎 发表评论: