Java除了Serializable,还有Externalizable

578 阅读2分钟

弄明白Externalizable接口之前,需要先了解Java序列化和反序列化的原理,可参考这篇# Serializable序列化与反序列化原理

1.Externalizable

1.序列化

其实了解过序列化原理后,会发现在writeOrdinaryObject()方法中,进行了逻辑判断,如果实现了Externalizable接口就进入了writeExternalData()方法。

private void writeOrdinaryObject(Object obj,
                               ObjectStreamClass desc,
                               boolean unshared)
  throws IOException
{
  if (extendedDebugInfo) {
      debugInfoStack.push(
          (depth == 1 ? "root " : "") + "object (class "" +
          obj.getClass().getName() + "", " + obj.toString() + ")");
  }
  try {
      desc.checkSerialize();

      bout.writeByte(TC_OBJECT);
      writeClassDesc(desc, false);
      handles.assign(unshared ? null : obj);
      if (desc.isExternalizable() && !desc.isProxy()) {//逻辑判断
          writeExternalData((Externalizable) obj);//实现了Externalizable接口,进入此方法
      } else {
          writeSerialData(obj, desc);
      }
  } finally {
      if (extendedDebugInfo) {
          debugInfoStack.pop();
      }
  }
}

进入writeExternalData()方法。

private void writeExternalData(Externalizable obj) throws IOException {
    PutFieldImpl oldPut = curPut;
    curPut = null;

    if (extendedDebugInfo) {
        debugInfoStack.push("writeExternal data");
    }
    SerialCallbackContext oldContext = curContext;
    try {
        curContext = null;
        if (protocol == PROTOCOL_VERSION_1) {
            obj.writeExternal(this);
        } else {
            bout.setBlockDataMode(true);
            obj.writeExternal(this);//调用了实现的writeExternal方法
            bout.setBlockDataMode(false);
            bout.writeByte(TC_ENDBLOCKDATA);
        }
    } finally {
        curContext = oldContext;
        if (extendedDebugInfo) {
            debugInfoStack.pop();
        }
    }

    curPut = oldPut;
}

会发现并没有做任何复杂的处理,就是直接调用实现了Externalizable接口的writeExternal()方法。

2.反序列化

了解过反序列化原理后,会发现在readOrdinaryObject()方法中,进行了逻辑判断,如果实现了Externalizable接口就进入了readExternalData()方法。

private Object readOrdinaryObject(boolean unshared)
    throws IOException
{
    if (bin.readByte() != TC_OBJECT) {
        throw new InternalError();
    }

    ObjectStreamClass desc = readClassDesc(false);
    desc.checkDeserialize();

    Class<?> cl = desc.forClass();
    if (cl == String.class || cl == Class.class
            || cl == ObjectStreamClass.class) {
        throw new InvalidClassException("invalid class descriptor");
    }

    Object obj;
    try {
        obj = desc.isInstantiable() ? desc.newInstance() : null;
    } catch (Exception ex) {
        throw (IOException) new InvalidClassException(
            desc.forClass().getName(),
            "unable to create instance").initCause(ex);
    }

    passHandle = handles.assign(unshared ? unsharedMarker : obj);
    ClassNotFoundException resolveEx = desc.getResolveException();
    if (resolveEx != null) {
        handles.markException(passHandle, resolveEx);
    }

    if (desc.isExternalizable()) {//逻辑判断
        readExternalData((Externalizable) obj, desc);//实现了Externalizable接口,进入此方法
    } else {
        readSerialData(obj, desc);
    }

    handles.finish(passHandle);

    if (obj != null &&
        handles.lookupException(passHandle) == null &&
        desc.hasReadResolveMethod())
    {
        Object rep = desc.invokeReadResolve(obj);
        if (unshared && rep.getClass().isArray()) {
            rep = cloneArray(rep);
        }
        if (rep != obj) {
            // Android-removed: ObjectInputFilter logic, to be reconsidered. http://b/110252929
            /*
            // Filter the replacement object
            if (rep != null) {
                if (rep.getClass().isArray()) {
                    filterCheck(rep.getClass(), Array.getLength(rep));
                } else {
                    filterCheck(rep.getClass(), -1);
                }
            }
            */
            handles.setObject(passHandle, obj = rep);
        }
    }

    return obj;
}

进入readExternalData()方法。

private void readExternalData(Externalizable obj, ObjectStreamClass desc)
    throws IOException
{
    SerialCallbackContext oldContext = curContext;
    if (oldContext != null)
        oldContext.check();
    curContext = null;
    try {
        boolean blocked = desc.hasBlockExternalData();
        if (blocked) {
            bin.setBlockDataMode(true);
        }
        if (obj != null) {
            try {
                obj.readExternal(this);//调用了实现的readExternal方法
            } catch (ClassNotFoundException ex) {
                /*
                 * In most cases, the handle table has already propagated
                 * a CNFException to passHandle at this point; this mark
                 * call is included to address cases where the readExternal
                 * method has cons'ed and thrown a new CNFException of its
                 * own.
                 */
                 handles.markException(passHandle, ex);
            }
        }
        if (blocked) {
            skipCustomData();
        }
    } finally {
        if (oldContext != null)
            oldContext.check();
        curContext = oldContext;
    }
}

会发现也并没有做任何复杂的处理,就是直接调用实现了Externalizable接口的readExternal()方法。

2.Externalizable VS Serializable

第一点

  • Serializable 是标识接口
  • Externalizable 接口继承于Serializable,实现该接口,需要重写readExternal和writeExternal方法

第二点

Serializable有两种方式进行对象的序列化

  • 采用默认序列化方式,将非transatient和非static的属性进行序列化
  • 编写readObject和writeObject完成部分属性的序列化

Externalizable接口只能通过实现writeExternal和readExternal方法,在方法中实现序列化和反序列化操作。

第三点

Externalizable接口的实现方式一定要有默认的无参构造函数

3.总结

我想Externalizable存在的意义,可能就是为了能完全自定义序列化的过程,来解决Serializable中序列化和反序列化时大量使用反射导致的性能问题吧!