输入输出流ObjectInputStream、ObjectOutputStream(对象序列化与反序列化)

对象的输入输出流 : 主要的作用是用于写入对象信息与读取对象信息。 对象信息一旦写到文件上那么对象的信息就可以做到持久化了
  对象的输出流: ObjectOutputStream
  对象的输入流:  ObjectInputStream

使用:

  对象的输出流将指定的对象写入到文件的过程,就是将对象序列化的过程,对象的输入流将指定序列化好的文件读出来的过程,就是对象反序列化的过程。既然对象的输出流将对象写入到文件中称之为对象的序列化,那么可想而知对象所对应的class必须要实现Serializable接口。(查看源码可得知:Serializable接口没有任何的方法,只是作为一个标识接口存在)。

import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Map;

public class ObjectStreamTest {
    private static final String TMP_FILE = "box.tmp";
    
    public static void main(String[] args) {
        testWrite();
        testRead();
    }
    
    private static void testWrite() {   
        try {
            ObjectOutputStream out = new ObjectOutputStream(
                    new FileOutputStream(TMP_FILE));
            out.writeBoolean(true);
            out.writeByte((byte)65);
            out.writeChar('a');
            out.writeInt(20131015);
            out.writeFloat(3.14F);
            out.writeDouble(1.414D);
            out.writeUTF("我是字符串");
            // 写入HashMap对象
            HashMap<String, String> map = new HashMap<String, String>();
            map.put("one", "red");
            map.put("two", "green");
            map.put("three", "blue");
            out.writeObject(map);
            // 写入自定义的Box对象,Box实现了Serializable接口
            Box box = new Box("desk", 80, 48);
            out.writeObject(box);

            out.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }
 
    /**
     * ObjectInputStream 测试函数
     */
    private static void testRead() {
        try {
            ObjectInputStream in = new ObjectInputStream(
                    new FileInputStream(TMP_FILE));
            System.out.printf("boolean:%b
" , in.readBoolean());
            System.out.printf("byte:%d
" , (in.readByte()&0xff));
            System.out.printf("char:%c
" , in.readChar());
            System.out.printf("int:%d
" , in.readInt());
            System.out.printf("float:%f
" , in.readFloat());
            System.out.printf("double:%f
" , in.readDouble());
            System.out.printf("String:%s
" , in.readUTF());
            // 读取HashMap对象
            HashMap map = (HashMap) in.readObject();
            Iterator<?> iter = map.entrySet().iterator();
            while (iter.hasNext()) {
                Map.Entry entry = (Map.Entry)iter.next();
                System.out.printf("%-6s -- %s
" , entry.getKey(), entry.getValue());
            }
            // 读取Box对象,Box实现了Serializable接口
            Box box = (Box) in.readObject();
            System.out.println("box: " + box);

            in.close();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

class Box implements Serializable {

    private static final long serialVersionUID = 1L;
    
    private int width;   
    private int height; 
    private String name;   

    public Box(String name, int width, int height) {
        System.out.println("Box的构造器");
        this.name = name;
        this.width = width;
        this.height = height;
    }

    @Override
    public String toString() {
        return "["+name+": ("+width+", "+height+") ]";
    }
}

console信息:

Box的构造器
boolean:true
byte:65
char:a
int:20131015
float:3.140000
double:1.414000
String:我是字符串
three -- blue
two -- green
one -- red
box: [desk: (80, 48) ]

最后总结一下对象输入输出流使用时需要注意:

  • 1. 如果对象需要被写出到文件上,那么对象所属的类必须要实现Serializable接口。 Serializable接口没有任何的方法,是一个标识接口而已。

  2. 对象的反序列化创建对象的时候并不会调用到构造方法的,从console打印的信息可以看出。

  • 3. serialVersionUID 是用于记录class文件的版本信息的,serialVersionUID这个数字是通过一个类的类名、成员、包名、工程名算出的一个数字。
  • 4. 使用ObjectInputStream反序列化的时候,ObjeectInputStream会先读取文件中的serialVersionUID,然后与本地的class文件的serialVersionUID
  • 进行对比,如果这两个id不一致,反序列则失败。
  • 5. 如果序列化与反序列化的时候可能会修改类的成员,那么最好一开始就给这个类指定一个serialVersionUID,如果一类已经指定的serialVersionUID,然后在序列化与反序列化的时候,jvm都不会再自己算这个 class的serialVersionUID了。
  • 6. 如果一个对象某个数据不想被序列化到硬盘上,可以使用关键字transient修饰。
  • 7. 如果一个类维护了另外一个类的引用,则另外一个类也需要实现Serializable接口。
原文地址:https://www.cnblogs.com/myseries/p/10757033.html