javaio objectStream

<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

  1. 建立一個對象輸出流,它能夠包裝一個其餘類型的目標輸出流,如文件輸出流;
  2. 經過對象輸出流的writeObject()方法寫對象。

對象反序列化的步驟以下:code

  1. 建立一個對象輸入流,它能夠包裝一個其餘類型的源輸入流,如文件輸入流;
  2. 經過對象輸入流的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}
相關文章
相關標籤/搜索