概念
序列化
将对象转换为字节序列的过程叫做对象的序列化。
对象在jvm
运行的时候是存在的,但是一旦jvm
运行结束之后,对象也会随之消失,那么如果我们不想让这个对象消失,那么就可以将它以字节描述的形式保存下来,这个转换的过程就叫做序列化。
反序列化
将字节序列恢复为对象的过程叫做对象的反序列化。
假如我们想在运行的时候使用已经保存好的对象,那么这个从字节描述转换为对象的过程就叫做反序列化。
用途
对象的序列化操作的主要用途有两种:
- 将对象序列化后永久地保存到硬盘上,比如保存到数据库或是保存为文件;
- 将对象序列化后用于网络传输。
实现方式
接口
在Java
中,要使一个类可以被序列化/反序列化,共有两种序列化接口可以选择:
Serializable
接口;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
类:
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
关键字。