之前看過一遍《Java編程思想》,把書中的代碼理解了一遍,也都敲過一遍。但是很多比較深入的知識在實際的工作中并未使用到,因此都忘記了,為了給自己做一些鞏固,在以后的時間里,我會努力地做一些關于這些內容的讀書筆記,以加強自己的理解
Java的序列化是指將Java對象轉化為可在磁盤或者其它存儲介質中保存的字節序列,以便在后續的操作中將這個字節序列重新復原為Java對象,存儲的字節序列可以寫入文件亦可以通過網絡進行傳輸。那么什么對象可以被序列化呢?被序列化的對象必須實現Serializable接口,請看下例:
package com.fan;
import java.io.*;
import java.util.Random;
/**
* Created by Alpha on 17/4/16.
*/
class Data implements Serializable {
private int n;
public Data(int n){this.n = n;}
public String toString(){return Integer.toString(n);}
}
public class Worm implements Serializable{
private static Random rand = new Random(47);
private Data d[] = {
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10)),
new Data(rand.nextInt(10))
};
private Worm next;
private char c;
public Worm(int i,char x){
System.out.println("Worm constructor:" + i);
c = x;
if(--i > 0){
next = new Worm(i,(char)(x + 1));
}
}
public Worm(){
System.out.println("Default constructor");
}
public String toString(){
StringBuilder result = new StringBuilder(":");
result.append(c);
result.append("(");
for(Data dat : d)
result.append(dat);
result.append(")");
if(next != null)
result.append(next);
return result.toString();
}
public static void test() throws IOException, ClassNotFoundException {
Worm w = new Worm(6,'a');
System.out.println("w = " + w);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("worm.out"));
out.writeObject("Worm storage");
out.writeObject(w);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("worm.out"));
String s = (String) in.readObject();
Worm w2 = (Worm) in.readObject();
System.out.println(s + "w2 = " + w2);
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out2 = new ObjectOutputStream(bout);
out2.writeObject("worm storage");
out2.writeObject(w);
out2.flush();
ObjectInputStream in2 = new ObjectInputStream(new ByteArrayInputStream(bout.toByteArray()));
s = (String) in2.readObject();
Worm w3 = (Worm) in2.readObject();
System.out.println(s + "w3 = " + w3);
}
}
輸出如下:
在上面的例子中我們可以看到,我們定義了兩個類,Data
和Worm
,它們都實現了Serializable
接口,在測試方法中我們創建一個包含6個Worm類對象并將這些對象寫到了文件worm.out
中,看上面的讀取步驟,與寫入的步驟相同,我們也是先讀取一個字符串對象再讀取一個Worm對象
如上例,假如我們將寫的對象的序列化文件通過網絡傳輸給其它的計算機,那么其它的計算機是不是同樣也能解析出這個對象呢,答案是不一定,假如另一臺計算機中的classpath
中沒有上述的Data
類和Worm
類,那么就會拋出一個ClassNotFoundException
的異常
Externalizable
假如我們需要序列化一個對象,但是又不希望將這個對象的所有成員都序列化,比如登錄表單,我們只希望提供給用戶用戶名
而不是密碼
,那么我們可以將包含用戶名
和密碼
的類通過實現Externalizable
接口來實現,請看下面的實例
package com.fan;
import java.io.*;
/**
* Created by Alpha on 17/4/16.
*/
public class Blips3 implements Externalizable {
private int i;
private String s;
public Blips3(){
System.out.println("Blips3 constructor");
}
public Blips3(String x,int a){
s = x;
i = a;
}
public String toString(){return s + i;}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("Blips3.writeExternal");
out.writeObject(s);
out.writeInt(i);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("Blips3.readExternal");
s = (String) in.readObject();
i = in.readInt();
}
public static void test() throws IOException, ClassNotFoundException {
System.out.println("Constructing objects:");
Blips3 b3 = new Blips3("A String " , 47);
System.out.println(b3);
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("Blip3.out"));
System.out.println("Saving object:");
out.writeObject(b3);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("Blip3.out"));
System.out.println("Recovering b3:");
b3 = (Blips3) in.readObject();
System.out.println(b3);
}
}
輸出如下
如上,我們在使用
Externalizable
接口來進行對象的初始化時,我們必須實現Externalizable
類的兩個接口writeExternal
和readExternal
,這個過程和Serializable
接口的不太一樣,Serializable
是以二進制為基礎來對對象進行存儲,而Externalizable
則需要調用構造器,寫入時調用writeExternal
,讀取時調用readExternal
,因此我們假如我們不想某個成員的內容被序列化,我們可以不在writeExternal
方法里將其寫入輸出文件。注意在使用序列化寫入或讀取時,寫入的方法和讀取的對應的方法要一致
transient關鍵字
利用Serializable也可以實現對象的部分成員序列化,那就是對不需要序列化的成員使用transient關鍵字,如下例所示
package com.fan;
import java.io.*;
import java.util.Date;
import java.util.concurrent.TimeUnit;
/**
* Created by fanwenlong on 17/4/16.
*/
public class Logon implements Serializable {
private Date date = new Date();
private String username;
private transient String password;
public Logon(String username,String password){
this.username = username;
this.password = password;
}
public String toString(){
return "logon info:\n username:" + username + "\n date:" + date + "\n password:" + password;
}
public static void test() throws IOException, InterruptedException, ClassNotFoundException {
Logon logon = new Logon("Aplha","hello");
System.out.println("Logon logon = " + logon);
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream("Logon.out"));
o.writeObject(logon);
o.close();
TimeUnit.SECONDS.sleep(1);
ObjectInputStream in = new ObjectInputStream(new FileInputStream("Logon.out"));
System.out.println("Recoving object at:" + new Date());
logon = (Logon) in.readObject();
System.out.println("logon logon = " + logon);
}
}
結果如下
可以看到,上面的
password
寫入序列化后再次的值為空,說明其沒有被寫入保存