什么是序列化
对象的序列化一般有两种用途:把对象的字节序列永久地保存到硬盘上,通常存放在一个指定文件中;或者在网络上传送对象的字节序列。而把字节序列恢复为对象的过程称为对象的反序列化。归纳起来,就是把你的数据换个时间和/或换个地方,继续使用换个时间,比如存盘,换个地方,比如网络传输,当然,实现“换个时间/地方用”的方式很多很多。
实现序列化功能的两个接口Serializable 和 Externalizable 详解
(1)Serializable接口
(2)Externalizable接口:该接口继承了Serializable接口,是对Serializable的扩展,并提供了readExternal(ObjectInput in)和writeExternal(ObjectOutout out)两种方法,通过重写这两个方法来实现自身的序列化行为的控制。在对实现了Externalizable的类的对象进行反序列化时,会先调用该类的无参构造函数,若无参构造函数被删除或被设置为private、default或protected时会抛出java.io.InvalidException:no valid construction
Serializable 序列化例子如下:
/**
* 实体类
*/
class Peaple implements Serializable{
private static final long serialVersionUID = 1L;
String name;
String age;
public Peaple(String name,String age){
this.name=name;
this.age=age;
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "name="+name+"age="+age;
}
}
public static void main(String[] args) {
Peaple peaple=new Peaple("mayou","18");
System.out.println(peaple.toString());
try {
ObjectOutputStream objOutput=new ObjectOutputStream(new FileOutputStream("D://mayou.txt"));
objOutput.writeObject(peaple);
objOutput.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D://mayou.txt"));
peaple = (Peaple)ois.readObject();
System.out.println(peaple.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
Externalizable接口是Serializable接口的子接口,在此接口中定义了两个方法,这两个方法的作用如下。
writeExternal(ObjectOutput out):在此方法中指定要保存的属性信息,对象序列化时调用。
readExternal(ObjectInput in):在此方法中读取被保存的信息,对象反序列化时调用。
这两个方法的参数类型是ObjectOutput和ObjectInput,两个接口的定义如下。
ObjectOutput接口定义:
public interface ObjectOutput extends DataOutput
ObjectInput接口定义:
public interface ObjectInput extends DataInput
可以发现以上两个接口分别继承DataOutput和DataInput,这样在这两个方法中就可以像DataOutputStream和DataInputStream那样直接输出和读取各种类型的数据。
如果一个类要使用Externalizable实现序列化时,在此类中必须存在一个无参构造方法,因为在反序列化时会默认调用无参构造实例化对象,如果没有此无参构造,则运行时将会出现异常,这一点的实现机制与Serializable接口是不同的。
范例如下:
public class ExternalizableDemo implements Externalizable{
String name;
String age;
String sex;
public ExternalizableDemo(String name,String age,String sex){
this.name=name;
this.age=age;
this.sex=sex;
}
public ExternalizableDemo(){}
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
out.writeObject(name);
out.writeObject(age);
}
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
//按照 out.writeObject() 的顺序逐一取出
this.name=(String)in.readObject();
this.age=(String)in.readObject();
}
@Override
public String toString() {
// TODO Auto-generated method stub
return "name="+name+"age="+age+"sex="+sex;
}
public static void main(String[] args) {
ExternalizableDemo peaple=new ExternalizableDemo("mayou", "18", "man");
System.out.println(peaple.toString());
try {
ObjectOutputStream objOutput=new ObjectOutputStream(new FileOutputStream("D://mayou.txt"));
objOutput.writeObject(peaple);
objOutput.close();
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D://mayou.txt"));
peaple = (ExternalizableDemo)ois.readObject();
System.out.println(peaple.toString());
} catch (FileNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IOException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
注意事项
-
1.只有实现了Serializable或Externalizable的类的对象才可以实现序列化。
-
2.对象和对象数组都可以实现序列化
-
3.若一个父类实现了Serializable或Externalizable接口,其子类均实现了Serializable或Externalizable接口。
-
4.实现Serializable或Externalizable接口的类应提供无参构造函数
-
5.static的属性和方法不能被序列化,因为static的属性和方法与对象无关,而序列化和反序列化则是针对对象而言的。
-
6.对于不希望被序列化的非static成员和方法可以使用transient关键字标明
-
7.若一个序列化子类的父类是非序列化的,则该子类从父类继承下来的变量将恢复其默认初始值而不被初始化。