1. 程式人生 > >java物件序列化機制

java物件序列化機制

1.定義

java物件序列化機制允許實現了Serializable/Externalizable介面的java物件永久性地儲存到計算機的磁碟中,或則允許java物件直接在網路中傳輸,擺脫平臺的限制。反序列化即使將IO流中的位元組序列轉化為java物件。

2.原理

3.使用

序列化:

1)一個實現了Serializable介面的Java類

2)建立一個ObjectOutputSream物件

3)ObjectOutputSream是一個處理流,必須建立在其他節點流的基礎上

ObjectOutputSream objectOutputSream=new ObjectOutputSream(new FileOutputStream(“obj.txt”));
Student student=new Student();
objectOutputSream. writeObject(student);

測試程式碼:呼叫ObjectOutputStream物件的writeObject()方法即可完成將一個java物件序列化為檔案

public class SerializableTest {

    static Logger logger=Logger.getLogger("SerializableTest");

    public static void main(String[] args){

    try{

           ObjectOutputStream objectOutputStream=new ObjectOutputStream(new FileOutputStream("student.txt"));

           Student student=new Student();

           objectOutputStream.writeObject(student);

       }

       catch (FileNotFoundException e){

           logger.warning("沒找到檔案");

       }

       catch (IOException e){

           logger.warning("序列化"+SerializableTest.class.getName()+"的物件失敗");

       }

    }

}

建立一個ObjectInputStram物件反序列化:

呼叫ObjectInputStream物件的readObject()方法

測試程式碼:

public static Object readObj(FileInputStream fileInputStream) throws IOException, ClassNotFoundException{

       ObjectInputStream objectInputStream=null;

       try{

           objectInputStream=new ObjectInputStream(fileInputStream);

        }

       catch (IOException e){

           logger.info("建立objectInputStream時失敗");

       }

           return objectInputStream.readObject();

    }

    public static void main(String[] args) throws IOException, ClassNotFoundException{

    //SerializableTest.writeObj();

       Student student=(Student)SerializableTest.readObj(new FileInputStream("student.txt"));

       System.out.println(student.toString());

    }

4應用

什麼情況下需要序列化? 
  a)當你想把的記憶體中的物件狀態儲存到一個檔案中或者資料庫中時候; 
  b)當你想用套接字在網路上傳送物件的時候; 
  c)當你想通過RMI傳輸物件的時候; 
相關注意事項 :
  a)序列化時,只對物件的狀態進行儲存,而不管物件的方法; 
  b)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable介面; 
  c)當一個物件的例項變數引用其他物件,序列化該物件時也把引用物件進行序列化; 
  d)並非所有的物件都可以序列化,,至於為什麼不可以,有很多原因了,比如:

  1)安全方面的原因,比如一個物件擁有private,public等field,對於一個要傳輸的物件,比如寫到檔案,或者進行rmi傳輸等等,在序列化進行傳輸的過程中,這個物件的private等域是不受保護的。 
  2)資源分配方面的原因,比如socket,thread類,如果可以序列化,進行傳輸或者儲存,也無法對他們進行重新的資源分配,而且,也是沒有必要這樣實現。 

5物件引用的序列化

當一個物件中含有另一個物件的引用時。

假設現在有一個student物件和兩個teacher物件,其中兩個teacher物件都含有該student例項的引用,那麼在序列化這三個物件時,會出現一個問題:student例項會被序列化三次,那麼在反序列化這三個例項時,會例項化三個student物件,會造成這三個student物件不是同一個物件,這是不符合我們的最初要求的。

那麼,怎麼解決這個問題呢?

Java在實現物件引用的序列化時是這樣做的:每一個被序列化到磁碟的物件都會有一個序列化編號,在序列化一個物件時,會通過該編號檢查該物件是否已經被例項化過了。如果已經例項化過了,那麼會返回一個序列化編號而不會重新序列化該物件。只有沒有被序列化過的物件才會被序列化。

6解決同一個類的不同例項在序列化時序列位元組檔案因為同名被覆蓋的問題

7如果序列化一個例項時不對序列化的檔案的名字加以特殊處理,那麼再次序列化同類例項時會出現序列位元組檔案因為同名被覆蓋的問題

 

解決方案

1:在檔名後加雜湊值做字尾

 

2.statement和prepareStatement的使用

 

區別在於prepareStatement是預編譯語句,它會先將一個SQL語句編譯好,在後面的使用中只需要向其傳入引數即可。

 

如果對於一個經常出現的資料庫操作,應該使用預編譯SQL語句的方式,這種方式雖然在建立prepareStatement的消耗上大於statement,但是在後面的使用中不需要再次編譯,因此可以提高效能。   但是對於只做少次的資料庫操作,使用statement或許效率更高。