Java 对象序列化

    xiaoxiao2021-03-25  68

    Java平台允许我们在内存中创建可复用的Java对象,但一般情况下,只有当JVM处于运行时,这些对象才可能存在,即,这些对象的生命周期不会比JVM的生命周期更长。 但在现实应用中,就可能要求在JVM停止运行之后能够保存(持久化)指定的对象,并在将来重新读取被保存的对象。Java对象序列化就能够帮助我们实现该功能。

    使用Java对象序列化,在保存对象时,会把其状态保存为一组字节,在未来,再将这些字节组装成对象。 必须注意地是,对象序列化保存的是对象的”状态”,即它的成员变量。由此可知,对象序列化不会关注类中的静态变量。

    Demo:

    public static void main(String[] args) throws Exception { // 对象序列化输出 ObjectOutputStream objOut = new ObjectOutputStream(new FileOutputStream("F:\\1.txt")); Man kole = new Man(); kole.setName("kole"); objOut.writeObject(kole); objOut.close(); // 对象序列化输入 ObjectInputStream objIn = new ObjectInputStream(new FileInputStream("F:\\1.txt")); Object newMan = objIn.readObject(); if (newMan instanceof Man){ System.out.println(((Man)newMan).getName()); } objIn.close(); } // 可被序列化的对象 public class Man implements Serializable{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } }

    为什么一个类要实现Serializable接口?

    // ObjectOutputStream源码 //.. if (obj instanceof String) { writeString((String) obj, unshared); } else if (cl.isArray()) { writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { writeEnum((Enum) obj, desc, unshared); } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } else { // 非String、数组、枚举、序列化对象直接报错 if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } } //..

    transient

    当某个字段被声明为transient后,默认序列化机制就会忽略该字段。

    public class Man implements Serializable { // .. // 此字段将不会被序列化 private transient double money; // .. }

    writeObject()&readObject()

    声明为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()... }

    why?

    // 如果自己实现writeObject; 就根据自己的方法实现 // 因此自己的方法中需要实现默认writeObject的方法。 if (slotDesc.hasWriteObjectMethod()) { PutFieldImpl oldPut = curPut; curPut = null; SerialCallbackContext oldContext = curContext; if (extendedDebugInfo) { debugInfoStack.push( "custom writeObject data (class \"" + slotDesc.getName() + "\")"); } try { curContext = new SerialCallbackContext(obj, slotDesc); bout.setBlockDataMode(true); // 调用自定义的writeObject方法 slotDesc.invokeWriteObject(obj, this); bout.setBlockDataMode(false); bout.writeByte(TC_ENDBLOCKDATA); } finally { curContext.setUsed(); curContext = oldContext; if (extendedDebugInfo) { debugInfoStack.pop(); } } curPut = oldPut; } else { // 调用默认的写方法 defaultWriteFields(obj, slotDesc); }

    Externalizable

    无论是使用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()

    当序列化的对象是单例模式时, 可通过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()中返回的对象直接替换在反序列化过程中创建的对象。

    转载请注明原文地址: https://ju.6miu.com/read-33703.html

    最新回复(0)