Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。 但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。
使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。 必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。
当某个字段被声明为transient后,默认序列化机制就会忽略该字段。
public class Man implements Serializable { // .. // 此字段将不会被序列化 private transient double money; // .. }声明为transitive的字段不一定无法将其序列化, 可通过writeObject()与readObject()方法实现自序列化而跳过transitive关键字;
public class Man implements Serializable{ private String name; private transient double money; // 只要添加writeObject和readObject方法即可 private void writeObject(ObjectOutputStream out) throws IOException { out.defaultWriteObject(); out.writeDouble(this.money); } private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException { in.defaultReadObject(); this.money = in.readDouble(); } // get()、set()... }无论是使用transient关键字,还是使用writeObject()和readObject()方法,其实都是基于Serializable接口的序列化。 JDK中提供了另一个序列化接口–Externalizable
实现该接口之后,之前基于Serializable接口的序列化机制就将失效。
public class Man implements Externalizable { private String name; private transient double money; // 需要构造函数(没有报错no valid constructor) public Man(){ } @Override public void writeExternal(ObjectOutput out) throws IOException { out.writeDouble(this.money); } @Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException { this.money = in.readDouble(); } } // Externalizable 继承于Serializable public interface Externalizable extends java.io.Serializable // .. // 如果实现Externalizable则走自定义的方法 if (desc.isExternalizable() && !desc.isProxy()) { // 自定义序列化 // 内部调用writeExternal(this); writeExternalData((Externalizable) obj); } else { // 系统实现的序列化 writeSerialData(obj, desc); }当序列化的对象是单例模式时, 可通过readResolve方法返回一个对象, 而替换序列化读取的对象。
public class Man implements Serializable { private static Man singleThiz = null; private String name; private transient double money; private Man() { } // 实现读取结果方法 private Object readResolve() throws ObjectStreamException { return Man.getInstance(); } public static Man getInstance() { if (Man.singleThiz == null) { synchronized (Man.class) { if (Man.singleThiz == null) { Man.singleThiz = new Man(); } } } return Man.singleThiz; } } // 是否存在ReadResolveMethod方法 if (obj != null && handles.lookupException(passHandle) == null && desc.hasReadResolveMethod()){ // 获得readResolve得到的方法 Object rep = desc.invokeReadResolve(obj); if (unshared && rep.getClass().isArray()) { rep = cloneArray(rep); } // 生成的obj对象与readResolve方法返回不同,进行替换 if (rep != obj) { handles.setObject(passHandle, obj = rep); } }无论是实现Serializable接口,或是Externalizable接口,当从I/O流中读取对象时,readResolve()方法都会被调用到。实际上就是用readResolve()中返回的对象直接替换在反序列化过程中创建的对象。