我们序列化对象的时候,静态成员是不序列化的,但是如果我们需要这样做,有什么办法吗?
9 回答
第一个问题是为什么需要序列化静态成员?
静态成员与类相关联,而不是与实例相关联,因此在序列化实例时包含它们是没有意义的。
第一个解决方案是使这些成员不是静态的。或者,如果这些成员在原始类和目标类(相同的类,但可能不同的运行时环境)中相同,则根本不要序列化它们。
我对如何跨静态成员发送有一些想法,但我首先需要查看用例,因为在所有情况下都意味着更新目标类,我还没有找到这样做的充分理由。
伙计们,静态并不意味着不可变。例如,我可能想序列化整个计算状态(是的,包括静态字段——计数器等),以便稍后在 JVM 和/或主机重新启动后恢复。
如前所述,正确的答案是使用 Externalizable,而不是 Serializable 接口。然后你可以完全控制你外化的内容和方式。
这是静态字段的序列化:newBookingNumber。
class Booking implements Serializable
{
/**
* Generated serial version ID.
*/
private static final long serialVersionUID = 5316748056989930874L;
// To hold new booking number.
private static int newBookingNumber = 0;
// The booking number.
private int bookingNumber;
/*
* Default serializable fields of a class are defined to be
* the non-transient and non-static fields. So, we have to
* write and read the static field separately.
*/
private void writeObject(ObjectOutputStream oos)
throws IOException
{
oos.defaultWriteObject();
oos.writeObject(new Integer(newBookingNumber));
}
private void readObject(ObjectInputStream ois)
throws ClassNotFoundException, IOException
{
ois.defaultReadObject();
newBookingNumber = (Integer)ois.readObject();
}
}
您可以通过实现来控制序列化:
private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
有序列化的完整描述http://java.sun.com/developer/technicalArticles/Programming/serialization/。
正如其他答案所说,序列化静态数据并没有真正意义,因为它是对象而不是您正在序列化的类,并且需要这样做闻起来就像您的代码对我有其他问题。
好的答案和评论——不要这样做。但是怎么做?
您最好创建一个对象来保存所有“静态”。该对象可能也应该具有您的类中的任何静态方法。
你的类的每个实例都可以容纳另一个类——或者如果你真的需要,你可以让它成为任何成员都可以访问的单例。
在你做了这个重构之后,你会发现它应该一直这样做。您甚至可能会发现,以前在 subconsicionce 级别上困扰您的一些设计约束已经消失。
您可能会发现此解决方案还解决了您尚未注意到的其他序列化问题。
您可以执行此操作,而无需在每次更改字段时手动更新您的课程。如果您希望静态成员可以轻松访问应用程序中的设置,但也希望保存这些设置,您可能希望这样做。在这种情况下,您还希望可以选择随心所欲地应用它们,而不是默认加载,因为这里的其他解决方案需要,因为它们是静态的。这允许出于显而易见的原因回滚设置。
基本上,使用字段方法获取类中的所有成员,然后将这些字段的全名映射到内容。由于 Field 本身不可序列化,因此需要全名。序列化此映射,并恢复它以获取保存的设置。
谜题的第二部分是 apply() 类型的函数。这通过映射,并将它可以应用于静态类。
您还必须确保静态成员的内容本身是可序列化的。
希望从这个示例类中可以看出,静态成员可以很容易地保存和返回。我将让实现者来担心类的 UID、安全措施等。 isSameAs() 用于单元测试。AppSettings 是包含您希望序列化的所有静态字段的类。
public class AppSettingsReflectorSaver implements Serializable {
HashMap<String, Object> genericNamesAndContents = new HashMap<String, Object>();
private AppSettingsReflectorSaver() {
}
static AppSettingsReflectorSaver createAppSettingsSaver() {
AppSettingsReflectorSaver ret = new AppSettingsReflectorSaver();
ret.copyAppSettings();
return ret;
}
private void copyAppSettings() {
Field[] fields = AppSettings.class.getFields();
for (Field field : fields) {
mapContentsForSerialization(field);
}
}
private void mapContentsForSerialization(Field field) {
try {
Object fieldContents = field.get(AppSettings.class);
genericNamesAndContents.put(field.toGenericString(), fieldContents);
} catch (IllegalArgumentException ex) {
Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
}
}
boolean isSameAs(AppSettingsReflectorSaver now) {
for( String thisKey : genericNamesAndContents.keySet()){
boolean otherHasThisKey = now.genericNamesAndContents.containsKey(thisKey);
Object thisObject = genericNamesAndContents.get(thisKey);
Object otherObject = now.genericNamesAndContents.get(thisKey);
boolean otherHasThisValue = thisObject.equals(otherObject);
if (!otherHasThisKey || !otherHasThisValue){
return false;
}
}
return true;
}
void applySavedSettingsToStatic() {
Field[] fields = AppSettings.class.getFields();
for (Field field : fields) {
if (!genericNamesAndContents.containsKey(field.toGenericString())){
continue;
}
Object content = genericNamesAndContents.get(field.toGenericString() );
try {
field.set(AppSettings.class, content);
} catch (IllegalArgumentException ex) {
Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
} catch (IllegalAccessException ex) {
Logger.getLogger(AppSettingsReflectorSaver.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
}
这是我的第一篇文章-放轻松:P〜
静态成员属于类,而不属于单个对象。
您应该重新考虑您的数据结构。
是的,我们可以序列化静态变量。但是我们可以编写自己的writeObject()
and readObject()
。我认为这可以解决问题。
要实现紧凑的实现,请在您的类中实现 readObject 和 writeObject 调用 defaultReadObject 和 defaultWriteObject 方法,这些方法在处理正常序列化的那些方法中,然后继续序列化和反序列化您需要的任何其他字段。
问候, GK