转载:https://www.cnblogs.com/yxym2016/p/12920315.html

    通过反序列化生成对象的过程主要由以下几个步骤:
    1、创建一个对象输入流,它可以包装一个其他类型的源输入流,如文件输入流;
    2、 通过对象输入流的readObject()方法读取对象。
    其中正是readObject方法返回了一个对象,这个对象就是根据序列化生成的文件而创建的对象,所以反序列化如何创建对象关键就在于readObject方法的实现,那就来探析一下它的实现,它的源码如下:

    1. public final Object readObject() throws IOException, ClassNotFoundException {
    2. if (enableOverride) {
    3. return readObjectOverride();
    4. }
    5. // if nested read, passHandle contains handle of enclosing object
    6. int outerHandle = passHandle;
    7. try {
    8. Object obj = readObject0(false);
    9. handles.markDependency(outerHandle, passHandle);
    10. ClassNotFoundException ex = handles.lookupException(passHandle);
    11. if (ex != null) {
    12. throw ex;
    13. }
    14. if (depth == 0) {
    15. vlist.doCallbacks();
    16. }
    17. return obj;
    18. } finally {
    19. passHandle = outerHandle;
    20. if (closed && depth == 0) {
    21. clear();
    22. }
    23. }
    24. }

    这个方法会从对象输入流中读取一个对象,其中还包括这个对象的类名、类的签名、类的非静态非瞬时属性值、以及它的所有超类。
    该对象所引用的对象是传递式读取的,所以readObject方法可以重建对象的完整等效图,也就复刻一个和原来被序列化对象一样的对象。
    由于该方法返回值就是一个Object类型,所以我们重点看实际返回的obj这个对象是怎么创建,可以看出它是通过另一个方法创建,继续查看readObject0方法的源码:

    private Object readObject0(boolean unshared) throws IOException {
        boolean oldMode = bin.getBlockDataMode();
        if (oldMode) {
            int remain = bin.currentBlockRemaining();
            if (remain > 0) {
                throw new OptionalDataException(remain);
            } else if (defaultDataEnd) {
                /*
                     * Fix for 4360508: stream is currently at the end of a field
                     * value block written via default serialization; since there
                     * is no terminating TC_ENDBLOCKDATA tag, simulate
                     * end-of-custom-data behavior explicitly.
                     */
                throw new OptionalDataException(true);
            }
            bin.setBlockDataMode(false);
        }
    
        byte tc;
        while ((tc = bin.peekByte()) == TC_RESET) {
            bin.readByte();
            handleReset();
        }
    
        depth++;
        totalObjectRefs++;
        try {
            switch (tc) {
                case TC_NULL:
                    return readNull();
    
                case TC_REFERENCE:
                    return readHandle(unshared);
    
                case TC_CLASS:
                    return readClass(unshared);
    
                case TC_CLASSDESC:
                case TC_PROXYCLASSDESC:
                    return readClassDesc(unshared);
    
                case TC_STRING:
                case TC_LONGSTRING:
                    return checkResolve(readString(unshared));
    
                case TC_ARRAY:
                    return checkResolve(readArray(unshared));
    
                case TC_ENUM:
                    return checkResolve(readEnum(unshared));
    
                case TC_OBJECT:
                    return checkResolve(readOrdinaryObject(unshared));
    
                case TC_EXCEPTION:
                    IOException ex = readFatalException();
                    throw new WriteAbortedException("writing aborted", ex);
    
                case TC_BLOCKDATA:
                case TC_BLOCKDATALONG:
                    if (oldMode) {
                        bin.setBlockDataMode(true);
                        bin.peek();             // force header read
                        throw new OptionalDataException(
                            bin.currentBlockRemaining());
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected block data");
                    }
                case TC_ENDBLOCKDATA:
                    if (oldMode) {
                        throw new OptionalDataException(true);
                    } else {
                        throw new StreamCorruptedException(
                            "unexpected end of block data");
                    }
    
                default:
                    throw new StreamCorruptedException(
                        String.format("invalid type code: %02X", tc));
            }
        } finally {
            depth--;
            bin.setBlockDataMode(oldMode);
        }
    }
    

    这个方法是readObject方法的底层实现,由于它的返回值类型也是对象类型,所以我们重点看返回的实际对象是哪个,通过观察和debug发现,开关语句执行时下面这行代码,checkResolve方法接收的参数类型是对象类型,返回值类型也是对象类型。

    case TC_OBJECT:
        return checkResolve(readOrdinaryObject(unshared));
    

    那我们来查看readOrdinaryObject对象:

    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);
        } 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) {
                // 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;
    }
    

    此处我们重点看的还应该是产生实际返回值的地方,也就是这块:
    obj = desc.isInstantiable() ? desc.newInstance() : null;

    desc.newInstance() 方法原理是利用反射创建了一个对象,本质是调用非序列化父类的无参构造器。
    如果该类是 Externalizable 类型的,则调用它自身的访问权限是 public 无参构造方法。
    如果该类是 Serializable 类型的,则调用该类的第一个非 Serializable 类型的父类的无参构造方法。

    所以这就是为什么通过反序列化创建对象的时候,并不会执行被序列化对象的构造方法。

    对于实现 Serializable 接口的类,并不要求该类具有一个无参的构造方法, 因为在反序列化的过程中实际上是去其继承树上找到一个没有实现 Serializable 接口的父类(最终会找到 Object ),然后构造该类的对象,再逐层往下的去设置各个可以反序列化的属性(也就是没有被 transient 修饰的非静态属性)。
    我们通过一个具体的案例就可以看出来:

    import java.io.Serializable;
    
    public class Users implements Serializable {
        private String username;
        private int age;
        private String sex;
    
        public Users() {
            System.out.println("调用了构造方法");
        }
      /*    get和set方法  */  …………
    }
    

    创建一个测试类:

    import java.io.*;
    
    public class TestUsers {
        public static void main(String[] args) {
    
            try {
                System.out.println("开始序列化。。。。。");
                Users users = new Users();
                users.setUsername("fym");
                users.setAge(23);
                users.setSex("nan");
    
                FileOutputStream fs = new FileOutputStream("users.ser");
                ObjectOutputStream os = new ObjectOutputStream(fs);
                os.writeObject(users);
                os.close();
                fs.close();
    
                System.out.println("开始反序列化。。。。。");
                FileInputStream fileInputStream = new FileInputStream("users.ser");
                ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream);
                Users o = (Users)objectInputStream.readObject();
                System.out.println(o);
                fileInputStream.close();
                objectInputStream.close();
            } catch (Exception e) {
                e.printStackTrace();
            }
    
        }
    }
    

    输出结果:

    开始序列化。。。。。
    调用了构造方法
    开始反序列化。。。。。
    Users{username='fym', age=23, sex='nan'}
    

    我们将其改造一下,让User类继承一个没有序列化的父类:

    class ParentsUser{
        public ParentsUser(){
            System.out.println("调用了父类构造方法");
        }
    }
    public class Users extends ParentsUser implements Serializable {
        ……
    }
    

    再一次执行上面的测试类,输出结果如下:

    开始序列化。。。。。
    调用了父类构造方法
    调用了构造方法
    开始反序列化。。。。。
    调用了父类构造方法
    Users{username='fym', age=23, sex='nan'}
    

    发现,反序列化创建对象的时候,果然调用了离 User 类最近的没有序列化的超类的无参构造函数。