Maison > Java > javaDidacticiel > Explication détaillée de la sérialisation et de la désérialisation d'objets en Java

Explication détaillée de la sérialisation et de la désérialisation d'objets en Java

高洛峰
Libérer: 2017-01-18 11:22:16
original
1422 Les gens l'ont consulté

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.

3. Implémentez Externalisable et définissez les méthodes readExternal et writeExternal

ObjectOutputStream appelle d'abord la méthode writeExternal de la classe Customer pour sérialiser les variables d'instance non transitoires

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.

3. Interface sérialisable

La classe implémente l'interface java.io.Seriallessly pour activer sa fonction de sérialisation. Une classe qui n’implémente pas cette interface ne pourra sérialiser ou désérialiser aucun de ses états. Tous les sous-types d'une classe sérialisable sont eux-mêmes sérialisables. L'interface de sérialisation n'a ni méthode ni champ et est utilisée uniquement pour identifier la sémantique sérialisable.

Lors de la désérialisation, les champs d'une classe non sérialisable sont initialisés à l'aide du constructeur sans paramètre public ou protégé de la classe. Les sous-classes sérialisables doivent avoir accès au constructeur sans paramètre. Les champs des sous-classes sérialisables seront restaurés à partir de ce flux.

Lorsque vous parcourez une vue de classe, vous pouvez rencontrer des objets qui ne prennent pas en charge l'interface Serialisable. Dans ce cas, NotSerializingException sera levée et la classe de l'objet non sérialisable sera identifiée.

1. Signature précise

Les classes qui nécessitent un traitement spécial lors de la sérialisation et de la désérialisation doivent utiliser la signature précise suivante pour implémenter des méthodes spéciales :

private void writeObject( java.io. ObjectOutputStream out) lance IOException

private void readObject(java.io.ObjectInputStream in) lance IOException, ClassNotFoundException;
private void readObjectNoData() lance ObjectStreamException;

la méthode writeObject est responsable de l'écriture L'état de un objet d'une classe spécifique afin que la méthode readObject correspondante puisse le restaurer. Le mécanisme par défaut pour enregistrer les champs d'un objet peut être invoqué en appelant out.defaultWriteObject. La méthode elle-même n’implique pas nécessairement un état appartenant à sa superclasse ou sous-classe. L'état peut être enregistré en écrivant des champs individuels dans un ObjectOutputStream à l'aide de la méthode writeObject ou en utilisant les méthodes prises en charge par DataOutput pour les types de données primitifs.

La méthode readObject est responsable de la lecture et de la restauration des champs de classe à partir du flux. Il peut appeler in.defaultReadObject pour appeler le mécanisme par défaut de restauration des champs non statiques et non transitoires de l'objet. La méthode defaultReadObject utilise les informations du flux pour allouer les champs de l'objet dans le flux détenus par les champs spécifiés correspondants dans l'objet actuel. Ceci est utilisé pour gérer les situations dans lesquelles de nouveaux champs doivent être ajoutés après l'évolution de la classe. La méthode elle-même n’implique pas nécessairement un état appartenant à sa superclasse ou sous-classe. L'état peut être enregistré en écrivant des champs individuels dans un ObjectOutputStream à l'aide de la méthode writeObject ou en utilisant les méthodes prises en charge par DataOutput pour les types de données primitifs.

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 !

Étiquettes associées:
source:php.cn
Déclaration de ce site Web
Le contenu de cet article est volontairement contribué par les internautes et les droits d'auteur appartiennent à l'auteur original. Ce site n'assume aucune responsabilité légale correspondante. Si vous trouvez un contenu suspecté de plagiat ou de contrefaçon, veuillez contacter admin@php.cn
Tutoriels populaires
Plus>
Derniers téléchargements
Plus>
effets Web
Code source du site Web
Matériel du site Web
Modèle frontal