只需实施Serializable
如果你得到一个NotSerializableException就像下面这样,
java.io.NotSerializableException: bean.ProjectAreaBean
那么它只是意味着由异常消息中的完全限定名称标识的类(即bean.ProjectAreaBean
在你的情况下)没有实现Serializable接口,而这是后面的代码所期望的。修复起来比较简单,只要让类实现Serializable
界面。
package bean;
import java.io.Serializable;
public class ProjectAreaBean implements Serializable {
private static final long serialVersionUID = 1L;
// ...
}
The serialVersionUID
field 不是必需的,但强烈建议使用,因为这可以保持类的不同版本及其实例的序列化表示之间的二进制兼容性。因此,当您稍后向类添加新的可序列化字段时,您需要更改serialVersionUID
字段(通常只需将其增加 1 就足够了)以防止在反序列化旧版本类的实例期间出现问题。像 Eclipse 这样的 IDE 还提供了一个选项来(重新)生成serialVersionUID
value 基本上是基于所有字段计算的哈希值。
也可以看看:
- JSF 托管 bean 在 Tomcat 部署期间导致 java.io.NotSerializedException
- 将不可序列化的应用程序作用域 bean 作为集群中可序列化会话作用域 bean 的托管属性注入
- 什么是serialVersionUID?为什么要使用它?
标记不可序列化字段transient
If your Serializable
类又包含引用另一个类的实例的字段/属性,这是绝对不能创建的Serializable
(通常,这些代表资源,例如InputStream
, Connection
等),那么你需要标记它transient
。这样,它将在类的序列化过程中被跳过。
private transient SomeObject thisWillNotBeSerialized;
您需要了解,反序列化后该字段始终会变成null
。请注意,类的构造函数和初始化块是not反序列化期间调用。如果您想对序列化和反序列化进行更细粒度的控制,请覆盖readObject()
and writeObject()
方法。您可以在以下链接中找到具体示例:
- 防止应用程序某些部分的组件树序列化
- 如何在 Android 中使用 DefaultHttpClient 制作持久 Cookie?
为什么要序列化?
至于why你需要担心序列化,这是因为大多数 Java servlet 容器(如 Tomcat)需要类来实现Serializable
每当这些类的实例被存储为HttpSession。那是因为HttpSession
当 servlet 容器需要关闭/重新启动或被放置在会话必须同步的服务器集群中时,可能需要保存在本地磁盘文件系统上,甚至需要通过网络传输。
为了能够将 Java 对象保存在本地磁盘文件系统上或通过网络传输它们,必须首先将它们转换为字节流(基本上:byte[]
or an InputStream
)并且只有当对象背后的类实现时才有可能Serializable
. The Serializable
界面本身并没有真正做任何事情,它只是一个标记接口。后面的代码只是做了一个instanceof Serializable
检查会话属性以进行相应操作。
也可以看看:
- java.io.Serializable javadoc
- Java 对象序列化规范
- Java 教程 - 基本类 - 基本 I/O - 对象流