序列化给传递对象和报文带来了方便,如果没有序列化就没有系统间的交互,所以序列化非常重要。有些场景不需要把所有的属性都传递出去,所以需要针对实际情况定制化对象的序列化内容。针对定制化,Java提供了一接口Externalizable。
import java.io.Externalizable;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectInputStream;
import java.io.ObjectOutput;
import java.io.ObjectOutputStream;
public class Test {
public static void main(String[] args) throws Exception {
testPo po = new testPo(18, "小明");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("F://testPo.txt"));
out.writeObject(po);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("F://testPo.txt"));
testPo po2 = (testPo)in.readObject();
System.out.println(po2.toString());
in.close();
}
}
class testPo implements Externalizable {
private int i;
private String str;
public testPo(){
System.out.println("testPo : 不带参数的构造方法");
}
public testPo(int i, String str){
this.i = i;
this.str = str;
System.out.println("testPo : 带参数的构造方法");
}
public String toString() {
return str + " " +i;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
System.out.println("testPo.writeExternal");
out.writeObject(str);
out.writeInt(i);
}
@Override
public void readExternal(ObjectInput in) throws IOException,
ClassNotFoundException {
// TODO Auto-generated method stub
System.out.println("testPo.readExternal");
str = (String)in.readObject();
i = in.readInt();
}
}
输出结果:
Externalizable接口继承自Serialiazable接口,且有两个抽象方法,即实例中的writeExternal(arg)和readExternal(arg)。看输出结果可以看出:
(1)、对象序列化时,会自动调用writeExternal(arg)方法,此方法用于定制序列化的内容,即对象的什么属性需要序列化,什么属性不需要序列化;针对不需要序列化的属性就没必要调用out.writeXX()方法;另外,还可以在该方法中自定义属性的内容。
(2)、对象反序列化时,会自动调用类中不带参数的构造函数,意思是会重新生成一个新的类对象(新对象的任何属性都没有值);这点与实现Serializable接口的类完全不同。
(3)、对象反序列化时,会自动调用readExternal(arg)方法,此方法用于给新生成的类对象赋值;这里可以在两个方法里把属性(int)不序列化(注释掉),你会发现结果反序列化结果中,属性(int)的值为0,即使开始构造对象时是赋值的。
所以,实现Externalizable接口的类,完全可以根据场景定制序列化内容。
当然,如果嫌这种方法麻烦,需要在方法里单独定制化内容,可以使用transient关键字。
transient是Java关键字之一,可以用来修饰属性,可以防止属性被序列化。
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class Test {
public static void main(String[] args) throws Exception {
testA A = new testA("hellow", "123456789");
ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream("F://testA.txt"));
out.writeObject(A);
out.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream("F://testA.txt"));
testA A1 = (testA)in.readObject();
System.out.println(A1.toString());
in.close();
}
}
class testA implements Serializable{
/**
*
*/
private static final long serialVersionUID = 1L;
private String account;
private transient String passWord;
public testA(String account,String passWord){
this.account = account;
this.passWord = passWord;
}
public String toString() {
return account + " " + passWord;
}
}
注意:由于Externalizable对象在默认情况下不保存它们的任何属性(不调用任何out.wirteXX()方法),所以transient关键字只能和Serializable对象一起使用。