【Java】序列化与反序列化

概念


序列化

对象转换为字节序列的过程叫做对象的序列化

对象在jvm运行的时候是存在的,但是一旦jvm运行结束之后,对象也会随之消失,那么如果我们不想让这个对象消失,那么就可以将它以字节描述的形式保存下来,这个转换的过程就叫做序列化

反序列化

字节序列恢复为对象的过程叫做对象的反序列化

假如我们想在运行的时候使用已经保存好的对象,那么这个从字节描述转换为对象的过程就叫做反序列化

用途


对象的序列化操作的主要用途有两种:

  1. 将对象序列化后永久地保存到硬盘上,比如保存到数据库或是保存为文件;
  2. 将对象序列化后用于网络传输

实现方式


接口

Java中,要使一个类可以被序列化/反序列化,共有两种序列化接口可以选择:

  1. Serializable接口;
  2. Externalizable接口。

Serializable接口是一个空接口,它的作用是声明当前类可以被序列化和反序列化,序列化操作与反序列化操作使用的是默认规则

/*
 * Copyright (c) 1996, 2013, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 */

package java.io;

public interface Serializable {
}

Externalizable接口继承自Serializable接口,包括了两个未实现的方法,用于自定义序列化操作时的规则和反序列化操作时的规则。

/*
 * Copyright (c) 1996, 2004, Oracle and/or its affiliates. All rights reserved.
 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
 */

package java.io;

import java.io.ObjectOutput;
import java.io.ObjectInput;

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;
}

I/O流类型

序列化对象时我们使用的I/O流类型为ObjectOutputStream类。

反序列化对象操作时我们使用的I/O流类型为ObjectInputStream类。

例子

定义一个对象类Ving类:

扫描二维码关注公众号,回复: 186067 查看本文章
package com.vingyun;

import java.io.Serializable;

public class Ving implements Serializable {
    /**
     * serialVersionUID 序列化与反序列化过程中的类信息校验
     */
    private static final long serialVersionUID = 1925138888826980930L;
    private String nickName;
    private int age;

    public String getNickName() {
        return nickName;
    }
    public void setNickName(String nickName) {
        this.nickName = nickName;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
}
package com.vingyun;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializeTest {

    public static void main(String[] args) throws FileNotFoundException, IOException, ClassNotFoundException {
        // TODO 自动生成的方法存根
        Ving vingSerialize = new Ving();
        vingSerialize.setNickName("MasterVing");
        vingSerialize.setAge(99);
        serializeVing(vingSerialize);

        Ving vingDeserialize = null;
        vingDeserialize = deserializeVing(vingDeserialize);
        System.out.println("NickName: " + vingDeserialize.getNickName() + "\nAge: " + vingDeserialize.getAge());

    }

    public static void serializeVing(Ving vingSerialize) throws FileNotFoundException, IOException {
        ObjectOutputStream obOStream = new ObjectOutputStream(new FileOutputStream("E:/vingInfo.txt"));
        obOStream.writeObject(vingSerialize);
        obOStream.close();
        System.out.println("序列化对象操作完成。\n");
    }

    public static Ving deserializeVing(Ving vingDeserialize) throws FileNotFoundException, IOException, ClassNotFoundException {
        ObjectInputStream obIStream = new ObjectInputStream(new FileInputStream("E:/vingInfo.txt"));
        vingDeserialize = (Ving) obIStream.readObject();
        obIStream.close();
        System.out.println("反序列化对象操作完成。\n");
        return vingDeserialize;
    }
}

这里写图片描述

相关属性


serialVersionUID

长整型属性serialVersionUID用于序列化与反序列化过程中的类信息校验,如果此属性的值在序列化之后发生了变化,那么已经序列化的文件就不能再反序列化,会抛出InvalidClassException异常。因此,在自定义的可序列化类中虽然不是必须的,但是不同的JVM默认生成的serialVersionUID不一定是完全相同的,因此建议应当显式地声明这个属性,并且用private static final修饰此属性。

serialPersistentFields

ObjectStreamField类型数组serialPersistentFields定义需要被自动序列化的字段,而且一旦定义了这个属性,那么就不会识别原本默认的可序列化字段,例如非static和非transitent字段。

serialPersistentFields属性需要用private static final修饰。

在本文的例子中,没有使用到serialPersistentFields属性。

相关关键字


transitent

关键字transitent用于将属性修饰为不被默认序列化

如果在transient关键字的同时定义了serialPersistentFields属性,那么transient关键字会被忽略,并且只有serialPersistentFields属性包含的字段才会被序列化。

在本文的例子中,没有使用到transitent关键字。

猜你喜欢

转载自blog.csdn.net/Ving_SuiXin/article/details/80223847