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

发布于 2024-07-25 06:21:33 字数 53 浏览 7 评论 0原文

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

When we serialize objects, static members are not serialized, but if we need to do so, is there any way out?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(9

可是我不能没有你 2024-08-01 06:21:34

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

This is serialization for the static field: 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();
    }
}
撑一把青伞 2024-08-01 06:21:34

您可以通过实现来控制序列化:

private void writeObject(ObjectOutputStream out) throws IOException;

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

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

正如其他答案所说,序列化静态并没有真正的意义,因为它是对象而不是您要序列化的类,并且需要这样做,这听起来就像您的代码有其他问题一样。

You can control serialization by implementing:

private void writeObject(ObjectOutputStream out) throws IOException;

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

There's a full description of serialization http://java.sun.com/developer/technicalArticles/Programming/serialization/.

As other answers have said, it doesn't really make sense to serialize statics as it's the object not the class you're serializing and needing to do so smells like you've got other issues with your code to me.

给不了的爱 2024-08-01 06:21:34

您可以执行此操作,而无需在每次更改字段时手动更新您的类。
如果您希望能够轻松地使用静态成员来访问应用程序中的设置,但又希望保存这些设置,则可能需要执行此操作。
在这种情况下,您还希望可以选择随心所欲地应用它们,而不是像此处其他解决方案所必需的那样默认加载它们,因为它们是静态的。 这允许出于明显的原因回滚设置。

基本上,使用字段方法获取类中的所有成员,然后将这些字段的全名映射到内容。 由于 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~

You can do this without having to manually update your class every time you simply change a field.
You may want to do this if you want to have the ease of static members for access to settings in an application, but would also like to save those settings.
In this case, you would also want to have the option to apply them at whim, not load by default as the other solutions here necessitate, since they are static. This allows for rollback of settings for obvious reasons.

Basically, use the field methods to get all the members in the class, then map the full names of these fields to the contents. The full name is required since Field is not serializable itself. Serialize this mapping, and reinstate it to get the saved settings.

The second part of the puzzle is the apply() type of function. This goes thru the mapping, and applies what it can to the static class.

You must also ensure that the contents of the static members are themselves serializable.

As can hopefully be seen from this example class, the static members can easily be saved and returned. I'll leave it up to the implementer to worry about UIDs of classes, safeguards etc. isSameAs() is used for unit testing. AppSettings is the class that contains all the static fields that you wish to serialize.

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);
        }
    }
}

}

This is my first post - go easy on me :P~

我是男神闪亮亮 2024-08-01 06:21:34

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

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

你的类的每个实例都可以保存另一个类——或者如果你确实需要的话,你可以将它设置为任何成员都可以访问的单例。

当你做了这个重构之后,你会发现本来就应该这样做。 您甚至可能会发现以前在潜意识层面上困扰您的一些设计限制已经消失。

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

Good answers and comments--don't do it. But how?

Chances are you would be best off creating an object to hold all your "Statics". That object should probably have any static methods from your class as well.

Every instance of your class can hold this other class--or if you really have to you can make it a singleton that any member can access.

After you do this refactor, you will find that it should have been done this way all along. You may even find that some of your previous design constraints that were bothering you at a subconsicionce level have vanished.

You'll probably find that this solution also solves other Serialization problems you hadn't even noticed yet.

左秋 2024-08-01 06:21:34

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

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

Static members belong to the class, not to the individual objects.

You should reconsider your data structure.

只涨不跌 2024-08-01 06:21:34

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

问候,
吉克

To have compact implementation, implement readObject & writeObject in your class call defaultReadObject & defaultWriteObject methods within those methods which handles normal serialization and then proceed with serializing & de-serializing whatever additional fields you need.

Regards,
GK

楠木可依 2024-08-01 06:21:34

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

Yes, we can serialize the static variables. But we can write our own writeObject() and readObject(). I think this can solve the problem.

一指流沙 2024-08-01 06:21:33

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

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

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

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

The first question is why you need to serialize the static members?

Static members are associated with the class, not the instances, so it does not make sense to include them when serializing an instance.

The first solution is to make those members not static. Or, if those members are the same in the original class and the target class (same class, but possibly different runtime environments), don't serialize them at all.

I have a few thoughts on how one could send across static members, but I first need to see the use case, as in all cases that means updating the target class, and I haven't found a good reason to do so.

熊抱啵儿 2024-08-01 06:21:33

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

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

Folks, static doesn't mean IMMUTABLE. For instance, I may want to serialize the whole state of the computation (yes, including static fields -- counters, etc) to resume later, after JVM and/or host computer restarted.

The right answer to that, as already said, is to use Externalizable, not Serializable, interface. Then you have a complete control on what and how you externalize.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文