非序列化类的可序列化内部类¶
ID: java/non-serializable-inner-class
Kind: problem
Security severity:
Severity: warning
Precision: medium
Tags:
- reliability
- maintainability
- language-features
Query suites:
- java-security-and-quality.qls
实现 Serializable
的非静态嵌套类必须定义在也是可序列化的封闭类中。非静态嵌套类保留对封闭类实例的隐式引用。如果封闭类不可序列化,Java 序列化机制将使用 java.io.NotSerializableException
失败。
建议¶
要避免导致 NotSerializableException
,请执行以下操作之一
将嵌套类声明为
static
: 如果嵌套类不使用封闭类的任何非静态字段或方法,最好将其声明为static
。这将删除对封闭类实例的隐式引用,并且还会断开这两个类之间不必要的依赖关系。类似的解决方案是将嵌套类变成独立的顶级类。使封闭类实现
Serializable
: 但是,不建议这样做,因为内部类的实现可能是特定于编译器的,并且序列化内部类会导致跨编译器的不可移植性。Java 序列化规范指出强烈建议不要序列化内部类(即非静态成员类),包括局部类和匿名类,原因如下:
示例¶
在以下示例中,类 WrongSession
无法序列化,否则会引发 NotSerializableException
,因为它被封闭在一个非可序列化类中。但是,类 Session
可以序列化,因为它被声明为 static
。
class NonSerializableServer {
// BAD: The following class is serializable, but the enclosing class
// 'NonSerializableServer' is not. Serializing an instance of 'WrongSession'
// causes a 'java.io.NotSerializableException'.
class WrongSession implements Serializable {
private static final long serialVersionUID = 8970783971992397218L;
private int id;
private String user;
WrongSession(int id, String user) { /*...*/ }
}
public WrongSession getNewSession(String user) {
return new WrongSession(newId(), user);
}
}
class Server {
// GOOD: The following class can be correctly serialized because it is static.
static class Session implements Serializable {
private static final long serialVersionUID = 1065454318648105638L;
private int id;
private String user;
Session(int id, String user) { /*...*/ }
}
public Session getNewSession(String user) {
return new Session(newId(), user);
}
}
参考资料¶
Java 对象序列化规范:1.10 可序列化接口,2.1 ObjectOutputStream 类.