序列化就是将一个对象(标志对象的类型)及其状态转换为字节码,以文件,内存,数据库等形式保存起来。反序列化就是在适当的时候通过读取这些文件,得到原有状态的对象。
序列化可以通过实现两种接口来实现,即Serializable和Externalizable这两个接口。
Serializable开发相对简单,其读取方式都是但速度慢,而且序列化后的数据文件比较大。
eg1:
package com.lmr.io;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class SerialPerson implements Serializable {
/**
*
*/
private static final long serialVersionUID = -1586881727918562464L;
// private transient int id;// transient类型,瞬时变量,不会被序列化
private int id;
private static int count = 0;
private String name;
private int age;
private String password;
public SerialPerson(String name, int age, String password) {
// TODO Auto-generated constructor stub
id = ++count;
this.name = name;
this.age = age;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
@Override
public String toString() {
return "SerialPerson [id=" + id + ", name=" + name + ", age=" + age + ", password=" + password + "]";
}
//在序列化前执行,可对要进行序列化的对象进行处理
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException{
in.defaultReadObject();
// password = "456";
}
//在反序列化后执行
private void writeObject(ObjectOutputStream out) throws IOException {
out.defaultWriteObject();
// out.writeObject(password);
}
}
package com.lmr.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.OutputStream;
public class TestSerializable {
public static void main(String[] args) throws IOException {
String headpath="D:\\TestIOData\\";
WriteMethod(headpath+"serialperson.txt");
ReadMethod(headpath+"serialperson.txt");
}
public static void WriteMethod(String path) throws IOException{
FileOutputStream fos=new FileOutputStream(path);
ObjectOutputStream oos=new ObjectOutputStream(fos);
for(int i=1;i<10;i++){
SerialPerson sp=new SerialPerson("A"+i, 10+i,"aBc"+i);
oos.writeObject(sp);
}
// List<SerialPerson> splist=new ArrayList<>();
// for(int i=1;i<10;i++){
// SerialPerson sp=new SerialPerson("A"+i, 10+i,"aBc"+i);
// splist.add(sp);
// }
// oos.writeObject(splist);//直接写入对象list,相对应的读取的时候转换的格式也要是list
oos.close();
fos.close();
}
public static void ReadMethod(String path) throws IOException{
FileInputStream fis=new FileInputStream(path);
ObjectInputStream ois=new ObjectInputStream(fis);
while(true){//使用处理异常的方式来判断文件是否结束
try {
SerialPerson sp=(SerialPerson) ois.readObject();//文件读取完毕后,会抛异常
System.out.println(sp.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("文件读取完毕!");
break;
}
}
// try {
// List<SerialPerson> splist=(List<SerialPerson>) ois.readObject();//这里反序列化后的转换格式要跟序列化之前的格式一样
//
// for(SerialPerson sp:splist){
// System.out.println(sp.toString());
// }
//
// } catch (ClassNotFoundException e) {
// // TODO Auto-generated catch block
// e.printStackTrace();
// }
ois.close();
fis.close();
}
}
结果:
SerialPerson [id=1, name=A1, age=11, password=aBc1]
SerialPerson [id=2, name=A2, age=12, password=aBc2]
SerialPerson [id=3, name=A3, age=13, password=aBc3]
SerialPerson [id=4, name=A4, age=14, password=aBc4]
SerialPerson [id=5, name=A5, age=15, password=aBc5]
SerialPerson [id=6, name=A6, age=16, password=aBc6]
SerialPerson [id=7, name=A7, age=17, password=aBc7]
SerialPerson [id=8, name=A8, age=18, password=aBc8]
SerialPerson [id=9, name=A9, age=19, password=aBc9]
文件读取完毕!
若是id的类型改为transient或者为静态变量static,id都将不参与序列化。在反序列化后,id的值为默认值。
SerialPerson [id=0, name=A1, age=11, password=aBc1]
SerialPerson [id=0, name=A2, age=12, password=aBc2]
SerialPerson [id=0, name=A3, age=13, password=aBc3]
SerialPerson [id=0, name=A4, age=14, password=aBc4]
SerialPerson [id=0, name=A5, age=15, password=aBc5]
SerialPerson [id=0, name=A6, age=16, password=aBc6]
SerialPerson [id=0, name=A7, age=17, password=aBc7]
SerialPerson [id=0, name=A8, age=18, password=aBc8]
SerialPerson [id=0, name=A9, age=19, password=aBc9]
文件读取完毕!
Externalizable是继承自Serializable。此接口定义了两个方法,只要实现这两个方法,完成对象的读取。要实现Externalizable接口的类必须有默认构造方法。
相比于Serializable,Externalizable序列化的速度更快,序列化之后的数据更小,但读和取都需要开发人员自行实现。
eg2:
package com.lmr.io;
import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;
import java.io.ObjectStreamException;
public class ExternalPerson implements Externalizable{
private int id=0;
private static int count=0;
private String name="";
private int age=0;
private String password="";
public ExternalPerson() {//无参构造器,必须有,不然无法进行反序列化
// TODO Auto-generated constructor stub
// System.out.println("必须要有无参构造器!!!!");
}
public ExternalPerson(String name,int age,String password) {
// TODO Auto-generated constructor stub
id=++count;
this.name=name;
this.age=age;
this.password=password;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
@Override
public String toString() {
return "ExternalPerson [id=" + id + ", name=" + name + ", age=" + age + ", password=" + password + "]";
}
// 在writeExternal之前执行,可以在序列化前对对象进行一些处理,比如加密。
private Object writeReplace() throws ObjectStreamException {
this.setPassword(new StringBuffer(password).reverse().toString());//这里对password进行了反转处理
System.out.println("writeReplace");
return this;
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
// TODO Auto-generated method stub
out.writeObject(id);
out.writeObject(name);
out.writeObject(age);
out.writeObject(password);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
// TODO Auto-generated method stub
id=(int) in.readObject();
name=(String) in.readObject();
age=(int) in.readObject();
password=(String) in.readObject();
}
// 在readExternal之后执行,可以在反序列化后对得到的对象进行一些处理,比如解密
private Object readResolve() throws ObjectStreamException {
//此处可以写对password的解密处理
System.out.println("readresolve");
return this;
}
}
package com.lmr.io;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class TestExternalizable {
public static void main(String[] args) throws IOException {
String headpath = "D:\\TestIOData\\";
EWriteMethod(headpath + "externalperson.txt");
EReadMethod(headpath + "externalperson.txt");
}
public static void EWriteMethod(String path) throws IOException {
FileOutputStream fos = new FileOutputStream(path);
ObjectOutputStream oos = new ObjectOutputStream(fos);
for (int i = 1; i < 10; i++) {
ExternalPerson ep = new ExternalPerson("A" + i, 10 + i, "ABCD" + i);
System.out.println(ep.toString());
oos.writeObject(ep);
// ep.writeExternal(oos);
}
System.out.println("----***************---------");
oos.close();
fos.close();
}
public static void EReadMethod(String path) throws IOException {
FileInputStream fis = new FileInputStream(path);
ObjectInputStream ois = new ObjectInputStream(fis);
while (true) {// 使用处理异常的方式来判断文件是否结束
try {
ExternalPerson ep = (ExternalPerson) (ois.readObject());// 文件读取完毕后,会抛异常
System.out.println(ep.toString());
} catch (Exception e) {
// TODO Auto-generated catch block
// e.printStackTrace();
System.out.println("文件读取完毕!");
break;
}
}
ois.close();
fis.close();
}
}
结果:通过使用writeReplace()和readResolve()来对序列化中的对象数据进行处理,writeExternal()可以决定哪些数据参与序列化(跟数据是否被transient修饰没关系),readExternal()则是进行反序列化去解数据。
ExternalPerson [id=1, name=A1, age=11, password=ABCD1]
ExternalPerson [id=2, name=A2, age=12, password=ABCD2]
ExternalPerson [id=3, name=A3, age=13, password=ABCD3]
ExternalPerson [id=4, name=A4, age=14, password=ABCD4]
ExternalPerson [id=5, name=A5, age=15, password=ABCD5]
ExternalPerson [id=6, name=A6, age=16, password=ABCD6]
ExternalPerson [id=7, name=A7, age=17, password=ABCD7]
ExternalPerson [id=8, name=A8, age=18, password=ABCD8]
ExternalPerson [id=9, name=A9, age=19, password=ABCD9]
----***************---------
ExternalPerson [id=1, name=A1, age=11, password=1DCBA]
ExternalPerson [id=2, name=A2, age=12, password=2DCBA]
ExternalPerson [id=3, name=A3, age=13, password=3DCBA]
ExternalPerson [id=4, name=A4, age=14, password=4DCBA]
ExternalPerson [id=5, name=A5, age=15, password=5DCBA]
ExternalPerson [id=6, name=A6, age=16, password=6DCBA]
ExternalPerson [id=7, name=A7, age=17, password=7DCBA]
ExternalPerson [id=8, name=A8, age=18, password=8DCBA]
ExternalPerson [id=9, name=A9, age=19, password=9DCBA]
文件读取完毕!