2
votes

Différence de désérialisation statique en Java selon le moment de la sérialisation de l'objet

J'essaie de comprendre la (dé /) sérialisation en Java.

J'ai lu que les variables statiques ne sont pas sérialisées.

Pour comprendre cela, j'ai fait un petit exemple:

public static void main(String[] args)  {
        try {
            // Deserialization
            Test deserializedFile = readFile();
            System.out.println(deserializedFile.i);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Pourquoi y a-t-il des différences entre l'exécution de ces deux méthodes principales?

Première version:

Sérialiser et désérialiser en une seule exécution

public static void main(String[] args)  {
        try {
            // Serialization
            writeFile();
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Ceci génère 10 . Mais pourquoi? Je pensais que la valeur de Integer i n'était pas sérialisée, car elle est static.

Deuxième version: Sérialisez et désérialisez en deux exécutions différentes.

Si j'exécute d'abord:

public static void main(String[] args)  {

        try {
            // Serialization
            writeFile();
            // Deserialization
            Test deserializedFile = readFile();
            System.out.println(deserializedFile.i);
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

Et dans une seconde exécution:

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;

public class SerialDemo {

    private static void writeFile() throws IOException, ClassNotFoundException {
        ObjectOutputStream o=new ObjectOutputStream(new FileOutputStream("foo"));
        Test test = new Test();
        o.writeObject(test);
        o.flush();
    }

    private static Test readFile() throws FileNotFoundException, IOException, ClassNotFoundException {
        ObjectInputStream in=new ObjectInputStream(new FileInputStream("foo"));
        return (Test) in.readObject();
    }
}
class Test implements Serializable{
    static Integer i;
    public Test(){
        i = 10;
    }
}


4 commentaires

Ne définissez pas de variables statiques dans les constructeurs: les variables statiques appartiennent à une classe, pas à une instance. Définissez-les soit directement sur les champs, soit dans des initialiseurs statiques.


@GhostCat et à vous. Vous partez pour le 100 km cette année?


@GhostCat hausse les épaules. Le vrai travail continue de vous gêner.


J'apprécie l'acceptation rapide!


3 Réponses :


2
votes

Dans votre premier exemple, la valeur 10 est toujours située dans la variable statique i puisqu'elle se trouve dans la même exécution. Il n'est pas réellement chargé par la méthode readFile () .

Dans votre deuxième exemple, la valeur est toujours 10 dans la première exécution, mais dans la deuxième exécution, c'est la valeur par défaut null (le constructeur n'est pas encore appelé), l'appel de readFile () ne charge pas réellement les valeurs dans i .


Essayez d'appeler deserializedFile.i = null; avant readFile () dans votre premier exemple, et vous remarquerez que le même comportement se produit que dans votre deuxième exemple.

/ p>


1 commentaires

Merci pour la modification. Et votez, car nous sommes presque arrivés dans la même minute :-)



1
votes

Il fonctionne comme prévu. Lors de votre première exécution, la variable i n'est pas sérialisée. Ce que vous voyez est la valeur qui a été définie dans le constructeur Test et parce que sa valeur statique est la même pour tous les objets de la même classe.

Dans votre deuxième exécution, vous ne créez pas la classe Test via le constructeur donc la valeur n'est pas définie. La désérialisation n'appelle pas le constructeur Test et ne désérialise pas la valeur i, donc vous voyez la valeur nulle de sortie correcte.


0 commentaires

2
votes

Simple: c'est une variable statique. Il est initialisé dans votre premier exemple, lorsque vous créez une instance à l'aide du constructeur!

Dans le deuxième exemple, ce constructeur n'est jamais appelé, le champ reste nul!

C'est tout ce qu'il y a à faire. Et comme vous l'avez dit vous-même: le champ statique n'est pas écrit dans ce fichier. La seule chose qui compte dans vos deux exemples est qu'une version appelle le constructeur, et l'autre pas.

Au-delà de cela, il y a une autre idée fausse ici: vous écrivez deserializedFile.i ... C'est conceptuellement faux. Vous devriez utiliser Test.i à la place. Les variables statiques sont les mêmes pour toutes les instances, leur portée est la classe Test, pas une instance de cette classe!

Et juste pour information: deserializedFile est un nom très trompeur. Cette variable représente un objet Test désérialisé. Ce n'est pas dans un fichier! Les noms doivent dire de quoi ils parlent et ne pas mentir. Ce nom ment!


0 commentaires