本文共 7890 字,大约阅读时间需要 26 分钟。
在日常开发中,前端与后端的交互,系统之间的远程调用都需要使用到序列化技术,在java中使用序列化非常简单,只需要将被序列化的对象的类实现Java.io.Serializable接口即可。
对于实现序列化接口的类,我们需要注意两点:下面是通过两个小案例来证明:
public class SeriaTest implements Serializable{ private static final long serialVersionUID = 1L; private static Integer count = 10; public static void main(String[] args) { try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.obj")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.obj"))) { oos.writeObject(new SeriaTest()); count = 20; SeriaTest seriaTest = (SeriaTest) ois.readObject(); System.out.println(seriaTest.count); } catch (Exception e) { System.out.println("序列化反序列化时出现异常:"+e); } }}
这段代码的运行结果为20,说明静态变量不会被序列化。
public class Fu { public String fu; public String getFu() { return fu; } public void setFu(String fu) { this.fu = fu; }}public class Zi extends Fu implements Serializable{ private static final long serialVersionUID = 1L; public String zi; public Zi(){ fu = "fu"; zi = "zi"; } public String getZi() { return zi; } public void setZi(String zi) { this.zi = zi; }}public class SeriaTest{ public static void main(String[] args) { public static void main(String[] args) { try (ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.obj")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.obj"))){ oos.writeObject(new Zi()); Zi zi = (Zi) ois.readObject(); System.out.println(zi.fu); System.out.println(zi.zi); } catch (Exception e) { } }}
这段代码的运行结果为null,zi。验证了上面的第二点。
将对象序列化实际上调用的就是ObjectOutputStream的wirteObject方法,跟踪源代码可知能被序列化的对象除了是实现Serializable接口的对象,还可以是String,数组或者枚举对象:
if (paramObject instanceof String) { writeString((String) paramObject, paramBoolean);} else if (((Class) localObject2).isArray()) { writeArray(paramObject, localObjectStreamClass, paramBoolean);} else if (paramObject instanceof Enum) { writeEnum((Enum) paramObject, localObjectStreamClass,paramBoolean);} else if (paramObject instanceof Serializable) { writeOrdinaryObject(paramObject, localObjectStreamClass,paramBoolean);}
再继续跟进writeOrdinaryObject方法,我们会发现会有这么一段逻辑:
if ((paramObjectStreamClass.isExternalizable()) && (!(paramObjectStreamClass.isProxy()))) writeExternalData((Externalizable) paramObject);else writeSerialData(paramObject, paramObjectStreamClass);
先判断是不是实现了Externalizable接口(这个是Serializable的子接口,这里先不管,后面会解释),如果不是,则执行writeSerialData方法。跟进去:
if (localObjectStreamClass.hasWriteObjectMethod()) { ********省略******* localObjectStreamClass.invokeWriteObject(paramObject, this); ********省略******* } else { defaultWriteFields(paramObject, localObjectStreamClass);}
我们发现源代码先判断了一下这个需要被序列化的类中有没有writeObject这个方法,如果有,那么就执行,如果没有,那么就执行默认的序列化方法。对于这个writeObject方法,有以下几个要求:
返回值类型必须为void
只有满足了以上三点,在序列化对象的时候,才会执行我们自定义的序列化方法。当然,我们除了可以重写writeObject方法,我们还可以重写readObject,readObjectNoData,writeReplace,readResolve等方法,这些方法之间有什么联系,有什么作用呢?我们通过一段代码来探索一下:
public class SeriaTest implements Serializable{ private static final long serialVersionUID = 1L; public Integer count = 10; public SeriaTest(Integer count){ this.count = count; } public static void main(String[] args) { try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.obj")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.obj"))) { oos.writeObject(new SeriaTest(20)); SeriaTest seriaTest = (SeriaTest) ois.readObject(); System.out.println(seriaTest.count); } catch (Exception e) { System.out.println("序列化反序列化时出现异常:"+e); } } private void writeObject(ObjectOutputStream oos) throws IOException{ System.out.println("序列化前执行了自定义的writeObject方法"); oos.defaultWriteObject(); System.out.println("序列化后执行了自定义的writeObject方法"); } private Object writeReplace() { System.out.println("序列化时执行了自定义的writeReplace方法"); SeriaTest s = new SeriaTest(10); return s; }}
执行结果如下:
序列化时执行了自定义的writeReplace方法序列化前执行了自定义的writeObject方法序列化后执行了自定义的writeObject方法10
根据执行结果我们我们可以知道,在对象序列化的时候,会先去执行被序列化的类中的writeReplace方法,再执行writeObject方法,如果重写了writeReplace方法,那么被序列化的对象就是这个方法的返回值,而writeObject方法主要作用就是在序列化前后可以做处理操作。
对应的读操作的方法分别是readResolve方法和readObject方法,将上面的代码再完善一下:public class SeriaTest implements Serializable{ private static final long serialVersionUID = 1L; public Integer count = 10; public SeriaTest(Integer count){ this.count = count; } public static void main(String[] args) { try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.obj")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.obj"))) { oos.writeObject(new SeriaTest(20)); SeriaTest seriaTest = (SeriaTest) ois.readObject(); System.out.println(seriaTest.count); } catch (Exception e) { System.out.println("序列化反序列化时出现异常:"+e); } } private void writeObject(ObjectOutputStream oos) throws IOException{ System.out.println("序列化前执行了自定义的writeObject方法"); oos.defaultWriteObject(); System.out.println("序列化后执行了自定义的writeObject方法"); } private Object writeReplace() { System.out.println("序列化时执行了自定义的writeReplace方法"); SeriaTest s = new SeriaTest(10); return s; } private void readObject(ObjectInputStream ois) throws ClassNotFoundException, IOException{ System.out.println("反序列化前执行了自定义的readObject方法"); ois.defaultReadObject(); System.out.println("反序列化后执行了自定义的readObject方法"); } private Object readResolve(){ System.out.println("反序列化前执行了自定义的readReslove方法"); SeriaTest s = new SeriaTest(30); return s; }}
执行结果符合我们的预期:
序列化时执行了自定义的writeReplace方法序列化前执行了自定义的writeObject方法序列化后执行了自定义的writeObject方法反序列化前执行了自定义的readObject方法反序列化后执行了自定义的readObject方法反序列化前执行了自定义的readReslove方法30
至于readObjectNoData方法,这个比较少见,这个方法的作用就是当一个对象被序列化后,反序列化时可以添加属性。(具体可参考:)
下面我们再来解析一下上面提到的Externalizable接口,这个接口是Serializable接口的子接口,这个接口有两个抽象方法:writeExternal和readExternal,这个两个方法分别对应于writeObject和readObject,不同点在于writeObject和readObject都是私有方法,所以其子类不能复用并且不能复写,而writeExternal和readExternal是共有方法,其子类可以复用并且复写。
public class SeriaTest implements Externalizable{ private String name; private Integer age; public static void main(String[] args) { try(ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("D:\\test.obj")); ObjectInputStream ois = new ObjectInputStream(new FileInputStream("D:\\test.obj")) ) { oos.writeObject(new SeriaTest()); SeriaTest seriaTest = (SeriaTest) ois.readObject(); System.out.println(seriaTest.name); System.out.println(seriaTest.age); } catch (Exception e) { System.out.println("序列化反序列化时出现异常:"+e); } } @Override public void writeExternal(ObjectOutput paramObjectOutput) throws IOException { System.out.println("writeExternal....."); paramObjectOutput.writeInt(18); paramObjectOutput.write("zhangsan".getBytes(Charset.forName("UTF-8"))); } @Override public void readExternal(ObjectInput paramObjectInput) throws IOException, ClassNotFoundException { System.out.println("readExternal....."); age = paramObjectInput.readInt(); name = paramObjectInput.readLine(); }}
执行结果如下:
writeExternal.....readExternal.....zhangsan18
转载地址:http://gfuwa.baihongyu.com/