<font color="#FF0000">based on jdk 8!</font>java
Introduction
ObjectInputStream 和 ObjectOutputStream 的做用是,对基本数据和对象进行序列化操做支持。
Serialization(序列化)是一种将对象以一连串的字节描述的过程;反序列化deserialization是一种将这些字节重建成一个对象的过程。
一个对象若是想要进行序列化,那么该对象的类必须实现Serializable接口。数据库
ObjectStream functions
ObjectInputStream
// 构造函数 ObjectInputStream(InputStream input) int available() void close() void defaultReadObject() int read(byte[] buffer, int offset, int length) int read() boolean readBoolean() byte readByte() char readChar() double readDouble() ObjectInputStream.GetField readFields() float readFloat() void readFully(byte[] dst) void readFully(byte[] dst, int offset, int byteCount) int readInt() String readLine() long readLong() final Object readObject() short readShort() String readUTF() Object readUnshared() int readUnsignedByte() int readUnsignedShort() synchronized void registerValidation(ObjectInputValidation object, int priority) int skipBytes(int length)
ObjectOutputStream
// 构造函数 ObjectOutputStream(OutputStream output) // public函数 void close() void defaultWriteObject() void flush() ObjectOutputStream.PutField putFields() void reset() void useProtocolVersion(int version) void write(int value) void write(byte[] buffer, int offset, int length) void writeBoolean(boolean value) void writeByte(int value) void writeBytes(String value) void writeChar(int value) void writeChars(String value) void writeDouble(double value) void writeFields() void writeFloat(float value) void writeInt(int value) void writeLong(long value) final void writeObject(Object object) void writeShort(int value) void writeUTF(String value) void writeUnshared(Object object)
Serializable interface
Usage scenario
- 将内存中的对象写入文件或数据库
- 经过socket在网络上传输对象
How to Implement
将须要进行序列化的类实现Serializable接口。
该接口源码:网络
public interface Serializable {}
Serializable接口没有任何成员变量和函数,它只是一个标记,实现了该接口的类就意味着该类能够进行序列化。app
serialVersionUID
The serialization runtime associates with each serializable class a version number, called a serialVersionUID, which is used during deserialization to verify that the sender and receiver of a serialized object have loaded classes for that object that are compatible with respect to serialization. If the receiver has loaded a class for the object that has a different serialVersionUID than that of the corresponding sender's class, then deserialization will result in an InvalidClassException. A serializable class can declare its own serialVersionUID explicitly by declaring a field named serialVersionUID that must be static, final, and of type long:socket
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;ide
If a serializable class does not explicitly declare a serialVersionUID, then the serialization runtime will calculate a default serialVersionUID value for that class based on various aspects of the class, as described in the Java(TM) Object Serialization Specification. However, it is strongly recommended that all serializable classes explicitly declare serialVersionUID values, since the default serialVersionUID computation is highly sensitive to class details that may vary depending on compiler implementations, and can thus result in unexpected InvalidClassExceptions during deserialization. Therefore, to guarantee a consistent serialVersionUID value across different java compiler implementations, a serializable class must declare an explicit serialVersionUID value. It is also strongly advised that explicit serialVersionUID declarations use the private modifier where possible, since such declarations apply only to the immediately declaring class serialVersionUID fields are not useful as inherited members.函数
序列化时系统会把当前类的 serialVersionUID 写入序列化的文件中(也多是其余的中介),当反序列化的时候系统会去检测文件中的 serialVersionUID,看它是否和当前类的 serialVersionUID 一致,若是一致就说明序列化的类的版本和当前类的版本是相同的,这个时候能够成功反序列化,不然就说明当前类和序列化的类相比发生了某些变化 简单而言serialVersionID的做用就是惟一的确承认序列化的对象,建议显示的定义,由于默认生成的serialVersionUid高度敏感,很容易致使InvalidClassException。IDE,不管是Eclipse,仍是Intellij都提供了自动生成serivalVersionUID的功能。this
others
- 序列化先后的对象内容同样,地址不一样,属于深拷贝(deep copy)
- 当一个父类实现序列化,子类自动实现序列化,不须要显式实现 Serializable 接口
- 有一些敏感数据是不适合被传输,所以须要加上 transient 关键字,便可避免序列化, transient只能修饰变量,不能修饰类和方法(类和方法也不须要序列化:rofl:)
- 静态变量是相对于类的,而非对象,所以其也没法参与到序列化中。上面的 Demo 中,咱们在写入对象后对静态变量进行修改。而再次读取对象时,该变量的值为咱们所修改过的。即序列化会忽略静态变量
Example
Example
对象序列化:spa
- 建立一个对象输出流,它能够包装一个其余类型的目标输出流,如文件输出流;
- 经过对象输出流的writeObject()方法写对象。
对象反序列化的步骤以下:code
- 建立一个对象输入流,它能够包装一个其余类型的源输入流,如文件输入流;
- 经过对象输入流的readObject()方法读取对象。
:warning:对象的序列化是基于字节的,不能使用Reader和Writer等基于字符的层次结构。
package com.test.io; import java.io.*; /** * @Author: yuler * @Date: 2019/9/28 10:14 */ enum Gender{MAN, WOMAN} class Student implements Serializable { private static final long serialVersionUID = 1266317689698700639L; // 实现Serializble接口才能进行序列化 private int id; private String name; private transient int age; private Gender gender; // add //private int grade; public Student(int id, String name, int age, Gender gender){ this.id = id; this.name = name; this.age = age; this.gender = gender; // this.grade = 123; } @Override public String toString() { return "Student{" + "id=" + id + ", name='" + name + '\'' + ", age=" + age + ", gender=" + (gender == Gender.MAN?"MAN":"WOMAN") + '}'; } } public class ObjectStreamTest { private static final String PATH = "object.tmp"; private void objectInputStreamTest(){ try{ FileInputStream fis = new FileInputStream(PATH); ObjectInputStream ois = new ObjectInputStream(fis); System.out.println(ois.readBoolean()); System.out.println(ois.readByte()); System.out.println(ois.readChar()); System.out.println(ois.readInt()); System.out.println(ois.readFloat()); System.out.println(ois.readLong()); System.out.println(ois.readDouble()); System.out.println((Student)ois.readObject()); }catch (Exception e){ e.printStackTrace(); } } private void objectOutputStreamTest(){ try{ FileOutputStream fos = new FileOutputStream(PATH); ObjectOutputStream oos = new ObjectOutputStream(fos); Student stu = new Student(1, "yuler", 21, Gender.MAN); oos.writeBoolean(true); oos.writeByte(1); oos.writeChar('2'); oos.writeInt(4); oos.writeFloat(4); oos.writeLong(8); oos.writeDouble(8); oos.writeObject(stu); oos.close(); }catch(Exception e){ e.printStackTrace(); } } public static void main(String[] args) { ObjectStreamTest ost = new ObjectStreamTest(); ost.objectOutputStreamTest(); ost.objectInputStreamTest(); } }
运行结果:
true 1 2 4 4.0 8 8.0 Student{id=1, name='yuler', age=0, gender=MAN}