一個對象產生以後其實是在內存中爲其開闢了一個存儲空間,方便存儲信息。java
import java.io.Serializable ; public class Person implements Serializable{ private String name ; // 聲明name屬性 private int age ; // 聲明age屬性 public Person(String name,int age){ // 經過構造設置內容 this.name = name ; this.age = age ; } public String toString(){ // 覆寫toString()方法 return "姓名:" + this.name + ";年齡:" + this.age ; } }
之後此類的對象,就能夠被序列化了。變爲二進制byte流。數組
import java.io.Serializable ; public class Person implements Serializable{ private static final long serialVersionUID = 1L;/*驗證版本的一致性*/ private String name ; // 聲明name屬性 private int age ; // 聲明age屬性 public Person(String name,int age){ // 經過構造設置內容 this.name = name ; this.age = age ; } public String toString(){ // 覆寫toString()方法 return "姓名:" + this.name + ";年齡:" + this.age ; } }
若是使用開發工具開發,沒有編寫此代碼,則會出現一些安全警告信息。安全
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() ; // 關閉 } }
全部的對象擁有各自的屬性值,可是全部的方法都是公共的,因此序列化對象的時候實際上序列化的就是屬性。ide
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) ; } }
import java.io.Serializable ;工具
public class Person implements Serializable{ private static final long serialVersionUID = 1L; private transient String name ; // 聲明name屬性,可是此屬性不被序列化 private int age ; // 聲明age屬性 public Person(String name,int age){ // 經過構造設置內容 this.name = name ; this.age = age ; } public String toString(){ // 覆寫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) ; } }
1)一旦變量被transient修飾,變量將再也不是對象持久化的一部分,該變量內容在序列化後沒法得到訪問。開發工具
2)transient關鍵字只能修飾變量,而不能修飾方法和類。注意,本地變量是不能被transient關鍵字修飾的。變量若是是用戶自定義類變量,則該類須要實現Serializable接口。this
3)被transient關鍵字修飾的變量再也不能被序列化,一個靜態變量無論是否被transient修飾,均不能被序列化。spa
第三點可能有些人很迷惑,由於發如今User類中的username字段前加上static關鍵字後,程序運行結果依然不變,即static類型的username也讀出來爲「Alexia」了,這不與第三點說的矛盾嗎?其實是這樣的:第三點確實沒錯(一個靜態變量無論是否被transient修飾,均不能被序列化),反序列化後類中static型變量username的值爲當前JVM中對應static變量的值,這個值是JVM中的不是反序列化得出的,不相信?好吧,下面我來證實:對象
import java.io.FileInputStream; import java.io.FileNotFoundException; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInputStream; import java.io.ObjectOutputStream; import java.io.Serializable; publicclass TransientTest { public static void main(String[] args) { User user = new User(); user.setUsername("Alexia"); user.setPasswd("123456"); System.out.println("read before Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); try { ObjectOutputStream os = new ObjectOutputStream( new FileOutputStream("C:/user.txt")); os.writeObject(user); // 將User對象寫進文件 os.flush(); os.close(); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } try { // 在反序列化以前改變username的值 User.username = "jmwang"; ObjectInputStream is = new ObjectInputStream(new FileInputStream( "C:/user.txt")); user = (User) is.readObject(); // 從流中讀取User的數據 is.close(); System.out.println("\nread after Serializable: "); System.out.println("username: " + user.getUsername()); System.err.println("password: " + user.getPasswd()); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } } } class User implements Serializable { private static final long serialVersionUID = 8294180014912103005L; public static String username; private transient String passwd; public String getUsername() { return username; } publicvoid setUsername(String username) { this.username = username; } public String getPasswd() { return passwd; } publicvoid setPasswd(String passwd) { this.passwd = passwd; } }
運行結果爲:接口
read before Serializable: username: Alexia password: 123456 read after Serializable: username: jmwang password: null
這說明反序列化後類中static型變量username的值爲當前JVM中對應static變量的值,爲修改後jmwang,而不是序列化時的值Alexia。
思考下面的例子:
import java.io.Externalizable; import java.io.File; import java.io.FileInputStream; import java.io.FileOutputStream; import java.io.IOException; import java.io.ObjectInput; import java.io.ObjectInputStream; import java.io.ObjectOutput; import java.io.ObjectOutputStream;
publicclass ExternalizableTest implements Externalizable { private transient String content = "是的,我將會被序列化,無論我是否被transient關鍵字修飾"; @Override publicvoid writeExternal(ObjectOutput out) throws IOException { out.writeObject(content); } @Override publicvoid readExternal(ObjectInput in) throws IOException, ClassNotFoundException { content = (String) in.readObject(); } publicstaticvoid main(String[] args) throws Exception { ExternalizableTest et = new ExternalizableTest(); ObjectOutput out = new ObjectOutputStream(new FileOutputStream( new File("test"))); out.writeObject(et); ObjectInput in = new ObjectInputStream(new FileInputStream(new File("test"))); et = (ExternalizableTest) in.readObject(); System.out.println(et.content); out.close(); in.close(); } }
content變量會被序列化嗎?好吧,我把答案都輸出來了,是的,運行結果就是:
是的,我將會被序列化,無論我是否被transient關鍵字修飾
這是爲何呢,不是說類的變量被transient關鍵字修飾之後將不能序列化了嗎?
咱們知道在Java中,對象的序列化能夠經過實現兩種接口來實現,若實現的是Serializable接口,則全部的序列化將會自動進行,若實現的是Externalizable接口,則沒有任何東西能夠自動序列化,須要在writeExternal方法中進行手工指定所要序列化的變量,這與是否被transient修飾無關。所以第二個例子輸出的是變量content初始化的內容,而不是null。
若是要保存多個對象,則最好使用對象數組的形式完成。
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 ; } }