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}
相关文章
相关标签/搜索