如何序列化Java类的静态数据成员?

当我们序列化对象的时候,静态成员是不会被序列化的,但是如果我们需要这样做的话,还有什么出路呢?

第一个问题是为什么你需要序列化静态成员?

静态成员与类关联,而不是实例,因此在序列化实例时将它们包括在内是没有意义的。

第一个解决scheme是使这些成员不是静态的。 或者,如果这些成员在原始类和目标类(相同的类,但可能不同的运行时环境)中是相同的,则不要序列化它们。

我对如何通过静态成员发送了一些想法,但是我首先需要看到用例,因为在所有情况下,这意味着更新目标类,而我没有find这样做的充分理由。

伙计,静态并不意味着IMMUTABLE。 例如,我可能希望序列化计算的整个状态(是的,包括静态字段 – 计数器等),以便在JVM和/或主机重新启动之后重新开始。

正如已经说过的,正确的答案是使用Externalizable而不是Serializable接口。 那么你完全可以控制什么以及如何外部化。

您可以通过执行以下控制序列化:

private void writeObject(ObjectOutputStream out) throws IOException; private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException; 

有一个序列化的完整描述http://java.sun.com/developer/technicalArticles/Programming/serialization/

正如其他答案所说的,将静态序列化并不是真正有意义的,因为它不是你要序列化的类,而是需要这样做的气味,就像你对我的代码有其他问题一样。

这是静态字段的序列化: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(); } } 

静态成员属于类,而不属于单个对象。

你应该重新考虑你的数据结构。

好的回答和评论 – 不要这样做。 但是,如何?

机会是你最好创build一个对象来保存所有的“静态”。 那个对象应该也可以有你的类的静态方法。

你的class级的每个实例都可以容纳另一个class级,或者如果你真的必须让你成为任何成员都可以访问的单身人士。

在你做这个重构之后,你会发现它应该一直这样做。 你甚至可能会发现,你以前的一些devise上的制约因素已经消失了。

你可能会发现这个解决scheme也解决了你还没有注意到的其他序列化问题。

你可以做到这一点,而无需每次只需要更改字段时手动更新class级。 如果您希望获得静态成员访问应用程序中的设置的便利性,但是也想保存这些设置,则可能需要执行此操作。 在这种情况下,你也可以select应用它们,而不是默认加载,因为它们是静态的。 这允许出于显而易见的原因回滚设置。

基本上,使用字段方法获取类中的所有成员,然后将这些字段的全名映射到内容。 全名是必需的,因为Field本身不是可序列化的。 序列化这个映射,并恢复它来获得保存的设置。

难题的第二部分是apply()types的函数。 这通过映射,并将其应用到静态类。

您还必须确保静态成员的内容本身是可序列化的。

从这个示例类中可以看出,静态成员可以很容易地保存和返回。 我将留给实施者来担心类的UID,安全措施等。isSameAs()用于unit testing。 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〜

为了实现紧凑的实现,在你的类中实现readObject&writeObject,在处理正常序列化的方法中调用defaultReadObject&defaultWriteObject方法,然后继续序列化和反序列化你需要的任何附加字段。

问候,GK

是的,我们可以序列化静态variables。 但是我们可以编写我们自己的writeObject()readObject() 。 我认为这可以解决问题。