【JAVA IO】_對象序列化筆記
本章目標:
掌握對象序列化的作用
掌握Serializable介面作用
可以使用ObjectOutputStream進行對象序列化操作
可以使用ObjectinputStream進行對象還原序列化操作
掌握Externalizable介面的作用及與Serializable介面的實現區別
掌握transient關鍵字的作用
可以序列化一組對象
3.1、什麼叫對象序列化
一個對象產生後實際上是在記憶體中為其開闢了一個儲存空間,方便儲存資訊。
對象序列化,就是把一個對象變為二進位的資料流的一種方法,通過對象序列化可以方便的實現對象的傳輸或儲存.
如果一個類的對象想被序列化,則對象所在的類必須實現java.io.Serializable介面。此介面定義如下:
public interface Serializable{}
一個類不能平白無故的被序列化。
但是,在此介面中沒有任何一個方法,此介面屬於一個標識介面,表示具備了某種能力。
例如:現在定義一個類,此類可以被序列化。
import java.io.Serializable;public class Person implements Serializable{ private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "姓名:"+this.name+";年齡:"+this.age; }}
以後此類的對象,就可以被序列化了,變為二進位byte流。
對象的序列化和還原序列化
要想完成對象的輸入或輸出,還必須依靠對象輸出資料流(ObjectOutputStream)和對象輸入資料流(ObjectInputStream)
使用對象輸出資料流輸出序列化對象的步驟,有時也稱之為序列化,而使用對象輸入資料流讀入對象的過程,有時也稱為還原序列化。
serialVersionUID
對象的序列化和還原序列化要考慮JDK版本不統一的問題,所以在序列化操作中引入了serialVersionUID的常量,可以通過此常量來驗證版本的一致性,在進行還原序列化時,JVM會把傳來的位元組流中的serialVersionUID與本地的相應實體類的serialVersionUID進行比較,如果相同就認為是一致的,可以進行還原序列化,否則就會出現序列化版本不一致的異常。
import java.io.Serializable;public class Person implements Serializable{ private static final long serialVersionUID = 1L; private String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "姓名:"+this.name+";年齡:"+this.age; }}
如果使用開發工具開發,就有編寫此代碼,則會出現一些安全警告的資訊。
3.2、對象的序列化及還原序列化操作
對象序列化依靠ObjectOutputStream,對象還原序列化依靠ObjectInputStream
3.2.1、序列化:ObjectOutputStream
定義格式:
public class ObjectOutputStream extends OutputStream implements ObjectOutput,ObjectStreamConstants
import java.io.File ;import java.io.FileOutputStream ;import java.io.OutputStream ;import java.io.ObjectOutputStream ;public class SerDemo01{ public static void main(String args[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectOutputStream oos = null ; // 聲明對象輸出資料流 OutputStream out = new FileOutputStream(f) ; // 檔案輸出資料流 oos = new ObjectOutputStream(out) ; oos.writeObject(new Person("張三",30)) ; // 儲存對象 oos.close() ; // 關閉 }};
到底序列化了哪些東西呢?
所有的對象擁有各自的屬性值,但是所有的方法都是公用的,所以序列化對象的時候實際上序列化的就是屬性。
3.2.2、還原序列化:ObjectInputStream
定義格式
public class ObjectInputStream extends InputStream implements ObjectInput,ObjectStreamConstants
import java.io.File ;import java.io.FileInputStream ;import java.io.InputStream ;import java.io.ObjectInputStream ;public class SerDemo02{ public static void main(String args[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectInputStream ois = null ; // 聲明對象輸入資料流 InputStream input = new FileInputStream(f) ; // 檔案輸入資料流 ois = new ObjectInputStream(input) ; // 執行個體化對象輸入資料流 Object obj = ois.readObject() ; // 讀取對象 ois.close() ; // 關閉 System.out.println(obj) ; }};
問題:如果一個類實現了Serializable介面,則肯定此類可以被序列化下來,那麼也就意味著此類多了一項功能,可以被序列化,那麼讓所有類都實現此介面是不是更好啊?
因為:JDK是會不斷升級的,現在Serializable介面中沒有任何定義,那麼以後呢?
3.3、Externalizable介面
使用Serializable介面可以方便的序列化一個對象,但是在序列化操作中也提供了另外一種序列化機制————Exnternalizable介面
定義格式:
public interface Externalizable extends Serializable{
public void writeExternal(ObjectOutput out)throws IOException;
public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException;
}
在使用Exterlizable介面的時候需要在被序列化的類中定義一個無參構造。
import java.io.Externalizable;import java.io.*;public class Person implements Externalizable{ private static final long serialVersionUID = 1L; private String name; private int age; public Person(){} public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "姓名:"+this.name+";年齡:"+this.age; } public void writeExternal(ObjectOutput out)throws IOException{ out.writeObject(this.name); out.writeInt(this.age); } public void readExternal(ObjectInput in)throws IOException,ClassNotFoundException{ this.name = (String)in.readObject(); this.age = in.readInt(); }}
import java.io.File ;import java.io.IOException ;import java.io.FileOutputStream ;import java.io.OutputStream ;import java.io.ObjectOutputStream ;import java.io.FileInputStream ;import java.io.InputStream ;import java.io.ObjectInputStream ;public class SerDemo03{ public static void main(String args[]) throws Exception{ //ser() ; dser() ; } public static void ser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectOutputStream oos = null ; // 聲明對象輸出資料流 OutputStream out = new FileOutputStream(f) ; // 檔案輸出資料流 oos = new ObjectOutputStream(out) ; oos.writeObject(new Person("張三",30)) ; // 儲存對象 oos.close() ; // 關閉 } public static void dser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectInputStream ois = null ; // 聲明對象輸入資料流 InputStream input = new FileInputStream(f) ; // 檔案輸入資料流 ois = new ObjectInputStream(input) ; // 執行個體化對象輸入資料流 Object obj = ois.readObject() ; // 讀取對象 ois.close() ; // 關閉 System.out.println(obj) ; }};
3.4、transient關鍵字
當使用Serializable介面實現序列化操作時,如果一個對象中的某個屬性不希望被序列化的話,則可以使用transient關鍵字進行聲明。
import java.io.Serializable;public class Person implements Serializable{ private static final long serialVersionUID = 1L; private transient String name; private int age; public Person(String name,int age){ this.name = name; this.age = age; } public String toString(){ return "姓名:"+this.name+";年齡:"+this.age; }}
import java.io.File ;import java.io.IOException ;import java.io.FileOutputStream ;import java.io.OutputStream ;import java.io.ObjectOutputStream ;import java.io.FileInputStream ;import java.io.InputStream ;import java.io.ObjectInputStream ;public class SerDemo04{ public static void main(String args[]) throws Exception{ ser() ; dser() ; } public static void ser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectOutputStream oos = null ; // 聲明對象輸出資料流 OutputStream out = new FileOutputStream(f) ; // 檔案輸出資料流 oos = new ObjectOutputStream(out) ; oos.writeObject(new Person("張三",30)) ; // 儲存對象 oos.close() ; // 關閉 } public static void dser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectInputStream ois = null ; // 聲明對象輸入資料流 InputStream input = new FileInputStream(f) ; // 檔案輸入資料流 ois = new ObjectInputStream(input) ; // 執行個體化對象輸入資料流 Object obj = ois.readObject() ; // 讀取對象 ois.close() ; // 關閉 System.out.println(obj) ; }};
transient+Serializable介面完全可以取代Externalizable介面的功能。
3.5、序列化一組對象(就是將Obj由單個對象變為多個對象)
import java.io.File ;import java.io.IOException ;import java.io.FileOutputStream ;import java.io.OutputStream ;import java.io.ObjectOutputStream ;import java.io.FileInputStream ;import java.io.InputStream ;import java.io.ObjectInputStream ;public class SerDemo05{ public static void main(String args[]) throws Exception{ Person per[] = {new Person("張三",30),new Person("李四",31), new Person("王五",32)} ; ser(per) ; Object o[] = (Object[])dser() ; for(int i=0;i<o.length;i++){ Person p = (Person)o[i] ; System.out.println(p) ; } } public static void ser(Object obj[]) throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectOutputStream oos = null ; // 聲明對象輸出資料流 OutputStream out = new FileOutputStream(f) ; // 檔案輸出資料流 oos = new ObjectOutputStream(out) ; oos.writeObject(obj) ; // 儲存對象 oos.close() ; // 關閉 } public static Object[] dser() throws Exception { File f = new File("D:" + File.separator + "test.txt") ; // 定義儲存路徑 ObjectInputStream ois = null ; // 聲明對象輸入資料流 InputStream input = new FileInputStream(f) ; // 檔案輸入資料流 ois = new ObjectInputStream(input) ; // 執行個體化對象輸入資料流 Object obj[] = (Object[])ois.readObject() ; // 讀取對象 ois.close() ; // 關閉 return obj ; }};