簡體   English   中英

如何序列化Java class的數據成員static?

[英]How to serialize static data members of a Java class?

當我們序列化對象時,static個成員沒有序列化,但是如果我們需要序列化,有什么辦法嗎?

第一個問題,為什么要序列化static成員?

Static 成員與 class 關聯,而不是實例,因此在序列化實例時包含它們沒有意義。

第一個解決方案是使這些成員不是 static。或者,如果這些成員在原始 class 和目標 class 中相同(相同的 class,但可能不同的運行時環境),則根本不要序列化它們。

我對如何發送 static 成員有一些想法,但我首先需要查看用例,因為在所有情況下這意味着更新目標 class,我還沒有找到這樣做的充分理由。

伙計們,static 並不意味着不可更改。 例如,我可能想序列化整個 state 的計算(是的,包括 static 字段——計數器等),以便稍后在 JVM 和/或主機重新啟動后恢復。

如前所述,正確的答案是使用 Externalizable 接口,而不是 Serializable 接口。 然后,您可以完全控制外化的內容和方式。

這是 static 字段的序列化: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/

正如其他答案所說,序列化靜態變量並沒有真正意義,因為它是 object 而不是您正在序列化的 class 並且需要這樣做,這聽起來就像您的代碼對我來說還有其他問題。

好的答案和評論——不要這樣做。 但是怎么辦?

很有可能你最好創建一個 object 來保存你所有的“靜態”。 那個 object 應該也有來自你的 class 的任何 static 方法。

您的 class 的每個實例都可以包含這個其他類——或者如果您確實需要,您可以將它設為任何成員都可以訪問的 singleton。

當你做了這個重構之后,你會發現本來應該一直這樣做的。 您甚至可能會發現之前在潛意識層面困擾您的一些設計限制已經消失。

您可能會發現該解決方案還解決了您尚未注意到的其他序列化問題。

您無需每次更改字段時都手動更新 class 即可執行此操作。 如果您想讓 static 成員輕松訪問應用程序中的設置,但又想保存這些設置,則可能需要這樣做。 在這種情況下,您還希望可以選擇隨心所欲地應用它們,而不是默認加載,因為這里的其他解決方案是必需的,因為它們是 static。出於顯而易見的原因,這允許回滾設置。

基本上,使用字段方法獲取 class 中的所有成員,然后 map 將這些字段的全名添加到內容中。 需要全名,因為 Field 本身不可序列化。 序列化此映射,並恢復它以獲取保存的設置。

謎題的第二部分是 function 的 apply() 類型。它通過映射,並將它可以應用到 static class。

您還必須確保 static 成員的內容本身是可序列化的。

從這個例子 class 中可以看出,static 成員可以很容易地保存和返回。 我將讓實施者擔心類的 UID、安全措施等。isSameAs() 用於單元測試。 AppSettings 是 class,它包含您希望序列化的所有 static 字段。

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

}

這是我的第一篇文章 - go 對我來說很簡單:P~

Static成員屬於class,不屬於個別對象。

您應該重新考慮您的數據結構。

是的,我們可以序列化 static 個變量。 但是我們可以編寫自己的writeObject()readObject() 我認為這可以解決問題。

要實現緊湊的實現,請在 class 調用 defaultReadObject 和 defaultWriteObject 方法中實現 readObject 和 writeObject,這些方法處理正常序列化,然后繼續序列化和反序列化您需要的任何其他字段。

問候, GK

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM