Java 序列化Serializable詳解(附詳細例子)


Java 序列化Serializable詳解(附詳細例子)

Java 序列化Serializable詳解(附詳細例子)

1、什么是序列化和反序列化
Serialization(序列化)是一種將對象以一連串的字節描述的過程;反序列化deserialization是一種將這些字節重建成一個對象的過程。

 

2、什么情況下需要序列化
a)當你想把的內存中的對象保存到一個文件中或者數據庫中時候;
b)當你想用套接字在網絡上傳送對象的時候;
c)當你想通過RMI傳輸對象的時候;

3、如何實現序列化

將需要序列化的類實現Serializable接口就可以了,Serializable接口中沒有任何方法,可以理解為一個標記,即表明這個類可以序列化。

 

4、序列化和反序列化例子

如果我們想要序列化一個對象,首先要創建某些OutputStream(如FileOutputStream、ByteArrayOutputStream等),然后將這些OutputStream封裝在一個ObjectOutputStream中。這時候,只需要調用writeObject()方法就可以將對象序列化,並將其發送給OutputStream記住:對象的序列化是基於字節的,不能使用Reader和Writer等基於字符的層次結構。而反序列的過程(即將一個序列還原成為一個對象),需要將一個InputStream(如FileInputstream、ByteArrayInputStream等)封裝在ObjectInputStream內,然后調用readObject()即可。

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
package com.sheepmu;
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;
  
public class MyTest implements Serializable
{
     private static final long serialVersionUID = 1L;
     private String name= "SheepMu" ;
     private int age= 24 ;
     public static void main(String[] args)
     { //以下代碼實現序列化
         try 
         {
             ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( "my.out" )); //輸出流保存的文件名為 my.out ;ObjectOutputStream能把Object輸出成Byte流
             MyTest myTest= new MyTest();
             oos.writeObject(myTest); 
             oos.flush();  //緩沖流 
             oos.close(); //關閉流
         } catch (FileNotFoundException e) 
         {        
             e.printStackTrace();
         } catch (IOException e) 
         {
             e.printStackTrace();
        
         fan(); //調用下面的  反序列化  代碼
     }
     public static void fan() //反序列的過程
     {    
          ObjectInputStream oin = null ; //局部變量必須要初始化
         try
         {
             oin = new ObjectInputStream( new FileInputStream( "my.out" ));
         } catch (FileNotFoundException e1)
         {        
             e1.printStackTrace();
         } catch (IOException e1)
         {
             e1.printStackTrace();
         }      
         MyTest mts = null ;
         try {
             mts = (MyTest ) oin.readObject(); //由Object對象向下轉型為MyTest對象
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }     
          System.out.println( "name=" +mts.name);    
          System.out.println( "age=" +mts.age);    
     }
}
會在此項目的工作空間生成一個 my.out文件。序列化后的內容稍后補齊,先看反序列化后輸出如下:

 

name=SheepMu
age=24

5、序列化ID

序列化 ID 在 Eclipse 下提供了兩種生成策略,一個是固定的 1L,一個是隨機生成一個不重復的 long 類型數據(實際上是使用 JDK 工具生成),在這里有一個建議,如果沒有特殊需求,就是用默認的 1L 就可以,這樣可以確保代碼一致時反序列化成功。這也可能是造成序列化和反序列化失敗的原因,因為不同的序列化id之間不能進行序列化和反序列化。

 

6.序列化前和序列化后的對象的關系

是 "=="還是equal? or 是淺復制還是深復制?

答案:深復制,反序列化還原后的對象地址與原來的的地址不同

序列化前后對象的地址不同了,但是內容是一樣的,而且對象中包含的引用也相同。換句話說,通過序列化操作,我們可以實現對任何可Serializable對象的”深度復制(deep copy)"——這意味着我們復制的是整個對象網,而不僅僅是基本對象及其引用。對於同一流的對象,他們的地址是相同,說明他們是同一個對象,但是與其他流的對象地址卻不相同。也就說,只要將對象序列化到單一流中,就可以恢復出與我們寫出時一樣的對象網,而且只要在同一流中,對象都是同一個。

 

7.靜態變量能否序列化

若把上面的代碼中的 age變量前加上 static ,輸出任然是

name=SheepMu
age=24

但是看下面的例子:

 

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
package com.sheepmu;
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;
public class MyTest implements Serializable
{
     private static final long serialVersionUID = 1L;
     private String name= "SheepMu" ;
     private static int age= 24 ;
     public static void main(String[] args)
     { //以下代碼實現序列化
         try 
         {
             ObjectOutputStream oos = new ObjectOutputStream( new FileOutputStream( "my.out" )); //輸出流保存的文件名為 my.out ;ObjectOutputStream能把Object輸出成Byte流
             MyTest myTest= new MyTest();
             oos.writeObject(myTest); 
             oos.flush();  //緩沖流 
             oos.close(); //關閉流
         } catch (FileNotFoundException e) 
         {        
             e.printStackTrace();
         } catch (IOException e) 
         {
             e.printStackTrace();
        
         fan(); //調用下面的  反序列化  代碼
     }
     public static void fan()
     {
         new MyTest().name= "SheepMu_1" ; //!!!!!!!!!!!!!!!!重點看這兩行 更改部分
           age= 1 ;<SPAN style= "FONT-FAMILY: verdana, 'ms song', 宋體, Arial, 微軟雅黑, Helvetica, sans-serif" > //!!!!!!!!!!!!!!!!!!!重點看這兩行 更改部分</SPAN>
          ObjectInputStream oin = null ; //局部變量必須要初始化
         try
         {
             oin = new ObjectInputStream( new FileInputStream( "my.out" ));
         } catch (FileNotFoundException e1)
         {        
             e1.printStackTrace();
         } catch (IOException e1)
         {
             e1.printStackTrace();
         }      
         MyTest mts = null ;
         try {
             mts = (MyTest ) oin.readObject(); //由Object對象向下轉型為MyTest對象
         } catch (ClassNotFoundException e) {
             e.printStackTrace();
         } catch (IOException e) {
             e.printStackTrace();
         }     
          System.out.println( "name=" +mts.name);    
          System.out.println( "age=" +mts.age);    
     }
}
輸出結果為:

 

name=SheepMu
age=1
為何把最上面代碼的age變量添上static 后還是反序列化出了24呢?而新的從新對變量賦值的代碼,不是static的得到了序列化本身的值,而static的則得到的是從新附的值。原因: 序列化會忽略靜態變量,即序列化不保存靜態變量的狀態。靜態成員屬於類級別的,所以不能序列化。即 序列化的是對象的狀態不是類的狀態。這里的不能序列化的意思,是序列化信息中不包含這個靜態成員域。最上面添加了static后之所以還是輸出24是因為該值是JVM加載該類時分配的值。注:transient后的變量也不能序列化,但是情況稍復雜,稍后開篇說。

8、總結:

a)當一個父類實現序列化,子類自動實現序列化,不需要顯式實現Serializable接口;

b)當一個對象的實例變量引用其他對象,序列化該對象時也把引用對象進行序列化;

c) static,transient后的變量不能被序列化;


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM