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