我們知道在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、當一個對象的實例變量引用其他對象,序列化該對象時也把引用對象進行序列化。