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 就是输出
扫描二维码关注公众号,回复:
301300 查看本文章