Java序列化之Externalizable

Externalizable简介


#这里可以看出 它也是直接继承自Serializable,实现它的类必须复写两个方法:
//#1.writeExternal
//#2.readExternal
public interface Externalizable extends java.io.Serializable {
    /**
     * The object implements the writeExternal method to save its contents
     * by calling the methods of DataOutput for its primitive values or
     * calling the writeObject method of ObjectOutput for objects, strings,
     * and arrays.
     *
     * @serialData Overriding methods should use this tag to describe
     *             the data layout of this Externalizable object.
     *             List the sequence of element types and, if possible,
     *             relate the element to a public/protected field and/or
     *             method of this Externalizable class.
     *
     * @param out the stream to write the object to
     * @exception IOException Includes any I/O exceptions that may occur
     */
    void writeExternal(ObjectOutput out) throws IOException;

    /**
     * The object implements the readExternal method to restore its
     * contents by calling the methods of DataInput for primitive
     * types and readObject for objects, strings and arrays.  The
     * readExternal method must read the values in the same sequence
     * and with the same types as were written by writeExternal.
     *
     * @param in the stream to read data from in order to restore the object
     * @exception IOException if I/O errors occur
     * @exception ClassNotFoundException If the class for an object being
     *              restored cannot be found.
     */
    void readExternal(ObjectInput in) throws IOException, ClassNotFoundException;
}

2.实现Externalizable 的类,源文件如下


package com.serializer.demo.nativenal.domain;


import java.io.Externalizable;
import java.io.IOException;
import java.io.ObjectInput;
import java.io.ObjectOutput;



public class Department implements Externalizable {
    private static final long serialVersionUID = -509314035422L;
    private String departmentId;
    private String departmentName;
    private String password;

//    public void writeExternal(ObjectOutput out) throws IOException {
//        System.out.println("I am going to write ");
//        out.writeObject(departmentId);
//        out.writeObject(departmentName);
//
//    }
//
//    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
//        System.out.println("I am going to read");
//        //注意这里顺序不能反了,怎么顺序写的,怎么顺序读
//        departmentId= (String) in.readObject();
//        departmentName= (String) in.readObject();
        password= (String) in.readObject(); //这里不能读会报错的:
//
//
//    }                                                          // java.io.OptionalDataException
        
                                                          
    public String getDepartmentId() {                     
        return departmentId;                              
    }                                                     
                                                          
    public void setDepartmentId(String departmentId) {    
        this.departmentId = departmentId;                 
    }                                                     


    public void writeExternal(ObjectOutput out) throws IOException {
        System.out.println("I am going to write ");

//如果以字节的方式写入时,由于是连续的,这里必须要写入字节长度,才能保证反序列化时,知道从哪个地方切断
        byte[] bytes = departmentId.getBytes();
        out.writeInt(bytes.length);
        out.write(bytes);
        bytes = departmentName.getBytes();
        out.writeInt(bytes.length);
        out.write(bytes);
    }

    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        System.out.println("I am going to read");
        //这里不能用readObject来读,会报错,因此
//        departmentId= (String) in.readObject();
//        departmentName= (String) in.readObject();

//这里与上述写的顺序和方式保持一致
        int available = in.available();
        System.out.println("available:" + available);
        int len1 = in.readInt();
        byte[] bytes = new byte[len1];
        in.read(bytes,0, len1);
        departmentId = new String(bytes);

        int len2 = in.readInt();
        bytes = new byte[len2];
        in.read(bytes,0, len2);
        departmentName = new String(bytes);
    }

    public String getDepartmentName() {
        return departmentName;
    }

    public void setDepartmentName(String departmentName) {
        this.departmentName = departmentName;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(String password) {
        this.password = password;
    }

}

从上面可以看出,Department 类实现Externalizable接口,因此必须实现两个方法:
1.writeExternal
2.readExternal
在进行数据序列化时,给用户提供的高度的自由,但是必须有所约束:
1.序列化的顺序和方式必须与反序列化的保持一致

序列化和反序列化时,一定会各自走这两个方法吗?

序列化时

//#step1 判断对象是否实现了Serializable接口,如果没实现,抛出异常;否则走序列化流程
 private void writeObject0(Object obj, boolean unshared)
        throws IOException
    {
       ............
         
            // remaining cases
            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 {
                if (extendedDebugInfo) {
                    throw new NotSerializableException(
                        cl.getName() + "\n" + debugInfoStack.toString());
                } else {
                    throw new NotSerializableException(cl.getName());
                }
            }
      .............
    }


//#step2 写入序列化标志TC_OBJECT代表是一个新的实例对象;写入类描述符
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);//写入TC_OBJECT代表是一个新的对象
            writeClassDesc(desc, false); //写入文件描述符
            handles.assign(unshared ? null : obj);
            if (desc.isExternalizable() && !desc.isProxy()) {//会走到这里来
                writeExternalData((Externalizable) obj);
            } else {
                writeSerialData(obj, desc);
            }
        } finally {
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }
    }

//#step3 调用对象自己序列化方法,完成序列化
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); //  这里开始写入数据,调用obj的writeExternal
                bout.setBlockDataMode(false);
                bout.writeByte(TC_ENDBLOCKDATA);
            }
        } finally {
            curContext = oldContext;
            if (extendedDebugInfo) {
                debugInfoStack.pop();
            }
        }

        curPut = oldPut;
    }

反序列化时


	
	 public final Object readObject()
        throws IOException, ClassNotFoundException
    {
        ................
            Object obj = readObject0(false);//走到这里
            handles.markDependency(outerHandle, passHandle);
            ClassNotFoundException ex = handles.lookupException(passHandle);
            if (ex != null) {
                throw ex;
            }
            if (depth == 0) {
                vlist.doCallbacks();
            }
            return obj;
      ..................
    }



   /**
     * Underlying readObject implementation.
     */
    private Object readObject0(boolean unshared) throws IOException {
       .......
            switch (tc) {
                case TC_NULL:
                    return readNull();

                case TC_REFERENCE:
                    return readHandle(unshared);
				....

                case TC_OBJECT:
                    return checkResolve(readOrdinaryObject(unshared));//会走到这里

              .....
                default:
                    throw new StreamCorruptedException(
                        String.format("invalid type code: %02X", tc));
            }
       ...
    }

  private Object readOrdinaryObject(boolean unshared)
        throws IOException
    {
       .....

        if (desc.isExternalizable()) {//这里由于是实现了Externalizable接口,所以会走到这里
            readExternalData((Externalizable) obj, desc);
        } else {
            readSerialData(obj, desc); //实现Serializable接口,会走这里
        }

        handles.finish(passHandle);

       .....

        return obj;
    }

 private void readExternalData(Externalizable obj, ObjectStreamClass desc)
        throws IOException
    {
        ......
            if (obj != null) {
                try {
                    obj.readExternal(this);//这里代码会走到这里来
                } 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);
                }
          ....
    }

从上面可知,对象实现了Externalizable,时,虽然间接的实现了Serializable接口,但,Externalizable的优先级要大于Serializable

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值