68 votes

L'enum personnalisé est-il également sérialisable ?

Je comprends Enum est Serializable. Par conséquent, il est sûr de le faire. (selectedCountry est enum Country )

Enum original sans variable membre client

public enum Country {
    Australia,
    Austria,
    UnitedState;
}

Fragment

@Override
public void onActivityCreated (Bundle savedInstanceState) {
    super.onActivityCreated(savedInstanceState);
    if (savedInstanceState != null) {
        selectedCountry = (Country)savedInstanceState.getSerializable(SELECTED_COUNTRY_KEY);
    }
}

@Override
public void onSaveInstanceState(Bundle savedInstanceState) {
    savedInstanceState.putSerializable(SELECTED_COUNTRY_KEY, selectedCountry);
}

Cependant, que se passe-t-il si j'ai des membres non sérialisables dans une classe d'enum personnalisée ? Par exemple,

Variables membres de l'enum original customer

package org.yccheok;

import org.yccheok.R;

/**
 *
 * @author yccheok
 */
public enum Country {
    Australia(R.drawable.flag_au),
    Austria(R.drawable.flag_at),
    UnitedState(R.drawable.flag_us);

    Country(int icon) {
        this.icon = icon;
        nonSerializableClass = new NonSerializableClass(this.toString());
    }

    public int getIcon() {
        return icon;
    }

    public static class NonSerializableClass {
        public NonSerializableClass(String dummy) { this.dummy = dummy; }
        public String dummy;
    }

    private final int icon;

    public NonSerializableClass nonSerializableClass;
}

J'ai testé. Cela fonctionne. (J'ai testé en imprimant toutes les valeurs des variables membres avant et après la sérialisation. Elles sont identiques avant et après)

Cependant, je ne comprends pas pourquoi cela fonctionne ? Comme je ne fournis pas de readObject y writeObject conformément aux dispositions de la Serializable interface.

Comme indiqué dans Effective Java Point 75 : envisager l'utilisation d'un formulaire personnalisé sérialisé dois-je fournir mes propres readObject y writeObject si j'ai des variables membres personnalisées dans mon enum ?

0 votes

Que voulez-vous dire par "ça marche" ? Quel test avez-vous effectué ?

111voto

vmironov Points 9810

La raison pour laquelle cela fonctionne est que le processus de sérialisation pour les Enum est différent du processus de sérialisation pour les autres classes. De la documentation officielle :

1.12 Sérialisation des constantes Enum

Les constantes Enum sont sérialisées différemment des objets sérialisables ou externalisables ordinaires. La forme sérialisée d'une constante enum consiste uniquement en son nom ; les valeurs des champs de la constante ne sont pas présentes dans la forme. Pour sérialiser une constante enum, ObjectOutputStream écrit la valeur renvoyée par la méthode name de la constante enum. Pour désérialiser une constante enum, ObjectInputStream lit le nom de la constante à partir du flux ; la constante désérialisée est ensuite obtenue en appelant la méthode java.lang.Enum.valueOf, en passant le type d'enum de la constante ainsi que le nom de la constante reçue comme arguments. Comme d'autres objets sérialisables ou externalisables, les constantes d'énumération peuvent fonctionner comme cibles de références arrière apparaissant ultérieurement dans le flux de sérialisation.

Cela signifie que tous vos champs personnalisés ne le fera pas être sérialisé. Dans votre cas, tout fonctionne bien puisque votre processus d'application est toujours en cours et que vous obtenez l'icône même Enum que vous avez passée à savedInstanceState.putSerializable .

Mais imaginez une situation où votre application est tuée parce que Android n'a pas assez de mémoire. La prochaine fois que l'utilisateur ouvrira l'application, vous obtiendrez une nouveau Enum et tous les champs personnalisés auront été perdus et réinitialisés par le constructeur. Ainsi, les champs mutables d'un enum sont toujours effectivement transient .

1 votes

Mais avez-vous une idée de la manière dont ils gèrent les variables membres du client dans la classe enum, comme par exemple nonSerializableClass , icon , ... ?

0 votes

Ils sont PAS serilisé du tout.

0 votes

Je m'attends à ce qu'il ne soit pas sérialisé et cassé aussi. Cependant, mes tests montrent que la sérialisation fonctionne d'une certaine manière...

10voto

sandrstar Points 5237

Conformément à Serializable documentation, readObject y writeObject ne sont pas du tout nécessaires, donc votre question n'est peut-être pas tout à fait correcte.

Serializable es un interface de marquage et n'a pas de méthodes.

Je vous renvoie à cette réponse qui fournit des détails supplémentaires sur l'implémentation de la sérialisation (ce qui explique pourquoi vous n'avez pas besoin de fonctions d'écriture et de lecture).

Et, comme mentionné aquí par Dianne Hackborn, Parcelable est beaucoup plus efficace pour Android.

Si vous êtes particulièrement intéressé par les Enum, reportez-vous à la rubrique paragraphe ci-dessous :

1.12 Sérialisation des constantes Enum

Les constantes Enum sont sérialisées différemment des objets sérialisables ou externalisables ordinaires. La forme sérialisée d'une constante enum consiste uniquement en son nom ; les valeurs de champ de la constante ne sont pas ne sont pas présentes dans la forme. Pour sérialiser une constante enum, ObjectOutputStream écrit la valeur renvoyée par le nom de la constante enum. name de la constante. Pour désérialiser une constante enum, ObjectInputStream lit le nom de la constante depuis le flux. le nom de la constante à partir du flux ; la constante désérialisée est ensuite obtenue en appelant la méthode java.lang. obtenue en appelant la méthode java.lang.Enum.valueOf, en passant le type d'énumération de la en passant le type d'énumération de la constante ainsi que le nom de la constante reçue en tant qu'arguments. comme arguments. Comme d'autres objets sérialisables ou externalisables, les constantes enum peuvent fonctionner comme les cibles des références arrière apparaissant apparaissant ultérieurement dans le flux de sérialisation.

Le processus par lequel les constantes d'énumération sont sérialisées ne peut pas être personnalisé : toute méthode writeObject, readObject, readObjectNoData, writeReplace et readResolve définies par les types sont ignorées pendant la sérialisation et la désérialisation. De même, toute déclaration de champ serialPersistentFields ou serialVersionUID sont également ignorées - tous les types d'énumérations ont un serialVersionUID fixe de 0L. La documentation des champs et des données sérialisables pour les types pour les types enum est inutile, puisqu'il n'y a aucune variation dans le type de données envoyées. données envoyées.

Donc, je ne pense pas que le Enum est le bon choix pour tester le fonctionnement interne des classes non sérialisables.

0 votes

Ya. Je suis tombé sur Parcelable qui est plus efficace. Cependant, je veux réduire le code (moins de code moins d'erreur), en utilisant directement les caractéristiques Serializable de l'enum. Seulement, je ne suis pas sûr que sans fournir mes propres readObject et writeObject (comme indiqué dans Effective Java #75), les variables membres personnalisées dans les enum se comporteront correctement.

0 votes

Veuillez vous référer à ma réponse mise à jour avec les détails de la spécification de sérialisation qui est assez spécifique pour les Enums.

4voto

dcernahoschi Points 7214

La sérialisation des membres de l'enum ne fonctionne pas. Le champ non sérialisable n'est jamais sérialisé comme l'a répondu @vmironov. Voici un test :

public enum Country {
Australia;

    public static class NonSerializableClass {
       public NonSerializableClass() {}
       public String dummy;
    }

    public NonSerializableClass nonSerializableClass;
}

Le code qui écrit l'enum dans le flux de sérialisation :

public class SerializationTestWrite {
    public static void main(String[] args) throws Exception{
        FileOutputStream f = new FileOutputStream("tmp");
        ObjectOutput s = new ObjectOutputStream(f);

        Country.Australia.nonSerializableClass = new Country.NonSerializableClass();
        Country.Australia.nonSerializableClass.dummy = "abc";

        s.writeObject(Country.Australia);
        s.flush();

        System.out.println(Country.Australia.nonSerializableClass.dummy);
    }
}    

A l'écriture, la valeur du champ fictif est : abc

Le code qui lit l'enum à partir du flux de sérialisation :

public class SerializationTestRead {
    public static void main(String[] args) throws Exception{
        FileInputStream in = new FileInputStream("tmp");
        ObjectInputStream so = new ObjectInputStream(in);
        Country readed = (Country) so.readObject();

        System.out.println(readed.nonSerializableClass);
    }
}

Mais à la lecture, la valeur du champ nonSerializableClass est : null

0 votes

Merci. Je pense que ma méthode de test est probablement erronée, car j'utilise le même processus pour la sérialisation et la dé-sérialisation.

0 votes

@dcernahoschi, oui, ce résultat est attendu. Mais si vous ajoutez tout le code de SerializationTestRead.main à la fin de SerializationTestWrite.main et l'exécuter, vous verrez que nonSerializableClass es no nul.

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X