1、实现 Serializable 接口,默认的序列化方式
2、实现 Externalizable 接口,这个接口要实现两个方法
void writeExternal(ObjectOutput var1) throws IOException;
void readExternal(ObjectInput var1) throws IOException, ClassNotFoundException;
分别在调用序列化和反序列化的时候进行调用。这样就可以自己定制自己的序列化方式,如加密后序列化,某个属性不用序列化(transient 也可以实现)
public class SerrializableTest implements Externalizable{
private String name;
private int age;
private String email;
@Override
public void writeExternal(ObjectOutput out) throws IOException {
System.out.println("write");
//write 和read 要顺序一致
out.writeObject(email);
out.writeInt(age);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
System.out.println("read");
//write 和read 要顺序一致
this.email = (String)in.readObject();
this.age = in.readInt();
}
public static void main(String[] args) throws IOException,SecurityException,ClassNotFoundException{
String filePath = "a";
SerrializableTest t = new SerrializableTest("mayihan",1,"mail");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(new File(filePath)));
o.writeObject(t);
o.flush();
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(filePath)));
SerrializableTest tt = (SerrializableTest)in.readObject();
System.out.println(tt);
}
@Override
public String toString() {
return name+"--"+age+"-"+email;
}
public SerrializableTest(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
/**
* 必须要有默认的构造器
*/
public SerrializableTest() {
}
}
输出:
write
read
null--1-mail
上面代码中只序列化了age 和 email,可以在实现接口方法中添加加密解密的实现等,就添加了功能实现。
注意:必须要有默认的构造器。
与Serializable 区别:
Serializable 反序列化是用二进制位来构造的,不要调用构造器。而Externalizable所有普通的置信构造器都会被调用(包括在字段定义时的初始化),然后调用readExternal 方法。
3、transient
Serializable 默认所有的属性都会被序列化,Externalizable 要自己手动序列化不会自动序列化。当在操作 Serializable 对象时,可以使用transient 关键字关闭某个属性,意思说:不用自动序列化和恢复,自己手动处理。上面的手动序列化就实现了transient 实现。
4、实现Serializable接口,实现手动序列化。
实现Serializable接口后,添加方法(主意方法是私有的):
/**
* 添加 序列化方法
* @param outputStream
* @throws IOException
*/
private void writeObject(ObjectOutputStream outputStream) throws IOException{}
/**
* 添加反序列化方法
* @param inputStream
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream inputStream) throws IOException,ClassNotFoundException{}
在调用序列化、反序列化时这两个方法会被调用(方法是私有的,后面通过反射实现调用私有方法)。
示例:
public class SerrializableTest implements Serializable{
private String name;
private int age;
private String email;
/**
* 添加 序列化方法
* @param outputStream
* @throws IOException
*/
private void writeObject(ObjectOutputStream outputStream) throws IOException{
System.out.println("write object");
//write 和read 要顺序一致
outputStream.writeInt(age);
outputStream.writeObject(email);
}
/**
* 添加反序列化方法
* @param in
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream in) throws IOException,ClassNotFoundException{
System.out.println("read object");
//write 和read 要顺序一致
this.age = in.readInt();
this.email = (String)in.readObject();
}
public static void main(String[] args) throws IOException,SecurityException,ClassNotFoundException{
String filePath = "a";
SerrializableTest t = new SerrializableTest("mayihan",1,"mail");
ByteArrayOutputStream stream = new ByteArrayOutputStream();
ObjectOutputStream o = new ObjectOutputStream(new FileOutputStream(new File(filePath)));
o.writeObject(t);
o.flush();
o.close();
ObjectInputStream in = new ObjectInputStream(new FileInputStream(new File(filePath)));
SerrializableTest tt = (SerrializableTest)in.readObject();
System.out.println(tt);
}
@Override
public String toString() {
return name+"--"+age+"-"+email;
}
public SerrializableTest(String name, int age, String email) {
this.name = name;
this.age = age;
this.email = email;
}
}
运行结果,name 没有序列 :
write object
read object
null--1-mail
还有一点是:在writeObject(ObjectOutputStream outputStream) 中调用 outputStream.defaultWriteObject(); 方法,就又实现了默认的序列化。
/**
* 添加 序列化方法
* @param outputStream
* @throws IOException
*/
private void writeObject(ObjectOutputStream outputStream) throws IOException{
System.out.println("write object");
//使用默认输出方式
outputStream.defaultWriteObject();
}
/**
* 添加反序列化方法
* @param inputStream
* @throws IOException
* @throws ClassNotFoundException
*/
private void readObject(ObjectInputStream inputStream) throws IOException,ClassNotFoundException{
System.out.println("read object");
//使用默认输入方式
inputStream.defaultReadObject();
}
上面两个方法被定义成私有了,是在什么时候调用的呢? 通过debug 方式来查看
主要是通过反射来实现的,主要代码是在ObjectOutputStream.invokeWriteObject 方法,代码如下:
void invokeWriteObject(Object obj, ObjectOutputStream out)
throws IOException, UnsupportedOperationException
{
requireInitialized();
if (writeObjectMethod != null) {
try {
writeObjectMethod.invoke(obj, new Object[]{ out });
} catch (InvocationTargetException ex) {
Throwable th = ex.getTargetException();
if (th instanceof IOException) {
throw (IOException) th;
} else {
throwMiscException(th);
}
} catch (IllegalAccessException ex) {
// should not occur, as access checks have been suppressed
throw new InternalError(ex);
}
} else {
throw new UnsupportedOperationException();
}
}
解析:
运行到此处:writeObjectMethod 就是自定义的writeObject 方法。
obj 就是当前要序列化的对象
out 就是输出