可序列化但没有 void 构造函数¶
ID: java/missing-no-arg-constructor-on-serializable
Kind: problem
Security severity:
Severity: warning
Precision: medium
Tags:
- reliability
- maintainability
- language-features
Query suites:
- java-security-and-quality.qls
如果可序列化类是非可序列化类的子类,则在超类未声明无参数构造函数时无法对其进行反序列化。在反序列化期间初始化创建的对象实例时,Java 序列化框架会使用无参数构造函数。如果超类未声明无参数构造函数,则反序列化会失败,并出现 InvalidClassException
。
Java 开发工具包 API 文档中指出
为了允许对非可序列化类的子类型进行序列化,子类型可以承担保存和恢复超类型公共、受保护和(如果可访问)包字段状态的责任。仅当子类型扩展的类具有可访问的无参数构造函数来初始化类的状态时,子类型才能承担此责任。如果并非如此,则声明类
Serializable
是错误的。此错误将在运行时检测到。
建议¶
确保每个被可序列化类扩展的非可序列化类都具有无参数构造函数。
示例¶
在以下示例中,类 WrongSubItem
无法反序列化,因为其超类 WrongItem
未声明无参数构造函数。但是,类 SubItem
可以序列化,因为它声明了无参数构造函数。
class WrongItem {
private String name;
// BAD: This class does not have a no-argument constructor, and throws an
// 'InvalidClassException' at runtime.
public WrongItem(String name) {
this.name = name;
}
}
class WrongSubItem extends WrongItem implements Serializable {
public WrongSubItem() {
super(null);
}
public WrongSubItem(String name) {
super(name);
}
}
class Item {
private String name;
// GOOD: This class declares a no-argument constructor, which allows serializable
// subclasses to be deserialized without error.
public Item() {}
public Item(String name) {
this.name = name;
}
}
class SubItem extends Item implements Serializable {
public SubItem() {
super(null);
}
public SubItem(String name) {
super(name);
}
}
参考¶
Java API 规范:Serializable。
J. Bloch,Effective Java(第二版),第 74 条。Addison-Wesley,2008 年。