Les exemples de cet article décrivent la sérialisation et la désérialisation d'objets en Java. Partagez-le avec tout le monde pour votre référence. Les détails sont les suivants :
1. Introduction
La sérialisation d'objet (sérialisable) fait référence au processus de conversion d'un objet en séquence d'octets, tandis que la désérialisation est le processus de restauration d'un objet basé sur une séquence d'octets.
La sérialisation est généralement utilisée dans les scénarios suivants :
1. Enregistrez définitivement l'objet et enregistrez la séquence d'octets de l'objet dans un fichier local
2. réseau Passer des objets ;
3. Passer des objets entre les processus via la sérialisation.
La classe à laquelle appartient l'objet doit implémenter l'interface Serialisable ou Externalisable pour être sérialisée. Pour les classes qui implémentent l'interface Serialisable, la méthode de sérialisation par défaut est utilisée pour la sérialisation et la désérialisation. L'interface Externalisable est une interface qui hérite de l'interface Serialisable et est une extension des classes Serialisable qui implémentent l'interface Externalisable contrôlent complètement la sérialisation et la désérialisation. eux-mêmes.
Java.io.ObjectOutputStream représente le flux de sortie de l'objet. Sa méthode writeObject(Object obj) peut réaliser la sérialisation de l'objet et écrire la séquence d'octets obtenue dans le flux de sortie cible.
Java.io.ObjectInputStream représente le flux d'entrée de l'objet. Sa méthode readObject() peut lire la séquence d'octets du flux d'entrée source, la désérialiser en un objet et la renvoyer.
2. Plusieurs méthodes de sérialisation
Supposons qu'une classe Customer soit définie En fonction de la manière dont le Client implémente la sérialisation, il peut y avoir les méthodes de sérialisation suivantes :
1. Implémentez les méthodes readObject et writeObject sérialisables et non définies
ObjectOutputStream utilise la méthode par défaut du JDK pour sérialiser les variables d'instance non transitoires de l'objet Customer
ObjectInputStream utilise la méthode par défaut du JDK pour sérialiser les variables d'instance non transitoires de ; l'objet Customer Les variables d'instance sont désérialisées.
2. Implémentez Seriallessly et définissez les méthodes readObject et writeObject
ObjectOutputStream appelle la méthode writeObject (ObjectOutputStream out) de la classe Customer pour sérialiser les variables d'instance non transitoires de l'objet Customer ; 🎜 >ObjectInputStream appelle la méthode readObject(ObjectInputStream in) de la classe Customer pour désérialiser les variables d'instance non transitoires de l'objet Customer.
ObjectInputStream ; transmet la méthode writeExternal de la classe Customer. Le constructeur sans paramètre instancie un objet, puis utilise la méthode readExternal pour désérialiser les variables d'instance non transitoires de l'objet Customer.
private void readObject(java.io.ObjectInputStream in) lance IOException, ClassNotFoundException;
private void readObjectNoData() lance ObjectStreamException;
La méthode readObjectNoData est responsable de l'initialisation de l'état de l'objet d'une classe spécifique dans les cas où le flux de sérialisation ne répertorie pas la classe donnée comme superclasse de l'objet à désérialiser. Cela se produit lorsque le destinataire utilise une version de la classe d'instance désérialisée différente de celle de l'expéditeur et que la version du destinataire étend une classe qui n'est pas étendue par la version de l'expéditeur. Cela se produira également lorsque le flux de sérialisation a été falsifié ; par conséquent, la méthode readObjectNoData peut être utilisée pour initialiser correctement l'objet désérialisé, que le flux source soit « hostile » ou incomplet.
Lors de l'écriture d'un objet dans un flux, vous devez spécifier la classe sérialisable de l'objet de remplacement à utiliser. Cette méthode spéciale doit être implémentée avec la signature exacte :
Objet ANY-ACCESS-MODIFIER. writeReplace() lance ObjectStreamException ;
Cette méthode writeReplace sera appelée par sérialisation si cette méthode existe et si elle est accessible via une méthode définie dans la classe de l'objet en cours de sérialisation. Par conséquent, la méthode peut avoir un accès privé, protégé et privé du package. L'accès à cette méthode par les sous-classes suit les règles d'accès Java.
Lors de la lecture d'une instance d'une classe à partir d'un flux, vous devez spécifier la signature exacte que la classe alternative doit utiliser pour implémenter cette méthode spéciale.
ANY-ACCESS-MODIFIER Object readResolve() lève ObjectStreamException ;
Cette méthode readResolve suit les mêmes règles d'appel et d'accès que writeReplace.
Si une classe définit la méthode readResolve, la méthode readResolve sera appelée à la fin de la désérialisation, et l'objet renvoyé par cette méthode est le résultat final de la désérialisation.
2.serialVersionUID
Le runtime de sérialisation utilise un numéro de version appelé SerialVersionUID à associer à chaque classe sérialisable, qui est utilisé pour vérifier la séquence pendant le processus de désérialisation. Si l'expéditeur et le destinataire d'une sérialisation L'objet a chargé une classe compatible avec la sérialisation pour l'objet. Si le SerialVersionUID de la classe de l'objet chargé par le récepteur est différent du numéro de version correspondant de la classe de l'expéditeur, la désérialisation entraînera une InvalidClassException. Une classe sérialisable peut déclarer explicitement son propre SerialVersionUID en déclarant un champ nommé "serialVersionUID" (qui doit être un champ long et final statique) :
ANY-ACCESS-MODIFIER static final long serialVersionUID = 42L;
Si un sérialisable Si la classe ne déclare pas explicitement un SerialVersionUID, le runtime de sérialisation calculera une valeur SerialVersionUID par défaut pour la classe en fonction des aspects de la classe, comme spécifié dans la « Spécification de sérialisation d'objet Java(TM) » indiquée dans. Cependant, il est fortement recommandé que toutes les classes sérialisables déclarent explicitement une valeur SerialVersionUID. La raison en est que le calcul de la valeur SerialVersionUID par défaut est très sensible aux détails de la classe et peut varier considérablement en fonction de l'implémentation du compilateur, de sorte que pendant le processus de désérialisation. provoquer une InvalidClassException inattendue. Par conséquent, pour garantir la cohérence des valeurs SerialVersionUID dans les différentes implémentations du compilateur Java, les classes de sérialisation doivent déclarer une valeur SerialVersionUID explicite. Il est également fortement recommandé de déclarer explicitement SerialVersionUID en utilisant le modificateur private (si possible), la raison étant qu'une telle déclaration ne doit être utilisée que pour déclarer directement des classes -- le champ SerialVersionUID n'est d'aucune utilité en tant que membre hérité. Les classes de tableau ne peuvent pas déclarer de SerialVersionUID explicite, elles ont donc toujours une valeur calculée par défaut, mais il n'est pas nécessaire que les classes de tableau correspondent à la valeur de SerialVersionUID.
3.Interface Externalisable
Externalisable est une extension de Serailizing La sérialisation d'une classe qui implémente l'interface Externalisable a les caractéristiques suivantes :
Appelez la méthode de classe writeExternal pendant la sérialisation et appelez. lors de la désérialisation. méthode readExternal ;
appelle d'abord le constructeur sans paramètre de la classe lors de la désérialisation. Par conséquent, pour les classes qui implémentent l'interface Externalisable, une classe doit être fournie. constructeur sans paramètre, sinon une exception se produira lors de la désérialisation.
4. Résumé
Si la méthode de sérialisation par défaut est utilisée, tant qu'une classe implémente l'interface Serialisable, ses instances peuvent être sérialisées. Généralement, les classes conçues spécifiquement pour l'héritage devraient essayer de ne pas implémenter l'interface Serialisable, car une fois que la classe parent implémente l'interface Serialisable, toutes ses sous-classes sont également sérialisables.
Inconvénients de la méthode de sérialisation par défaut :
1. Il n'est pas sûr de sérialiser directement des données sensibles d'objets qui ne doivent pas être divulguées au public
2. vérifiez si les variables membres de l'objet répondent aux contraintes correctes, et les données peuvent être falsifiées, provoquant un fonctionnement anormal
3. Il est nécessaire de parcourir le graphe de l'objet de manière récursive. Si le graphe de l'objet est très complexe, il le fera. consomme beaucoup de ressources, et le paramètre provoquera un débordement de Java Stack de la machine virtuelle ;
4 Rendre l'interface de la classe contrainte par l'implémentation interne de la classe, limitant la mise à niveau et la maintenance de la classe.
En implémentant les types privés writeObject() et readObject() de l'interface Serialisable, ou en implémentant l'interface Externalisable, en implémentant les méthodes writeExternal() et readExternal() et en fournissant deux constructeurs de type public sans paramètre. contrôler le processus de sérialisation peut efficacement éviter les défauts de la méthode de sérialisation par défaut.
J'espère que cet article sera utile à la programmation Java de chacun.
Pour des articles plus détaillés sur la sérialisation et la désérialisation d'objets en Java, veuillez faire attention au site Web PHP chinois !