java - 为什么Serializable中定义的Class 不能序列化?
问题描述
Fields in a Serializable class must themselves be either Serializable or transient even if the class is never explicitly serialized or deserialized. That’s because under load, most J2EE application frameworks flush objects to disk, and an allegedly Serializable object with non-transient, non-serializable data members could cause program crashes, and open the door to attackers.This rule raises an issue on non-Serializable fields, and on collection fields when they are not private (because they could be assigned non-Serializable values externally), and when they are assigned non-Serializable types within the class.Noncompliant Code Examplepublic class Address { //...}public class Person implements Serializable { private static final long serialVersionUID = 1905122041950251207L; private String name; private Address address; // Noncompliant; Address isn’t serializable}
问题解答
回答1:一个对象序列化时,按照Java默认的序列化规则,对象内的所有成员都要序列化,也就是说,这些Class都必须实现Serializable。
所以,你有两种改法,一是Address实现Serializable接口,二是对Person中的address成员加上transient标记,这样该成员就不会被序列化进去。
回答2:如果 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。且在序列化对象时,不仅会序列化当前对象本身,还会对该对象引用的其它对象也进行序列化。
相关文章:
1. javascript - swiper.js嵌套了swiper 初始设置不能向下一个滑动 结束后重新初始2. 为什么span的color非要内联样式才起作用?3. angular.js - angular-ui-bootstrap 报错无法使用?4. docker - 如何修改运行中容器的配置5. python - 如何修改twisted自带的日志输出格式?6. 请问一下各位老鸟 我一直在学习独孤九贱 现在是在tp5 今天发现 这个系列视频没有实战7. 老师,请问我打开browsersync出现这个问题怎么解决啊?8. 求救一下,用新版的phpstudy,数据库过段时间会消失是什么情况?9. html5 - H5做的手机分享页微信更新后,分享出去不再默认显示第一个图 作为缩略图10. 高并发写入和更新mysql

网公网安备