java - 为什么Serializable中定义的Class 不能序列化?
欧阳克
欧阳克 2017-06-30 09:56:37
0
2
1237
Serialized 类中的

Fields 本身必须是可序列化的或瞬态的,即使该类从未显式序列化或反序列化。这是因为在负载下,大多数 J2EE 应用程序框架都会将对象刷新到磁盘,而具有非瞬态、不可序列化数据成员的所谓可序列化对象可能会导致程序崩溃,并为攻击者打开大门。

此规则在非可序列化字段以及非私有字段(因为可以在外部为它们分配非序列化值)以及在类内为它们分配非序列化类型时引发集合字段问题。

不合规代码示例

雷雷
欧阳克
欧阳克

温故而知新,可以为师矣。 博客:www.ouyangke.com

全部回复(2)
扔个三星炸死你

一个对象序列化时,按照Java默认的序列化规则,对象内的所有成员都要序列化,也就是说,这些Class都必须实现Serializable。

所以,你有两种改法,一是Address实现Serializable接口,二是对Person中的address成员加上transient标记,这样该成员就不会被序列化进去。

typecho

如果 address 成员需要进行序列化的话,则Address类也需要实现Serializable接口。
如果 address 成员不需要进行序列化的话,可以加上transient关键字,则address成员不做序列化操作,值为null。如下:

public class Person implements Serializable {
  private static final long serialVersionUID = 1905122041950251207L;

  private String name;
  private transient Address address;  // Noncompliant; Address isn't serializable
}

当然还有其他方式:
比如实现Externalizable接口,重写readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
还有一个替代实现Externalizable接口方法,还是实现Serializable接口,添加writeObject(ObjectOutputStream obs)和readObject(ObjectInputStream ois)方法。


再说说为什么Address一定要实现Serializable,或者加上transient关键字Person才能进行序列化?
先看看不做处理,使用 ObjectOutputStream 来持久化对象,抛出的异常

Exception in thread "main" java.io.NotSerializableException

ObjectOutputStream源码:

/**
     * Underlying writeObject/writeUnshared implementation.
     */
    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());
                }
            }
        } finally {
            depth--;
            bout.setBlockDataMode(oldMode);
        }
    }

从此可知, 如果被写对象类型是String、Array、Enum、Serializable,就可以进行序列化,否则将抛出NotSerializableException。且在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化。

热门教程
更多>
最新下载
更多>
网站特效
网站源码
网站素材
前端模板
关于我们 免责声明 Sitemap
PHP中文网:公益在线PHP培训,帮助PHP学习者快速成长!