转载: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方法的源码:

    1. private Object readObject0(boolean unshared) throws IOException {
    2. boolean oldMode = bin.getBlockDataMode();
    3. if (oldMode) {
    4. int remain = bin.currentBlockRemaining();
    5. if (remain > 0) {
    6. throw new OptionalDataException(remain);
    7. } else if (defaultDataEnd) {
    8. /*
    9. * Fix for 4360508: stream is currently at the end of a field
    10. * value block written via default serialization; since there
    11. * is no terminating TC_ENDBLOCKDATA tag, simulate
    12. * end-of-custom-data behavior explicitly.
    13. */
    14. throw new OptionalDataException(true);
    15. }
    16. bin.setBlockDataMode(false);
    17. }
    18. byte tc;
    19. while ((tc = bin.peekByte()) == TC_RESET) {
    20. bin.readByte();
    21. handleReset();
    22. }
    23. depth++;
    24. totalObjectRefs++;
    25. try {
    26. switch (tc) {
    27. case TC_NULL:
    28. return readNull();
    29. case TC_REFERENCE:
    30. return readHandle(unshared);
    31. case TC_CLASS:
    32. return readClass(unshared);
    33. case TC_CLASSDESC:
    34. case TC_PROXYCLASSDESC:
    35. return readClassDesc(unshared);
    36. case TC_STRING:
    37. case TC_LONGSTRING:
    38. return checkResolve(readString(unshared));
    39. case TC_ARRAY:
    40. return checkResolve(readArray(unshared));
    41. case TC_ENUM:
    42. return checkResolve(readEnum(unshared));
    43. case TC_OBJECT:
    44. return checkResolve(readOrdinaryObject(unshared));
    45. case TC_EXCEPTION:
    46. IOException ex = readFatalException();
    47. throw new WriteAbortedException("writing aborted", ex);
    48. case TC_BLOCKDATA:
    49. case TC_BLOCKDATALONG:
    50. if (oldMode) {
    51. bin.setBlockDataMode(true);
    52. bin.peek(); // force header read
    53. throw new OptionalDataException(
    54. bin.currentBlockRemaining());
    55. } else {
    56. throw new StreamCorruptedException(
    57. "unexpected block data");
    58. }
    59. case TC_ENDBLOCKDATA:
    60. if (oldMode) {
    61. throw new OptionalDataException(true);
    62. } else {
    63. throw new StreamCorruptedException(
    64. "unexpected end of block data");
    65. }
    66. default:
    67. throw new StreamCorruptedException(
    68. String.format("invalid type code: %02X", tc));
    69. }
    70. } finally {
    71. depth--;
    72. bin.setBlockDataMode(oldMode);
    73. }
    74. }

    这个方法是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 类最近的没有序列化的超类的无参构造函数。