對象流
對象流
概念
用於存儲和讀取基本數據類型數據或對象的處理流,可以把Java中的對象寫入到數據源中,也能把對象從數據源中還原回來
- 序列化:用ObjectOutputStream類保存基本數據類型或對象的機制
- 反序列化:用ObjectInputStream類讀取基本類型數據
注意:ObjectOutputStream和ObjectInputStream不能序列化static和transient修飾的成員變量
- transient的含義:不讓序列化這個屬性
對象的序列化機制
理解
對象序列化機制允許把內存中的Java對象轉換成平台無關的二進制流,從而允許把這種二進制流持久地保存在磁盤上,或通過網絡將這種二進制流傳輸到另一個網絡節點。當其它程序獲取了這種二進制流,就可以恢復成原來的Java對象
使用
一個可序列化的java對象需要滿足的要求
-
如果需要讓某個對象支持序列化機制,該類必須實現如下兩個接口之一,否則,會拋出NotSerializableException異常
- Serializable(常用)
- Externalizable
-
需要當前類提供一個全局常量serialVersionUID
public static final long serialVersionUID = 4892322646L;
其中數值沒有嚴格要求,隨便寫一個即可
-
內部所有屬性也必須是可序列化的(默認情況下,基本數據類型和String是可序列化的)
過程
序列化
- 創建一個ObjectOutputStream
- 調用 ObjectOutputStream 對象的 writeObject( 對象) 方法輸出可序列化對象
- 注意寫出一次,操作flush()方法
反序列化
- 創建一個 ObjectInputStream
- 調用 readObject() 方法讀取流中的對象
注意
如果某個類的屬性不是基本數據類型或 String 類型,而是另一個引用類型,那麼這個引用類型必須是可序列化的(實現Serializable接口),否則擁有該類型的Field 的類不能序列化
字符串序列化反序列化操作
序列化
使用ObjectOutputStream來實現
public void test1(){
//序列化過程:將內存中的java對象保存在磁盤中或通過網絡傳輸出去
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("我愛北京天安門"));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(oos != null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
反序列化
使用ObjectInputStream來實現
public void test2(){
//反序列化過程:將磁盤文件中對象還原為內存中的一個java對象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object object = ois.readObject();
String s = (String) object;
System.out.println(s);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(ois != null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
自定義類序列化反序列化操作
自定義類
注意自定義類一定要實現Serializable接口和有一個全局變量serialVersionUID
public class Person implements Serializable {
public static final long serialVersionUID = 4892322646L;
private String name;
private int age;
public Person() {
}
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
序列化
public void test1(){
//序列化過程:將內存中的java對象保存在磁盤中或通過網絡傳輸出去
ObjectOutputStream oos = null;
try {
oos = new ObjectOutputStream(new FileOutputStream("object.dat"));
oos.writeObject(new String("我愛北京天安門"));
oos.flush();
oos.writeObject(new Person("殷志源",42));
oos.flush();
} catch (IOException e) {
e.printStackTrace();
} finally {
try {
if(oos != null)
oos.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
反序列化
public void test2(){
//反序列化過程:將磁盤文件中對象還原為內存中的一個java對象
ObjectInputStream ois = null;
try {
ois = new ObjectInputStream(new FileInputStream("object.dat"));
Object object = ois.readObject();
String s = (String) object;
Person p = (Person) ois.readObject();
System.out.println(s);
System.out.println(p);
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
} finally {
try {
if(ois != null)
ois.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
serialVersionUID的理解
相當於一個標識
目的是以序列化對象進行版本控制,有關各版本反序列化時是否兼容
如果對類進行了修改,但是定義了serialVersionUID,反序列化的時候依舊可以識別出其內容
如果類沒有顯示定義這個靜態常量,它的值是Java運行時環境根據類的內部細節自動生成的。若類的實例變量做了修改,serialVersionUID可能發生變化。所以需要顯示聲明