輸入輸出流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\n" , in.readBoolean());
            System.out.printf("byte:%d\n" , (in.readByte()&0xff));
            System.out.printf("char:%c\n" , in.readChar());
            System.out.printf("int:%d\n" , in.readInt());
            System.out.printf("float:%f\n" , in.readFloat());
            System.out.printf("double:%f\n" , in.readDouble());
            System.out.printf("String:%s\n" , 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\n" , 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接口。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM