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

时间:2009-06-17 16:02:40

标签: java serialization static-members

当我们序列化对象时,静态成员不是序列化的,但是如果我们需要这样做,有什么办法吗?

9 个答案:

答案 0 :(得分:18)

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

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

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

我对如何发送静态成员有一些想法,但我首先需要查看用例,因为在所有情况下这意味着更新目标类,我没有找到一个很好的理由这样做

答案 1 :(得分:15)

民众,静态并不意味着IMMUTABLE。例如,我可能想要在JVM和/或主机重新启动之后序列化计算的整个状态(是的,包括静态字段 - 计数器等)以便稍后恢复。

正如已经说过的,正确的答案是使用Externalizable,而不是Serializable接口。然后,您可以完全控制外部化的内容和方式。

答案 2 :(得分:5)

您可以通过实施:

来控制序列化
private void writeObject(ObjectOutputStream out) throws IOException;

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

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

正如其他答案所说的那样,序列化静态并不是真的有意义,因为它不是你要序列化的对象,而是需要这样做,闻起来你的代码还有其它问题。< / p>

答案 3 :(得分:5)

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

答案 4 :(得分:2)

好的答案和评论 - 不要这样做。但是如何?

你可能最好创建一个对象来保存你的所有“静力学”。该对象也应该包含您的类中的任何静态方法。

你班级的每个实例都可以拥有另一个班级 - 或者如果你真的需要,你可以把它作为任何成员都可以访问的单身人士。

执行此重构后,您会发现它应该一直以这种方式完成。你甚至可能会发现你以前在subconsicionce级别困扰你的一些设计约束已经消失了。

您可能会发现此解决方案还解决了您尚未注意到的其他序列化问题。

答案 5 :(得分:2)

每次只更改字段时,无需手动更新课程即可完成此操作。 如果您希望使用静态成员轻松访问应用程序中的设置,但您还希望保存这些设置,则可能需要执行此操作。 在这种情况下,您还希望可以选择随意应用它们,而不是默认加载,因为其他解决方案是必需的,因为它们是静态的。由于显而易见的原因,这允许回滚设置。

基本上,使用字段方法获取类中的所有成员,然后将这些字段的全名映射到内容。由于Field本身不可序列化,因此需要全名。序列化此映射,并将其恢复以获取已保存的设置。

拼图的第二部分是apply()类型的函数。这将通过映射,并将其可以应用于静态类。

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

从这个示例类中可以看出,可以轻松保存和返回静态成员。我将把它留给实现者来担心类的UID,安全措施等.asSameAs()用于单元测试。 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~

答案 6 :(得分:1)

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

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

答案 7 :(得分:0)

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

答案 8 :(得分:0)

要实现紧凑的实现,请实现readObject&amp;你的类中的writeObject调用defaultReadObject&amp;这些方法中的defaultWriteObject方法处理正常的序列化,然后继续序列化&amp;反序列化您需要的任何其他字段。

此致 GK