我們知道在JAVA類中,很多類都實作了Serializable類的方法,他的意思是将這個類在運作的時候進行序列化,這個接口類的注解是這麼寫的,
/ * @author unascribed
* @see java.io.ObjectOutputStream
* @see java.io.ObjectInputStream
* @see java.io.ObjectOutput
* @see java.io.ObjectInput
* @see java.io.Externalizable
* @since JDK1.1
*/
起源于JDK1.1版本,是屬于java.io類裡的接口。
1、那什麼是序列化?
對象的狀态有:
1. 建立階段(Created)
2. 應用階段(In Use)
3. 不可見階段(Invisible)
4. 不可達階段(Unreachable)
5. 收集階段(Collected)
6. 終結階段(Finalized)
7. 對象空間重配置設定階段(De-allocated)
那麼,如果一個對象在建立之後,如果我想把工程停下來,但是卻又想保留住這個對象的資訊,以便下次使用,那麼怎麼辦呢?這個時候就是序列化Serializable起到作用的時候了,它把對象的狀态和資訊轉換為位元組序列儲存到磁盤上,然後在你想使用的時候,通過一些java類方法可以再次讀取到這個對象的資訊和狀态,重新擷取該對象。那麼如果在儲存的時候如果有其他對象的引用,那麼序列化過程中把其他對象的資訊以遞歸的方式儲存下來,整個儲存的格式會是一個複雜的樹形,最後讀取也是以這個格式來擷取對象。
2、如何進行序列化?
如果我們想要序列化一個對象,首先要建立某些OutputStream(如FileOutputStream、ByteArrayOutputStream等,其實就是Serializable類注
解上的呢些類的方法),然後将這些OutputStream封裝在一個ObjectOutputStream中。這時候,隻需要調用writeObject()方法就可以将對象序列化,
并将其發送給OutputStream(記住:對象的序列化是基于位元組的,不能使用Reader和Writer等基于字元的層次結構)。而反序列的過程(即将一個序列還原成
為一個對象),需要将一個InputStream(如FileInputstream、ByteArrayInputStream等)封裝在ObjectInputStream内,然後調用readObject()即可。
以下是代碼示例:
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
{
//輸出流儲存的檔案名為 my.out,ObjectOutputStream能把Object輸出成Byte流
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("my.out"));
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
3:序列化ID
在很多時候,發現model類中有呢麼一個字段:
private static final long serialVersionUID = xxxxxxxxxxxxxxl;
可以很明顯的看出來,這描述的是一個為long型的序列化ID,那麼這個序列化ID是用來幹什麼的呢?
因為序列化的左右就是用來反序列化的,那麼一個已經序列化的檔案,在反序列化的時候,我如何知道這段時間中這個對象類是否有變化呢?假如我删了字段,其實如果将這個對象再反序列化回來是錯誤的,那麼如何标記序列化對象和反序列化的時候的對象是否是一緻的呢?就是用的這個序列化ID了,其實就相當于對這個對象hash出來了一個long的數值而已,這就是我的了解,如果這兩個ID不一緻,在反序列化的時候是會報錯的。4:序列化的注意事項:
1、靜态類是無法被序列化的。序列化的是對象的狀态不是類的狀态,靜态成員屬于類級别的,序列化會忽略靜态變量,即序列化不儲存靜态變量的狀态。
2、transient是一個瞬時狀态,是以也是無法被序列化的。
3、當一個父類實作序列化,子類自動實作序列化,不需要顯式實作Serializable接口。
4、當一個對象的執行個體變量引用其他對象,序列化該對象時也把引用對象進行序列化。