当前位置:网站首页>Sérialisation et déséquençage brisant le mode Singleton pour optimiser le clonage profond

Sérialisation et déséquençage brisant le mode Singleton pour optimiser le clonage profond

2022-01-15 02:41:56 Vers le Haut

1.Sérialisation et désrialisation

​ Java Fournit un objetSérialisationMécanisme.Une séquence d'octets peut représenter un objet,Cette séquence d'octets contientDonnées de l'objetType d'objetEtPropriétés stockées dans l'objetAttendez les informations.Après que la séquence d'octets a été écrite dans le fichier,C'est l'équivalent deConservation durableDes informations sur un objet.

​ Au contraire,Cette séquence d'octets peut également être lue à partir du fichier,Refactor Object,Faites - le.Désérialisation.Données de l'objetType d'objetEtDonnées stockées dans l'objetInformation,Peut être utilisé pour créer des objets en mémoire.

ObjectOutputStreamCatégorie

java.io.ObjectOutputStream Catégorie,Oui.JavaLe type de données original de l'objet est écrit dans le fichier,Mise en œuvre du stockage persistant des objets.

Méthode de construction

  • public ObjectOutputStream(OutputStream out): Créer une affectationOutputStreamDeObjectOutputStream.

Exemple de construction,Les codes sont les suivants::

FileOutputStream fileOut = new FileOutputStream("employee.txt");
ObjectOutputStream out = new ObjectOutputStream(fileOut);

Opération de sérialisation

1.Pour sérialiser un objet,Deux conditions doivent être remplies:

  • Cette classe doit mettre en œuvrejava.io.Serializable Interface,Serializable C'est une interface de marquage,Les classes qui n'implémentent pas cette interface ne sérialiseront ni ne désrialiseront aucun état,Va lancerNotSerializableException .
  • Toutes les propriétés de cette classe doivent être sérialisables.Si une propriété n'a pas besoin d'être sérialisée,L'attribut doit alors indiquer qu'il est transitoire,Utilisertransient Modification des mots clés.

2.Méthode d'écriture de l'objet

  • public final void writeObject (Object obj) : Écrire l'objet spécifié.

ObjectInputStreamCatégorie

ObjectInputStreamFlux de désrialisation,Utiliser avantObjectOutputStreamLes données brutes sérialisées sont restaurées en tant qu'objets.

Méthode de construction

  • public ObjectInputStream(InputStream in): Créer une affectationInputStreamDeObjectInputStream.

Opération de désrialisation1

Si vous pouviez trouver un objetclassDocumentation,Nous pouvons effectuer une opération de désrialisation,AppelezObjectInputStreamMéthode de lecture de l'objet:

  • public final Object readObject () : Lire un objet.

PourJVMLes objets peuvent être désérialisés,Il doit être capable de trouverclassLa classe du fichier.Si vous ne trouvez pasclassDocumentation,Pour lancer un ClassNotFoundException Anomalie.

Opération de désrialisation2

En plus,QuandJVMLors de la désérialisation d'un objet,On peut le trouver.classDocumentation,Maisclass..Le fichier a été modifié après la sérialisation de l'objet,L'opération de désrialisation échouera aussi,Lancer unInvalidClassExceptionAnomalie.

Cette exception s'est produite pour les raisons suivantes:

  • Le numéro de version série de la classe ne correspond pas au numéro de version du descripteur de classe lu à partir du flux
  • Cette classe contient un type de données inconnu
  • La classe n'a pas de méthode de construction accessible sans paramètres

Serializable L'interface donne aux classes qui doivent être sérialisées,Un numéro de version série est fourni.serialVersionUID Le but de ce numéro de version est de vérifier que l'objet sérialisé et la classe correspondante correspondent à la version.

public class Employee implements java.io.Serializable {
    
     // Ajouter le numéro de version série
     private static final long serialVersionUID = 1L;
     public String name;
     public String address;
     // Ajouter une nouvelle propriété ,Recompiler, Peut être désérialisé,Cette propriété est assignée par défaut.
     public int eid; 

     public void addressCheck() {
    
         System.out.println("Address check : " + name + " -- " + address);
     }
}

2.Détruire le mode Singleton

Mode Singleton

public class Singleton implements Serializable {
    

    private static final long serialVersionUID = -4998695514017895268L;

    //1. La méthode de construction de la privatisation 
    private Singleton(){
    

    }

    //2.Classes internes statiques privées
    private static class InnerClass{
    
        //3. Une instance privée statique de cette classe 
        private static Singleton singleton = new Singleton();
    }

    //4. Méthode statique exposée pour obtenir des exemples de cette classe 
    public static Singleton getInstance(){
    
        return InnerClass.singleton;
    }

}
public class SingletonTest {
    

    public static void main(String[] args) {
    
        Singleton s1 = Singleton.getInstance();
        try (
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
        ){
    
            //Sérialisation
            oos.writeObject(s1);
            oos.flush();

            //Désérialisation
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Singleton s2 = (Singleton)ois.readObject();

            // Exemple unique obtenu par test , Ce n'est toujours pas une instance de désrialisation obtenue 
            System.out.println(s1 == s2);  //false 
        } catch (IOException | ClassNotFoundException e) {
    
            e.printStackTrace();
        }
    }

}
/*  J'ai un objet qui n'est pas à la même adresse ,Mode Singleton corrompu Solutions: InSingletonAjouterreadResolve()Méthodes */   
    //Définir unreadResolve(), L'Instance résolue après désrialisation reste cette instance unique 
    public Object readResolve(){
    
        return InnerClass.singleton;
    }

3. La sérialisation elle - même est un clone profond

Quand une classe est associée , La sérialisation est un clone profond , Les objets de la classe associée sont ensuite clonés

La façon de terminer le clonage dans les blogs précédents était

( Student Classe associée Major Catégorie)

//ObjectDans la classeclone
    @Override
    protected Student clone() throws CloneNotSupportedException {
    
        //Clonage superficiel
        //return super.clone();

        //Clonage profond
        Student stu = (Student)super.clone();
        Major major = this.major.clone();
        stu.setMajor(major);

        return stu;
    }

Il y a trop de couplage de classe pour écrire le Code comme ça , Quand une classe est associée à plusieurs classes , Lorsqu'une classe est associée à une autre classe , Pour compléter un clone profond , Chaque classe doit être implémentée CloneableInterface overrideclone()Méthodes,Très fastidieux.

Solutions:

Nous utilisons la sérialisation et la désérialisation pour résoudre ce problème

 //Sérialisation et désrialisation, Terminer le clonage profond 
    @Override
    protected Student clone() throws CloneNotSupportedException {
    
        try (
                ByteArrayOutputStream baos = new ByteArrayOutputStream();
                ObjectOutputStream oos = new ObjectOutputStream(baos);
        ){
    
            //Sérialisation
            oos.writeObject(this);
            oos.flush();

            //Désérialisation
            ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bais);
            Student stu = (Student)ois.readObject();
            return stu;
        } catch (IOException | ClassNotFoundException e) {
    
            e.printStackTrace();
        }
        return null;
    }

ByteArrayInputStream C'est le flux de mémoire ,Le flux de sortie du tableau d'octets crée un tampon de tableau d'octets en mémoire,Toutes les données envoyées au flux de sortie sont sauvegardées dans ce tampon de tableau d'octets

版权声明
本文为[Vers le Haut]所创,转载请带上原文链接,感谢
https://chowdera.com/2022/01/202201080601056188.html

随机推荐