Lorsque nous sérialisons des objets, les membres statiques ne sont pas sérialisés, mais s'il le faut, y a-t-il un moyen de sortir?
La première question est pourquoi vous devez sérialiser les membres statiques?
Les membres statiques sont associés à la classe, pas aux instances, il est donc inutile de les inclure lors de la sérialisation d'une instance.
La première solution consiste à rendre ces membres non statiques. Ou, si ces membres sont les mêmes dans la classe d'origine et dans la classe cible (même classe, mais éventuellement environnements d'exécution différents), ne les sérialisez pas du tout.
J'ai quelques idées sur la manière d'envoyer des membres statiques, mais je dois d'abord voir le cas d'utilisation, car dans tous les cas, cela signifie mettre à jour la classe cible et je n'ai pas trouvé de bonne raison de le faire.
Les gens, statique ne veut pas dire IMMUTABLE. Par exemple, je souhaiterais peut-être sérialiser l'état complet du calcul (oui, y compris les champs statiques - compteurs, etc.) pour le reprendre plus tard, après le redémarrage de l'ordinateur JVM et/ou de l'ordinateur hôte.
Comme nous l’avons déjà dit, la bonne réponse à cette question est d’utiliser l’interface Externalizable, et non Serializable. Ensuite, vous avez un contrôle complet sur quoi et comment vous extériorisez.
Vous pouvez contrôler la sérialisation en implémentant:
private void writeObject(ObjectOutputStream out) throws IOException;
private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException;
Il existe une description complète de la sérialisation http://Java.Sun.com/developer/technicalArticles/Programming/serialization/ .
Comme d'autres réponses l'ont déjà dit, sérialiser les statiques n'a pas vraiment de sens car c'est l'objet et non la classe que vous êtes en train de sérialiser et que vous avez besoin de le faire.
C'est la sérialisation pour le champ statique: 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();
}
}
Bonnes réponses et commentaires - ne le fais pas. Mais comment?
Il est fort probable que vous feriez mieux de créer un objet capable de contenir toutes vos "statiques". Cet objet devrait probablement avoir aussi des méthodes statiques de votre classe.
Chaque instance de votre classe peut contenir cette autre classe - ou si vous en avez vraiment besoin, vous pouvez en faire un singleton auquel tout membre peut accéder.
Après avoir effectué ce refactor, vous constaterez que cela aurait dû être fait de cette façon depuis le début. Vous pouvez même constater que certaines de vos contraintes de conception antérieures qui vous gênaient au niveau des sous-licences ont disparu.
Vous constaterez probablement que cette solution résout également d'autres problèmes de sérialisation que vous n'aviez même pas encore remarqués.
Vous pouvez le faire sans avoir à mettre à jour manuellement votre classe à chaque fois que vous modifiez simplement un champ . Vous pouvez le faire si vous voulez avoir la facilité de membres statiques pour accéder aux paramètres dans une application, mais vous aimeriez aussi pour enregistrer ces paramètres . Dans ce cas, vous voudriez également avoir la possibilité de les appliquer à volonté, pas de les charger par défaut comme le nécessitent les autres solutions ici, car elles sont statiques. Cela permet d’annuler les paramètres pour des raisons évidentes.
En gros, utilisez les méthodes de champ pour obtenir tous les membres de la classe, puis mappez les noms complets de ces champs au contenu. Le nom complet est requis puisque Field n'est pas lui-même sérialisable. Sérialisez ce mappage et rétablissez-le pour obtenir les paramètres enregistrés.
La deuxième partie du puzzle est le type de fonction apply (). Cela passe par le mappage et applique ce qu'il peut à la classe statique.
Vous devez également vous assurer que le contenu des membres statiques est lui-même sérialisable.
Comme on peut l'espérer dans cet exemple de classe, les membres statiques peuvent facilement être sauvegardés et renvoyés. Je laisserai à l'implémenteur le soin de se soucier des UID des classes, des sauvegardes, etc. isSameAs () est utilisé pour les tests unitaires. AppSettings est la classe qui contient tous les champs statiques que vous souhaitez sérialiser.
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);
}
}
}
}
Ceci est mon premier post - allez-y doucement sur moi: P ~
Les membres statiques appartiennent à la classe et non aux objets individuels.
Vous devriez reconsidérer votre structure de données.
Oui, nous pouvons sérialiser les variables statiques. Mais nous pouvons écrire nos propres writeObject()
et readObject()
. Je pense que cela peut résoudre le problème.
Pour une implémentation compacte, implémentez les méthodes readObject & writeObject dans votre classe, appelez les méthodes defaultReadObject & defaultWriteObject qui traitent la sérialisation normale, puis procédez à la sérialisation et à la désérialisation des champs supplémentaires nécessaires.
Cordialement, GK