Cet article décrit la sérialisation des objets et la désérialisation en Java. Partagez-le pour tout le monde pour votre référence. Les détails sont les suivants:
1. Introduction
La sérialisation des objets fait référence au processus de conversion d'un objet en une 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. Enregistrer l'objet en permanence et enregistrer la séquence d'octets de l'objet au fichier local;
2. Passez des objets dans le réseau en les sérialisant;
3. Passez des objets entre les processus par sérialisation.
La classe à laquelle appartient l'objet doit implémenter l'interface sérialisable ou externalisable à sérialiser. Pour les classes qui implémentent l'interface sérialisable, la sérialisation et la désérialisation adoptent la méthode de sérialisation par défaut.
Java.io.ObjectOutputStream représente le flux de sortie de l'objet, et sa méthode writeObject (objet obj) peut réaliser la sérialisation de l'objet et écrire la séquence d'octet obtenue vers le flux de sortie cible.
Java.io.ObjectInputStream représente le flux d'entrée d'objet, et sa méthode readObject () peut lire une séquence d'octets à partir du flux d'entrée source, le désérialiser dans un objet et le renvoyer.
2. Plusieurs façons de sérialiser
Supposons qu'une classe client soit définie, en fonction de la méthode de sérialisation du client, il peut y avoir les méthodes de sérialisation suivantes:
1. Mettre en œuvre des méthodes sérialisables, non définies en lecture et writeObject
ObjectOutStream utilise JDK pour sérialiser les variables d'instance non transitoires de l'objet client par défaut;
ObjectInputStream désérialise les variables d'instance non transitoires de l'objet client à l'aide de la méthode par défaut JDK.
2. Implémentez les méthodes sérialisables et définissent les méthodes readObject et WriteObject
ObjectOutputStream appelle la méthode writeObject (objectOutputStream out) de la classe client pour sérialiser les variables d'instance non transitoires de l'objet client;
ObjectInputStream appelle la méthode readObject (ObjectInputStream in) de la classe client pour désérialiser les variables d'instance non transitoires de l'objet client.
3. Mettre en œuvre des méthodes externalisables, définissent les méthodes de lecture et d'écriture
ObjectOutputStream appelle la méthode WriteExternal de la classe client pour sérialiser les variables d'instance non transitoires de l'objet client;
ObjectInputStream instancie d'abord un objet via le constructeur sans paramètre de la classe client, puis désérialise la variable d'instance non transitoire de l'objet client à l'aide de la méthode ReadExternal.
3. Interface sérialisable
La classe permet sa fonctionnalité de sérialisation en implémentant l'interface java.io.Serializable. Les classes qui n'implémentent pas cette interface ne pourront sérialiser ou désérialiser aucun de leurs États. Tous les sous-types d'une classe sérialisable sont eux-mêmes sérialisables. L'interface de sérialisation n'a pas de méthodes ou de champs et n'est utilisé que pour identifier la sémantique sérialisable.
Pendant le processus de désérialisation, les champs de la classe non sérialisée seront initialisés à l'aide du constructeur sans paramètre commun ou protégé de la classe. La sous-classe sérialisable doit être capable d'accéder au constructeur sans paramètre. Les champs qui peuvent être des sous-classes sérialisables seront restaurés à partir du flux.
Lorsque vous traversez une vue de classe, vous pouvez rencontrer des objets qui ne prennent pas en charge l'interface sérialisable. Dans ce cas, une NotSerializableException est lancée et la classe qui n'est pas sérialisable est identifiée.
1. Signature précise
Les classes qui nécessitent un traitement spécial pendant la sérialisation et la désérialisation doivent mettre en œuvre des méthodes spéciales en utilisant les signatures précises suivantes:
private void writeObject (java.io.objectoutputStream out) lance ioException
private void readObject (java.io.objectInputStream in) lève ioException, classNotFoundException;
private void readObjectNodata () lève ObjectStreamException;
La méthode WriteObject est responsable de l'écriture de l'état d'un objet d'une classe spécifique afin que la méthode ReadObject correspondante puisse la restaurer. Le mécanisme par défaut pour enregistrer les champs de l'objet peut être appelé en appelant.defaultwriteObject. La méthode elle-même n'a pas besoin d'impliquer des états appartenant à sa superclasse ou à sa sous-classe. L'état peut être enregistré en écrivant des champs individuels sur objectOutputStream à l'aide de la méthode WriteObject ou en utilisant la méthode prise en charge par DataOutput pour les types de données de base.
La méthode ReadObject est responsable de la lecture et de la restauration des champs de classe du flux. Il peut appeler In.defaulTreadObject pour appeler le mécanisme par défaut pour restaurer les champs non statiques et non transitoires de l'objet. La méthode DefaulTreadObject utilise des informations dans le flux pour allouer des champs d'objets dans le flux qui sont enregistrés via les champs spécifiés correspondants dans l'objet actuel. Ceci est utilisé pour gérer les situations où de nouveaux champs doivent être ajoutés après l'évolution des classes. La méthode elle-même n'a pas besoin d'impliquer des états appartenant à sa superclasse ou sous-classe. L'état peut être enregistré en écrivant des champs individuels sur objectOutputStream à l'aide de la méthode WriteObject ou en utilisant la méthode prise en charge par DataOutput pour les types de données de base.
Dans le cas où le flux de sérialisation ne répertorie pas la classe donnée comme la superclasse à désérialiser, la méthode readObjectNodata est responsable de l'initialisation de l'état d'objet d'une classe spécifique. Cela se produit lorsque la classe d'instance désérialisée utilisée par le récepteur est différente de l'expéditeur et que la classe étendue par la version du récepteur n'est pas une classe étendue par la version de l'expéditeur. Il se produit également lorsque le flux de sérialisation a été falsifié;
Lorsque vous écrivez des objets sur un flux, vous devez spécifier la classe sérialisable de l'objet alternatif à utiliser, et vous devez implémenter cette méthode spéciale avec une signature précise:
L'objet de modificateur de tout accessible WriteRereplace () lève ObjectStreamException;
Cette méthode WriteRereplace sera appelée par sérialisation, à condition que si cette méthode existe, et elle peut être accessible par une méthode définie dans la classe de l'objet sérialisé. Par conséquent, la méthode peut avoir un accès privé, protégé et privé de package. L'accès à la sous-classe à cette méthode suit les règles d'accès Java.
Lorsque vous lisez 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.
L'objet du modificateur any-accès ReadResolve () lève ObjectStreamException;
Cette méthode ReadResolve suit les mêmes règles d'appel et les règles d'accès que WriteRereplace.
Si une classe définit une méthode ReadResolve, la méthode ReadResolve sera appelée à la fin de la désérialisation, et l'objet renvoyé par la 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 pour s'associer à chaque classe sérialisable, qui est utilisée pendant la désérialisation pour vérifier que l'expéditeur et le récepteur de l'objet sérialisé chargé pour l'objet. Si le récepteur charge le SerialVersionUid de la classe de l'objet différent du numéro de version de l'expéditeur correspondant, la désérialisation se traduira par une invalidclassexception. Une classe sérialisable peut déclarer explicitement son propre SerialVersionUid en déclarant un champ nommé "SerialVersionUID" (ce champ doit être un champ long statique et final):
MODIFICATEUR DE L'ACCESSION DU MODIFICE STATIQUE Long SerialVersionUID = 42L;
Si la classe sérialisable ne déclare pas explicitement SerialVersionUID, le runtime de sérialisation calcule la valeur par défaut SerialVersionUid de la classe basée sur divers aspects de la classe, comme décrit dans la spécification de sérialisation des objets "Java (TM)". Cependant, il est fortement recommandé que toutes les classes sérialisables déclarent explicitement les valeurs SerialVersionUid, car le calcul du 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, donc dans le processus de désérialisation, un processus invalidclassexception inattendu, donc dans le processus de désérialisation, un processus invalidclassexception inattendu peut en résulter. Par conséquent, pour garantir la cohérence entre les valeurs de SErialVersionUid à travers différents compilateurs Java, la classe sérialisée doit déclarer une valeur explicite SerialVersionuid. Il est également fortement recommandé d'utiliser le modificateur privé pour afficher la déclaration SerialVersionUID si possible, car ces déclarations ne sont utilisées que pour déclarer directement la classe - le champ SerialVersionUid en tant que membre hérité n'est d'aucune utilité. Les classes de tableaux ne peuvent pas déclarer un SerialVersionUID explicite, ils ont donc toujours la valeur calculée par défaut, mais les classes de tableaux ne correspondent pas aux exigences de valeur SerialVersionUid.
3. Interface externalisable
Externalisable est une extension de sérailisable.
Appelez la méthode de la classe écritexternal pendant la sérialisation et désérialisez la méthode ReadExternal;
Lors de la désérialisation, le constructeur sans paramètres de la classe est appelé d'abord, ce qui est différent de la désérialisation par défaut.
Quatrièmement, résumé
Si la méthode de sérialisation par défaut est adoptée, tant qu'une classe implémente l'interface sérialisable, son instance peut être sérialisée. Généralement, les classes conçues spécifiquement pour l'héritage devraient essayer de ne pas implémenter l'interface sérialisable, car une fois que la classe parent a mis en œuvre l'interface sérialisable, toutes ses sous-classes sont sérialisables.
Les lacunes 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 qui ne conviennent pas à la divulgation de l'objet;
2. Il ne vérifiera pas si les variables membre de l'objet respectent les contraintes correctes et peuvent être falsifiées des données et provoquer un fonctionnement anormal;
3. La traversée récursive du graphique de l'objet est requise.
4. Rendez l'interface de la classe limitée par la mise en œuvre interne de la classe, restreignant la mise à niveau et la maintenance de la classe.
En implémentant le type privé writeObject () et readObject () de l'interface sérialisable, ou implémentant l'interface externalisable, implémentant les méthodes de WriteExternal () et ReadExternal (), et en fournissant un constructeur sans paramètre de type public deux façons de contrôler le processus de sérialisation informatique informatique informatique de type public. peut éviter efficacement les lacunes de la méthode de sérialisation par défaut.
On espère que cet article est utile à la conception du programme Java de tous.