【JDK源码分析】03-对象自定义序列化

在前两篇文章中分析了序列化与反序列化的流程,下面说一下Serializable中如果定义private void writeObject(ObjectOutputStrean os)和private void readObject(ObjectInputStrean os)的作用也就是在《对象序列化》那篇文章中分析的ObjectStreamClass中定义的两个成员变量writeObjectMethod和readObjectMethod。

在writeObject0方法中有一段代码

Class<?> repCl;
desc = ObjectStreamClass.lookup(cl, true);
if (!desc.hasWriteReplaceMethod() ||
    (obj = desc.invokeWriteReplace(obj)) == null ||
    (repCl = obj.getClass()) == cl)
{
    break;
}
cl = repCl;

可以看到可以在对象中定义private Object writeReplace()方法用来替换原始的可序列化对象。

private void writeSerialData(Object obj, ObjectStreamClass desc)
    throws IOException
{
    ObjectStreamClass.ClassDataSlot[] slots = desc.getClassDataLayout();
    for (int i = 0; i < slots.length; i++) {
        ObjectStreamClass slotDesc = slots[i].desc;
        if (slotDesc.hasWriteObjectMethod()) {//如果有writeObject()方法则用对象自定义的序列化方法
            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);
                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);
        }
    }
}

如果定定义了writeObject()方法则会调用自定义的而不是默认的序列化方法defaultWriteFields(obj, slotDesc)。

同样在ObjectInputStream中readSerialData()方法中有如下代码

if (obj == null || handles.lookupException(passHandle) != null) {
    defaultReadFields(null, slotDesc); // skip field values
} else if (slotDesc.hasReadObjectMethod()) {
    ThreadDeath t = null;
    boolean reset = false;
    SerialCallbackContext oldContext = curContext;
    if (oldContext != null)
        oldContext.check();
    try {
        curContext = new SerialCallbackContext(obj, slotDesc);

        bin.setBlockDataMode(true);
        slotDesc.invokeReadObject(obj, this);
    

我们就知道了如果类中定义了writeObject和readObject方法就不会用默认的序列化和反序列化方法而是我们定义的这两个方法。

下面写个例子测试一下

public class Person extends Human implements Serializable {
    public String xyz = "lmn";
    public String name;
    public int age = 55;
    public int length = 66;
    public int width = 77;
    public static Person single=new Person("hero");

    public Person(String name) {
        super(name);
        this.name = name;
    }
    private Object readResolve() {
        return single;
    }
    private void writeObject(ObjectOutputStream os) throws IOException {
        os.writeObject("自定义writeObject");
        os.defaultWriteObject();
    }
    private void readObject(ObjectInputStream is) throws IOException, ClassNotFoundException {
        System.out.println(is.readObject());
        is.defaultReadObject();
    }
}

测试用例

private static void testWriteObject() throws IOException, ClassNotFoundException {
        ByteArrayOutputStream baos=new ByteArrayOutputStream();
        ObjectOutputStream oos=new ObjectOutputStream(baos);
        Person p=Person.single;
        oos.writeObject(p);
        System.out.println(baos.toString());
        ByteArrayInputStream bais=new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois=new ObjectInputStream(bais);
        Object readObject = ois.readObject();
        System.out.println(readObject==p);
    }

结果


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值