Serializable的簡單認識
一、Serializable簡介
Serializable是Java中的一個提供序列化的接口,可以為對象提供序列化和反序列化。Serializable接口是一個空接口,使用起來非常方便,只需要將準備序列化的類實現(xiàn)該接口即可。
public interface Serializable {
/* empty */
}
二、Serializable的簡單應用
1、對象的存儲
一般情況下我們見得比較多的是將一些具體的數據,如數字、文字、視頻、音頻等會保存到存儲設備上,但有的時候也需要將對象持久化到存儲設備上,這個時候就需要使用Serializable將對象持久化的操作,即將對象保存到存儲設備上。
通過Serializable的方式非常簡單,因為大多數工作都由系統(tǒng)完成,我們只需讓對象的類實現(xiàn)Serializable接口,并且使用ObjectInputStream和ObjectOutputStream即可完成,來看下面的的列子。
自定義一個Books類:
public class Books implements Serializable {
private static final long serialVersionUID = 12345678L;
public String name = "紅樓";
public Books(String name) {
super();
this.name = name;
}
}
布局文件就不做介紹,上面就放置兩個按鈕,一個實現(xiàn)序列化,一個實現(xiàn)反序列化。對應的MainActivity代碼如下:
public class MainActivity extends Activity {
File file = new File(Environment.getExternalStorageDirectory(),
"serializable.txt");
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
findViewById(R.id.bt1).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
write();
}
});
findViewById(R.id.bt2).setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
read();
}
});
}
/**
* 實現(xiàn)序列化存儲
*/
private void write() {
try {
Books books = new Books("三國");
FileOutputStream fout = new FileOutputStream(file);
ObjectOutputStream out = new ObjectOutputStream(fout);
out.writeObject(books);
System.out.println("books = " + books);
out.close();
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
/**
* 反序列化從存儲設備讀取對象
*/
private void read() {
try {
FileInputStream fin = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fin);
Books books = (Books) in.readObject();
System.out.println("books = " + books);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
上面程序運行,點擊序列化按鈕。
在sd卡目錄下找到我們保存的文件,打開。
可以看到我們已經將程序中創(chuàng)建的Books對象book存儲到的sd卡上。點擊反序列化按鈕即可將對象的數據從sd卡反序列化,從新生成一個Books對象,如下打印信息所示,可以看到數據是一樣的,但是這兩個對象并不是同一個了。
大家會發(fā)現(xiàn)在Books類中聲明了一個serialVersionUID,這個常量并不是必須的,不聲明也可實現(xiàn)對象的序列化,但是在一些情況下會對反序列化產生影響。如果我們不去自己指定一個serialVersionUID,在序列化時會按照類的結構自動生成一個serialVersionUID值,但是在序列化存儲后改變了類的結構,如增加和刪除成員變量,重新編譯運行后直接進行反序列化的話,這個時候會出現(xiàn)反序列化失敗。
在序列化時會將serialVersionUID值也寫入序列化的文件中,當我們把類的結構改變后,當前類中的serialVersionUID會重新生成,這就導致文件中serialVersionUID和目前的serialVersionUID不一致,就如上面輸出信息提示所示,這將會導致反序列化失敗。
但是當手動指定serialVersionUID后,如果將類的結構改變之后,反序列化依舊會成功,并且將大程度的恢復數據。還是上面那個例子,先進行序列化,然后在Books類中增加一個成員變量:
public class Books implements Serializable {
private static final long serialVersionUID = 12345678L;
public String name = "紅樓";
public int price = 100;
public Books(String name) {
super();
this.name = name;
}
}
/**
* 反序列化從存儲設備讀取對象
*/
private void read() {
try {
FileInputStream fin = new FileInputStream(file);
ObjectInputStream in = new ObjectInputStream(fin);
Books books = (Books) in.readObject();
// 打印輸出類中的成員變量
System.out.println("books = " + books+" "+books.name+" "+books.price);
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
然后重新編譯運行直接反序列化:
可以看到這次反序列化成功,并且原本序列化文件中并沒有“price”的數據,通過自己指定serialVersionUID后能避免類似的情況,這里就給該屬性附了一個默認值0。
2、對象的傳遞
這里只是介紹利用Intent傳遞對象,Intent默認沒有提供一個方法直接去傳遞一個對象,但是可以將對象序列化后便可。Intent中的putExtra方法就可以傳遞一個Serializable 類型的數據,所以只需要這個類實現(xiàn)Serializable 接口即可。
putExtra(String name, Serializable value)
如下所示:
Books books = new Books("三國");
Intent intent = new Intent();
intent.putExtra("data", books);
在接收數據時利用intent中對應的Serializable getSerializableExtra(String name)方法即可。
Books newbook = (Books) intent.getSerializableExtra("data");