zoukankan      html  css  js  c++  java
  • 一文读懂 Java 序列化与反序列化

    序列化与反序列化

    Java 将创建出来的对象,存放在 JVM 的对内存中,只有在 JVM 运行的时候,这些对象才会存在,一旦 JVM 停止运行,这些对象的状态也就随之消失了。

    但是在一些应用场景中,我们需要将这些对象进行持久化,并且需要在使用的时候能够重新读取对象信息,比如说在 RPC 调用的时候,需要将对象通过网络进行传输,此时就需要下将对象记性序列化进行传输,再将其反序列化进行处理。

    序列化(Serialization)是指将对象的状态信息,转换成可以可以存储或传输的形式。在网络传输过程中,可以是字节或是XML等格式。

    • 序列化:Java对象转换为字节序列。
    • 反序列化:字节序列恢复为原先的Java对象。

    Java 提供了一种对象序列化的机制。用一个字节序列可以表示一个对象,该字节序列包含该对象的数据、对象的类型和对象中存储的属性等信息。字节序列写出到文件之后,相当于文件中持久保存了一个对象的信息。
    反之,该字节序列还可以从文件中读取回来,重构对象,对它进行反序列化。对象的数据、对象的类型和对象中存储的数据信息,都可以用来在内存中创建对象。

    Java提供了下面这些类来进行序列化和反序列化

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

    Serializable 接口

    java.io.Serializable 是一个没有任何方法或者字段的接口类,仅用于标识这个类可以被序列化。如果要序列化的类有父类,要想同时将在父类中定义过的变量持久化下来,那么父类也应该集成 java.io.Serializable 接口。

    Java在进行序列化之前,会检查类是否实现了Serializable接口,没有实现就会报Serializable 接口就会报 NotSerializableException 异常。

    往序列化的方法底层看到 java.io.ObjectOutputStream#writeObject0 接口,它对被序列化对象的类型进行了判断,不是字符串、数组、枚举,也没有实现 Serializable 的接口都会抛出 NotSerializableException 异常。

    Externalizable 接口

    Externalizable继承了Serializable,该接口中定义了两个抽象方法:writeExternal()readExternal()。当使用Externalizable接口来进行序列化与反序列化的时候需要开发人员重写writeExternal()readExternal()方法。

    serialVersionUID 的作用

    反序列化的时候可能遇到 InvalidClassException 异常,说是序列化的时候字节码文件的 serialVersionUID 和本地类的 serialVersionUID 不一致。这是由于反序列化的时候对类进行了修改,比如加上一个 toString 方法打印对象信息。

    使用 ObjectOutputStream、ObjectInputStream 进行序列化

    public void serialize() {
        User user = new User("深页", 18, "杭州");
        try (
                ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("user.txt"));
        ) {
            oos.writeObject(user);
            System.out.println("Serialized data is saved");
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    
    public void deserialize() {
        try (
                ObjectInputStream ois = new ObjectInputStream(new FileInputStream("user.txt"));
        ) {
            User user = (User) ois.readObject();
            System.out.println(user);
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
    

    static、transient 修饰不想被序列化的变量

    被 static 和 transient 修饰的字段是不会被序列化的:

    • 序列化保存的是对象的状态而非类的状态,所以会忽略 static 静态域;
    • 序列化某个类的对象时,不希望某个字段被序列化,可以用 transient 修饰变量
  • 相关阅读:
    关于JavaScript文档对象
    关于JavaScript浏览器对象
    关于JavaScript事件与函数
    关于JavaScript基础知识
    关于CSS基础知识
    第七章:Hexadecimal, octal, ASCII, UTF8, Unicode, Runes
    没有 Cgroups,就没有 Docker
    Redis 文件事件
    Python 垃圾回收总结
    Docker Bridge 网络原理
  • 原文地址:https://www.cnblogs.com/shuiyj/p/13161177.html
Copyright © 2011-2022 走看看