對象的輸入輸出流 : 主要的作用是用於寫入對象信息與讀取對象信息。 對象信息一旦寫到文件上那么對象的信息就可以做到持久化了
對象的輸出流: 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接口。