我们在上一篇博客中介绍了类实现标记性接口Serializable来实现序列化,但是如果你只想序列化诸多域中的某几个域,一种选择是将不序列化的域都标记上transient关键字,但是如果不需要序列化的域比较多,那么这种方式看起来很麻烦呀,第二种选择就是实现Externalizable接口了。这个接口其实是继承自Serializable接口,继承Externalizable的类必须实现writeExternal(ObjectOutput paramObjectOutput)和readExternal(ObjectInput paramObjectInput)两个方法,之后在序列化和反序列化是jdk序列化代码会判断是否是实现Externalizable接口的类,如果是的话序列化是就会调用writeExternal方法,反序列化时就会调用readExternal,这样我们就必须负责类的序列化所有的细节。
public abstract interface Externalizable extends Serializable {
public abstract void writeExternal(ObjectOutput paramObjectOutput)
throws IOException;
public abstract void readExternal(ObjectInput paramObjectInput)
throws IOException, ClassNotFoundException;
}
当然如果想正常的序列化除了实现上述两个方法之后,实现Externalizable接口的类必须提供一个公共的无参构造函数,在反序列化时会调用这个无参构造函数创建一个对象,之后再调用readExternal方法为域设置域值。
我们的测试代码如下:
/**
* 实现Externalizable接口的类 必须提供一个无参的公共构造函数
* @author yujie.wang
* @since 10/4/2017
*/
public class Book_Externalizable implements Externalizable {
//序列化的版本号
private static final long serialVersionUID = 6165984730624879548L;
private String name;
private double price;
private boolean status;
private int rent_days;
private List<String> list;
// 静态域属于类,不是对象的状态
private static String note = "this is a nice book";
// 构造函数的属性必须是public
public Book_Externalizable(){
}
public Book_Externalizable(String name, double price, boolean status, int rent_days, List<String> list){
this.name = name;
this.price = price;
this.status = status;
this.rent_days = rent_days;
this.list = list;
}
@Override
public void writeExternal(ObjectOutput paramObjectOutput)
throws IOException {
// TODO Auto-generated method stub
paramObjectOutput.writeObject(name);
paramObjectOutput.writeDouble(price);
paramObjectOutput.writeBoolean(status);
paramObjectOutput.writeInt(rent_days);
paramObjectOutput.writeObject(list);
}
@Override
public void readExternal(ObjectInput paramObjectInput) throws IOException,
ClassNotFoundException {
// TODO Auto-generated method stub
name = (String)paramObjectInput.readObject();
price = paramObjectInput.readDouble();
status = paramObjectInput.readBoolean();
rent_days = paramObjectInput.readInt();
list = (List<String>)paramObjectInput.readObject();
}
public static String getNote() {
return note;
}
public static void setNote(String note) {
Book_Externalizable.note = note;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public boolean isStatus() {
return status;
}
public void setStatus(boolean status) {
this.status = status;
}
public int getRent_days() {
return rent_days;
}
public void setRent_days(int rent_days) {
this.rent_days = rent_days;
}
public List<String> getList() {
return list;
}
public void setList(List<String> list) {
this.list = list;
}
@Override
public String toString() {
return "Book [name=" + name + ", price=" + price + ", status=" + status
+ ", rent_days=" + rent_days + ", list=" + list
+ "]";
}
}
/**
* 序列化测试工具
* @author yujie.wang
*
*/
public class Externalizable_Main {
private static FileInputStream fin;
private static FileOutputStream fout;
private static String prefix_Path = "D:\\yujie_serialize\\yujie_externalizable_book";
private static String suffix_file_name = ".txt";
public static void main(String[] args) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
System.out.println("begin to execute");
Book_Externalizable book = new Book_Externalizable("thinking in java", 99.99, true, 10, new ArrayList<String>());
String filePathName = getFileFullPathName("1");
//执行序列化
serializeObject(book,filePathName );
//执行反序列化过程
deSerializeObject(filePathName);
System.out.println("end");
}
/**
* 反序列化
* @param fileName
* @throws IOException
* @throws ClassNotFoundException
*/
public static void deSerializeObject(String fileName) throws IOException, ClassNotFoundException{
File file = createFile(fileName);
if(file == null)
return;
fin = new FileInputStream(file);
ObjectInputStream ois = new ObjectInputStream(fin);
Book_Externalizable book = (Book_Externalizable)ois.readObject();
if(book == null) {
System.out.println("boo == null");
} else {
System.out.println(book.toString());
}
}
/**
* 序列化一个对象
* @param book
* @param fileName
* @throws IOException
*/
public static void serializeObject(Book_Externalizable book, String fileName) throws IOException{
File file = createFile(fileName);
if(file == null)
return;
fout = new FileOutputStream(file);
ObjectOutputStream oos = new ObjectOutputStream(fout);
oos.writeObject(book);
oos.flush();
oos.close();
fout.close();
}
/**
* 创建一个文件
* @param fileName
* @return
* @throws IOException
*/
public static File createFile(String fileName) throws IOException{
if(fileName == null || fileName.isEmpty())
return null;
File file = new File(fileName);
if(!file.exists()){
file.createNewFile();
System.out.println("create a file: "+ fileName);
} else {
System.out.println("file "+ fileName + " already exists");
}
return file;
}
/**
* 获得一个全路径的文件名
* @param fileName
* @return
*/
public static String getFileFullPathName(String fileName){
return prefix_Path + fileName +suffix_file_name;
}
}
运行测试工具类代码输出结果:
begin to execute
create a file: D:\yujie_serialize\yujie_externalizable_book1.txt
file D:\yujie_serialize\yujie_externalizable_book1.txt already exists
Book [name=thinking in java, price=99.99, status=true, rent_days=10, list=[]]
end
总结一下实现Externalizable接口的序列化方法:
(1)自己手动实现writeExternal和readExternal方法
(2)实现Externalizable接口的类必须提供一个公共的无参构造函数