序列化,反序列化与空参构造函数

Posted csyxwk

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了序列化,反序列化与空参构造函数相关的知识,希望对你有一定的参考价值。

序列化

对象要想序列化,需要类实现接口 Serializable与Externalizable其中之一

Seializable

  1. 类通过实现 java.io.Serializable 接口以启用其序列化功能。未实现此接口的类将无法使其任何状态序列化或反序列化。
  2. 可序列化类的所有子类型本身都是可序列化的。序列化接口没有方法或字段,仅用于标识可序列化的语义。
  3. 如果实现Serializable接口,对象如何序列化,各个属性序列化的顺序是什么,都是默认的,程序员无法指定,也不用关心。
  4. 如果属性前面有static和transient修饰,不参与序列化。

Externalizable

Externalizable接口继承自Serializable,但是增加了两个方法即writeExternal方法和readExternal方法

在writeExternal方法中,自定定制哪些属性要序列化,顺序是什么样。

在readExternal方法中,自定定制哪些属性要反序列化,顺序和writeExternal的方法中一致。

 

先说实现Serializable接口的类对象反序列化时是否需要空参构造。

查找ObjectStreamClass源码 找到一个方法

 private static Constructor<?> getSerializableConstructor(Class<?> cl) {
        Class<?> initCl = cl;
        while (Serializable.class.isAssignableFrom(initCl)) {
            if ((initCl = initCl.getSuperclass()) == null) {
                return null;
            }
        }
        try {
            Constructor<?> cons = initCl.getDeclaredConstructor((Class<?>[]) null);
            int mods = cons.getModifiers();
            if ((mods & Modifier.PRIVATE) != 0 ||
                ((mods & (Modifier.PUBLIC | Modifier.PROTECTED)) == 0 &&
                 !packageEquals(cl, initCl)))
            {
                return null;
            }
            cons = reflFactory.newConstructorForSerialization(cl, cons);
            cons.setAccessible(true);
            return cons;
        } catch (NoSuchMethodException ex) {
            return null;
        }
    }

方法注释为:

Returns subclass-accessible no-arg constructor of first non-serializable superclass, or null if none found. Access checks are disabled on the returned constructor (if any)。

即:该方法会返回Serializable接口实现类往上一直寻找到第一个没有实现该接口父类的空参构造方法,若第一个没有实现该接口的父类没有空参构造方法,则会抛出java.io.InvalidClassException: IO.goods; no valid constructor异常,如果该实现类有无空参构造都可以,但是第一个没有实现该接口的父类必须有

 

实现Externalizable接口的类对象反序列化时是否需要空参构造。

同样的,查找ObjectStreamClass源码发现,

 private static Constructor<?> getExternalizableConstructor(Class<?> cl) {
        try {
            Constructor<?> cons = cl.getDeclaredConstructor((Class<?>[]) null);
            cons.setAccessible(true);
            return ((cons.getModifiers() & Modifier.PUBLIC) != 0) ?
                cons : null;
        } catch (NoSuchMethodException ex) {
            return null;
        }
    }

该方法注释为:

Returns public no-arg constructor of given class, or null if none found.
     * Access checks are disabled on the returned constructor (if any), since
     * the defining class may still be non-public.

即;查找实现类是否有空参构造,如果没有则返回null,

因此Externalizable接口实现类必须有空参构造方法,否则反序列化时会抛出 java.io.InvalidClassException异常。

以上是关于序列化,反序列化与空参构造函数的主要内容,如果未能解决你的问题,请参考以下文章

大数据之Hadoop(MapReduce):自定义bean对象实现序列化接口(Writable)

在构造函数中反序列化 const 成员对象

Protobuf-Net 无法在没有无参数构造函数的情况下反序列化记录

反序列化没有默认构造函数的类型的 STL 容器

C++ 模板工厂构造函数/反序列化

使用 XmlSerializer.Deserialize 反序列化时何时调用类构造函数?