web-dev-qa-db-fra.com

Que signifie "sérialisable"?

Qu'est-ce que cela signifie exactement pour une classe d'être Serializable en Java? Ou en général, d'ailleurs ...

124
Ritwik Bose

Sérialisation persiste un objet de la mémoire à une séquence de bits, par exemple pour le sauvegarder sur le disque. La désérialisation est l'opposé - lire les données du disque pour hydrater/créer un objet.

Dans le contexte de votre question, il s'agit d'une interface qui, si elle est implémentée dans une classe, peut être automatiquement sérialisée et désérialisée par différents sérialiseurs.

120
Oded

Bien que la plupart des utilisateurs aient déjà donné la réponse, je souhaiterais cependant ajouter un exemple à ceux qui en ont besoin afin d'expliquer l'idée:

Disons que vous avez une personne de classe comme celle-ci:

public class Person implements Java.io.Serializable {
    /**
     * 
     */
    private static final long serialVersionUID = 1L;
    public String firstName;
    public String lastName;
    public int age;
    public String address;

    public void play() {
        System.out.println(String.format(
                "If I win, send me the trophy to this address: %s", address));
    }
    @Override
    public String toString() {
        return String.format(".....Person......\nFirst Name = %s\nLast Name = %s", firstName, lastName);
    }
}

et ensuite vous créez un objet comme ceci:

Person william = new Person();
        william.firstName = "William";
        william.lastName = "Kinaan";
        william.age = 26;
        william.address = "Lisbon, Portugal";

Vous pouvez sérialiser cet objet sur plusieurs flux. Je ferai cela à deux flux:

Sérialisation sur la sortie standard:

public static void serializeToStandardOutput(Person person)
            throws IOException {
        OutputStream outStream = System.out;
        ObjectOutputStream stdObjectOut = new ObjectOutputStream(outStream);
        stdObjectOut.writeObject(person);
        stdObjectOut.close();
        outStream.close();
    }

Sérialisation dans un fichier:

public static void serializeToFile(Person person) throws IOException {
        OutputStream outStream = new FileOutputStream("person.ser");
        ObjectOutputStream fileObjectOut = new ObjectOutputStream(outStream);
        fileObjectOut.writeObject(person);
        fileObjectOut.close();
        outStream.close();
    }

Ensuite:

désérialiser du fichier:

public static void deserializeFromFile() throws IOException,
            ClassNotFoundException {
        InputStream inStream = new FileInputStream("person.ser");
        ObjectInputStream fileObjectIn = new ObjectInputStream(inStream);
        Person person = (Person) fileObjectIn.readObject();
        System.out.println(person);
        fileObjectIn.close();
        inStream.close();
    }
37
William Kinaan

Cela signifie que les instances de la classe peuvent être transformées en un flux d'octets (par exemple, pour être enregistrées dans un fichier), puis reconverties en classes. Ce rechargement pourrait se produire dans une autre instance du programme, voire sur une autre machine. La sérialisation (quelle que soit la langue) soulève toutes sortes de problèmes, en particulier lorsque vous avez des références à d'autres objets à l'intérieur de l'objet sérialisable.

35
David

Voici une explication détaillée de la sérialisation : (mon propre blog)

Sérialisation:

La sérialisation est le processus de sérialisation de l'état d'un objet qui est représenté et stocké sous la forme d'une séquence d'octets. Cela peut être stocké dans un fichier. Le processus permettant de lire l'état de l'objet à partir du fichier et de le restaurer s'appelle une désérialisation.

Quel est le besoin de sérialisation?

Dans l'architecture moderne, il est toujours nécessaire de stocker l'état de l'objet, puis de le récupérer. Par exemple, dans Hibernate, pour stocker un objet, nous devons rendre la classe Serializable. Ce qu’il fait, c’est que, une fois que l’objet est sauvegardé sous forme d’octets, il peut être transféré à un autre système, qui peut alors lire l’état et récupérer la classe. L'état de l'objet peut provenir d'une base de données ou d'un autre gestionnaire de volume ou d'un composant distinct. Avec l'aide de la sérialisation, nous pouvons récupérer l'état de l'objet.

Exemple de code et explication:

Voyons d'abord la classe d'objets:

public class Item implements Serializable{

    /**
    *  This is the Serializable class
    */
    private static final long serialVersionUID = 475918891428093041L;
    private Long itemId;
    private String itemName;
    private transient Double itemCostPrice;
    public Item(Long itemId, String itemName, Double itemCostPrice) {
        super();
        this.itemId = itemId;
        this.itemName = itemName;
        this.itemCostPrice = itemCostPrice;
      }

      public Long getItemId() {
          return itemId;
      }

     @Override
      public String toString() {
          return "Item [itemId=" + itemId + ", itemName=" + itemName + ", itemCostPrice=" + itemCostPrice + "]";
       }


       public void setItemId(Long itemId) {
           this.itemId = itemId;
       }

       public String getItemName() {
           return itemName;
       }
       public void setItemName(String itemName) {
            this.itemName = itemName;
        }

       public Double getItemCostPrice() {
            return itemCostPrice;
        }

        public void setItemCostPrice(Double itemCostPrice) {
             this.itemCostPrice = itemCostPrice;
        }
}

Dans le code ci-dessus, on peut voir que Item La classe implémente Serializable.

C'est l'interface qui permet à une classe d'être sérialisable.

Nous pouvons maintenant voir qu'une variable appelée serialVersionUID est initialisée à la variable Long. Ce nombre est calculé par le compilateur en fonction de l'état de la classe et des attributs de la classe. C'est le numéro qui aidera le JVM à identifier l'état d'un objet lorsqu'il lit l'état de l'objet à partir du fichier.

Pour cela, nous pouvons consulter la documentation officielle d’Oracle:

L'exécution de la sérialisation associe à chaque classe sérialisable un numéro de version, appelé serialVersionUID, utilisé lors de la désérialisation pour vérifier que l'expéditeur et le destinataire d'un objet sérialisé ont chargé pour cet objet des classes compatibles avec la sérialisation. Si le destinataire a chargé une classe pour l'objet dont l'ID de série est différent de celui de la classe de l'expéditeur correspondante, la désérialisation donnera lieu à une exception InvalidClassException. Une classe sérialisable peut déclarer explicitement son propre serialVersionUID en déclarant un champ nommé "serialVersionUID" qui doit être statique, final et de type long: ANY-ACCESS-MODIFIER statique final long serialVersionUID = 42L; Si une classe sérialisable ne déclare pas explicitement un serialVersionUID, l'exécution de la sérialisation calculera alors une valeur par défaut serialVersionUID pour cette classe, en fonction de divers aspects de la classe, comme décrit dans la spécification de sérialisation d'objet Java (TM). Cependant, il est vivement recommandé que toutes les classes sérialisables déclarent explicitement les valeurs serialVersionUID, car le calcul par défaut serialVersionUID est très sensible aux détails de classe qui peuvent varier en fonction de l'implémentation du compilateur et peuvent donc entraîner des exceptions InvalidClassException inattendues lors de la désérialisation. Par conséquent, pour garantir une valeur serialVersionUID cohérente dans différentes implémentations du compilateur Java, une classe sérialisable doit déclarer une valeur serialVersionUID explicite. Il est également vivement recommandé que les déclarations serialVersionUID explicites utilisent le modificateur privé dans la mesure du possible, car ces déclarations ne s'appliquent qu'à la classe à déclaration immédiate - les champs serialVersionUID ne sont pas utiles en tant que membres hérités.

Si vous avez remarqué qu'il existe un autre mot clé que nous avons utilisé, à savoir transitoire.

Si un champ n'est pas sérialisable, il doit être marqué comme étant transitoire. Ici, nous avons marqué le itemCostPrice comme transitoire et ne voulons pas que cela soit écrit dans un fichier

Voyons maintenant comment écrire l'état d'un objet dans le fichier et le lire à partir de là.

public class SerializationExample {

    public static void main(String[] args){
        serialize();
       deserialize();
    } 

    public static void serialize(){

         Item item = new Item(1L,"Pen", 12.55);
         System.out.println("Before Serialization" + item);

         FileOutputStream fileOut;
         try {
             fileOut = new FileOutputStream("/tmp/item.ser");
             ObjectOutputStream out = new ObjectOutputStream(fileOut);
             out.writeObject(item);
             out.close();
             fileOut.close();
             System.out.println("Serialized data is saved in /tmp/item.ser");
           } catch (FileNotFoundException e) {

                  e.printStackTrace();
           } catch (IOException e) {

                  e.printStackTrace();
           }
      }

    public static void deserialize(){
        Item item;

        try {
                FileInputStream fileIn = new FileInputStream("/tmp/item.ser");
                ObjectInputStream in = new ObjectInputStream(fileIn);
                item = (Item) in.readObject();
                System.out.println("Serialized data is read from /tmp/item.ser");
                System.out.println("After Deserialization" + item);
        } catch (FileNotFoundException e) {
                e.printStackTrace();
        } catch (IOException e) {
               e.printStackTrace();
        } catch (ClassNotFoundException e) {
               e.printStackTrace();
        }
     }
}

Dans ce qui précède, nous pouvons voir un exemple de sérialisation et de désérialisation d'un objet.

Pour cela nous avons utilisé deux classes. Pour sérialiser l'objet, nous avons utilisé ObjectOutputStream. Nous avons utilisé la méthode writeObject pour écrire l'objet dans le fichier.

Pour la désérialisation, nous avons utilisé ObjectInputStream, qui lit l'objet à partir du fichier. Il utilise readObject pour lire les données d'objet à partir du fichier.

La sortie du code ci-dessus serait comme:

Before SerializationItem [itemId=1, itemName=Pen, itemCostPrice=12.55]
Serialized data is saved in /tmp/item.ser
After DeserializationItem [itemId=1, itemName=Pen, itemCostPrice=null]

Notez que itemCostPrice de l'objet désérialisé est null comme il n'a pas été écrit.

12
Pritam Banerjee

La sérialisation implique de sauvegarder l'état actuel d'un objet dans un flux et de restaurer un objet équivalent à partir de ce flux. Le flux fonctionne comme un conteneur pour l'objet

11
Jigar Joshi

Serializable est appelé comme une interface, mais plutôt comme un drapeau du compilateur. Il dit que cet objet peut être enregistré. Toutes les variables d'instance Objects à l'exception des objets non sérialisables et marqués comme volatiles seront sauvegardées.

Imaginez que votre application puisse changer de couleur en tant qu'option, sans conserver ce paramètre en externe, vous auriez besoin de changer la couleur à chaque fois que vous l'exécutiez.

5
AphexMunky

La sérialisation est une technique permettant de stocker ou d'écrire les objets et les données dans des fichiers. En utilisant les classes ObjectOutputStream et FileOutputStream. Ces classes ayant leurs méthodes spécifiques pour persister les objets. comme writeObject();

pour explantaion claire avec des chiffres. Voir ici pour plus d'infos

4
Mdhar9e

Sérialisation: Ecriture de l'état d'un objet dans un fichier/réseau ou n'importe où. (Moyenne Java Objet pris en charge pour enregistrer un formulaire pris en charge ou un formulaire pris en charge réseau)

Désérialisation: Lecture de l'état d'un objet depuis un fichier/réseau ou n'importe où. (Forme de fichier/réseau prise en charge prise en compte pour Java Forme prise en charge par un objet)

2
Asif Mushtaq

Présenter d'un autre point de vue. La sérialisation est une sorte d'interface appelée "interface de marqueur". Une interface de marqueur est une interface qui ne contient aucune déclaration de méthode, mais désigne simplement (ou "marque") une classe qui implémente l'interface comme ayant une propriété. Si vous comprenez le polymorphisme, cela aura beaucoup de sens. Dans le cas de l'interface de marqueur Serializable, la méthode ObjectOutputStream.write (Object) échouera si son argument n'implémente pas l'interface. C'est une erreur potentielle en Java, cela aurait pu être ObjectOutputStream.write (Serializable)

Hautement recommandé: lecture de l’article 37 de Effectif Java par Joshua Bloch pour en savoir plus.

2
nanospeck

Juste pour ajouter aux autres réponses et en ce qui concerne la généralité. La sérialisation est parfois appelée archivage, par exemple en Objective-C.

0
Greg Sexton