オブジェクトをシリアル化する場合、静的メンバーはシリアル化されませんが、そうする必要がある場合、解決策はありますか?
9 に答える
皆さん、静的は不変を意味しません。たとえば、JVM やホスト コンピューターの再起動後に、計算の状態全体 (はい、静的フィールド (カウンターなど) を含む) をシリアル化し、後で再開したい場合があります。
すでに述べたように、それに対する正しい答えは、Serializable ではなく Externalizable インターフェースを使用することです。次に、何をどのように外部化するかを完全に制御できます。
これは静的フィールド 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/。
他の回答が言っているように、静的をシリアル化するのは本当に意味がありません。これは、シリアル化するクラスではなくオブジェクトであり、シリアル化する必要があるため、コードに他の問題があるようなにおいがします。
良い答えとコメント--しないでください。しかし、どのように?
おそらく、すべての「Statics」を保持するオブジェクトを作成するのが最善でしょう。そのオブジェクトには、おそらくクラスの静的メソッドもあるはずです。
クラスのすべてのインスタンスは、この他のクラスを保持できます。または、本当に必要な場合は、すべてのメンバーがアクセスできるシングルトンにすることができます。
このリファクタリングを実行すると、最初からこの方法で実行する必要があったことがわかります。潜在意識レベルで悩まされていた以前の設計上の制約の一部が消えたことに気付くかもしれません。
おそらく、このソリューションによって、まだ気付いていなかった他のシリアライゼーションの問題も解決されることに気付くでしょう。
フィールドを変更するたびに手動でクラスを更新する必要なく、これを行うことができます。アプリケーションの設定にアクセスするための静的メンバーを簡単に使用したいが、それらの設定を保存したい場合は、これを行うことができます。この場合、他のソリューションが静的であるため、デフォルトでロードするのではなく、気まぐれに適用するオプションも必要です。これにより、明らかな理由で設定のロールバックが可能になります。
基本的には、フィールド メソッドを使用してクラス内のすべてのメンバーを取得し、これらのフィールドの完全な名前をコンテンツにマップします。Field 自体はシリアル化できないため、完全な名前が必要です。このマッピングをシリアル化し、復元して保存された設定を取得します。
パズルの 2 番目の部分は、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);
}
}
}
}
これは私の最初の投稿です。
コンパクトな実装を行うには、クラスに readObject と writeObject を実装し、通常のシリアル化を処理するメソッド内で defaultReadObject と defaultWriteObject メソッドを呼び出してから、必要な追加フィールドをシリアル化および逆シリアル化します。
よろしく、GK
はい、静的変数をシリアル化できます。しかし、独自のwriteObject()
andを書くことができますreadObject()
。これで問題は解決できると思います。