Le livre Effective Java et d'autres sources fournissent une assez bonne explication sur comment et quand utiliser la méthode readObject () lorsque vous travaillez avec des classes Java sérialisables. La méthode readResolve (), en revanche, reste un peu mystérieuse. En gros, tous les documents que j'ai trouvés ne mentionnent qu'un seul des deux ou ne mentionnent les deux qu'individuellement.
Les questions qui restent sans réponse sont:
- Quelle est la différence entre les deux méthodes?
- Quand quelle méthode doit-elle être mise en œuvre?
- Comment utiliser readResolve (), en particulier pour renvoyer quoi?
J'espère que vous pourrez faire la lumière à ce sujet.
java
serialization
singleton
Fourrage
la source
la source
String.CaseInsensitiveComparator.readResolve()
Réponses:
readResolve
est utilisé pour remplacer l'objet lu dans le flux. La seule utilisation que j'ai jamais vue pour cela est l'application de singletons; quand un objet est lu, remplacez-le par l'instance singleton. Cela garantit que personne ne peut créer une autre instance en sérialisant et en désérialisant le singleton.la source
transient
champs.readResolve
est utilisé pour résoudre l'objet après sa lecture. Un exemple d'utilisation est peut-être qu'un objet contient un cache qui peut être recréé à partir de données existantes et qui n'a pas besoin d'être sérialisé; les données mises en cache peuvent être déclaréestransient
etreadResolve()
peuvent les reconstruire après la désérialisation. Ce sont des choses comme ça à quoi sert cette méthode.Serializable
: il dit "Les classes qui doivent désigner un remplaçant lorsqu'une instance de celui-ci est lue à partir du flux doivent implémenter cette [readResolve
] méthode spéciale ...".L'article 90, Effective Java, 3e édition couvre
readResolve
etwriteReplace
pour les proxys série - leur utilisation principale. Les exemples n'écrivent pasreadObject
et leswriteObject
méthodes car ils utilisent la sérialisation par défaut pour lire et écrire des champs.readResolve
est appelé aprèsreadObject
a retourné (à l'inversewriteReplace
est appelé avantwriteObject
et probablement sur un objet différent). L'objet renvoyé par la méthode remplace l'this
objet renvoyé à l'utilisateurObjectInputStream.readObject
et toute autre référence en arrière à l'objet dans le flux. Les deuxreadResolve
etwriteReplace
peuvent renvoyer des objets de types identiques ou différents. Le renvoi du même type est utile dans certains cas où les champs doivent l'êtrefinal
et où la compatibilité descendante est requise ou les valeurs doivent être copiées et / ou validées.L'utilisation de
readResolve
n'applique pas la propriété singleton.la source
readResolve peut être utilisé pour modifier les données sérialisées via la méthode readObject. Par exemple, l'API xstream utilise cette fonctionnalité pour initialiser certains attributs qui n'étaient pas dans le XML à désérialiser.
http://x-stream.github.io/faq.html#Serialization
la source
readResolve est destiné au moment où vous devrez peut-être renvoyer un objet existant, par exemple parce que vous recherchez des entrées en double qui devraient être fusionnées, ou (par exemple dans des systèmes distribués éventuellement cohérents) parce que c'est une mise à jour qui peut arriver avant que vous en soyez conscient toutes les anciennes versions.
la source
readObject () est une méthode existante dans la classe ObjectInputStream.Lors de la lecture de l'objet au moment de la désérialisation, la méthode readObject vérifie en interne si l'objet de classe qui est désérialisé a la méthode readResolve ou non si la méthode readResolve existe, il invoquera la méthode readResolve et retournera la même chose exemple.
Donc, l'intention d'écrire la méthode readResolve est une bonne pratique pour obtenir un modèle de conception de singleton pur où personne ne peut obtenir une autre instance en sérialisant / désérialisant.
la source
readResolve () assurera le contrat singleton lors de la sérialisation.
Veuillez vous référer
la source
Lorsque la sérialisation est utilisée pour convertir un objet afin qu'il puisse être enregistré dans un fichier, nous pouvons déclencher une méthode, readResolve (). La méthode est privée et est conservée dans la même classe dont l'objet est récupéré lors de la désérialisation. Il garantit qu'après la désérialisation, l'objet retourné est le même que celui qui a été sérialisé. C'est,
instanceSer.hashCode() == instanceDeSer.hashCode()
La méthode readResolve () n'est pas une méthode statique. After
in.readObject()
est appelé pendant la désérialisation, il s'assure simplement que l'objet retourné est le même que celui qui a été sérialisé comme ci-dessous tandis queout.writeObject(instanceSer)
De cette manière, cela facilite également l' implémentation du modèle de conception singleton , car chaque fois que la même instance est renvoyée.
la source
Je sais que cette question est vraiment ancienne et a une réponse acceptée, mais comme elle apparaît très haut dans la recherche Google, j'ai pensé que je pèserais car aucune réponse fournie ne couvre les trois cas que je considère importants - dans mon esprit, l'utilisation principale de ceux-ci méthodes. Bien sûr, tous supposent qu'il existe un besoin de format de sérialisation personnalisé.
Prenez, par exemple, les classes de collection. La sérialisation par défaut d'une liste chaînée ou d'un BST entraînerait une énorme perte d'espace avec très peu de gain de performances par rapport à la simple sérialisation des éléments dans l'ordre. Cela est encore plus vrai si une collection est une projection ou une vue - conserve une référence à une structure plus grande que celle qu'elle expose par son API publique.
Si l'objet sérialisé a des champs immuables qui nécessitent une sérialisation personnalisée, la solution d'origine de
writeObject/readObject
est insuffisante, car l'objet désérialisé est créé avant de lire la partie du flux écrite danswriteObject
. Prenez cette implémentation minimale d'une liste chaînée:Cette structure peut être sérialisée en écrivant récursivement le
head
champ de chaque lien, suivi d'unenull
valeur. La désérialisation d'un tel format devient cependant impossible: impossible dereadObject
modifier les valeurs des champs membres (désormais fixées ànull
). Voici la pairewriteReplace
/readResolve
:Je suis désolé si l'exemple ci-dessus ne compile pas (ou ne fonctionne pas), mais j'espère qu'il sera suffisant pour illustrer mon propos. Si vous pensez qu'il s'agit d'un exemple très tiré par les cheveux, rappelez-vous que de nombreux langages fonctionnels fonctionnent sur la JVM et que cette approche devient essentielle dans leur cas.
Nous pouvons souhaiter désérialiser en fait un objet d'une classe différente de celle que nous avons écrite dans le
ObjectOutputStream
. Ce serait le cas avec des vues telles qu'unejava.util.List
implémentation de liste qui expose une tranche d'un plus longArrayList
. De toute évidence, sérialiser toute la liste de sauvegarde est une mauvaise idée et nous ne devrions écrire que les éléments de la tranche visualisée. Pourquoi s'arrêter là cependant et avoir un niveau d'indirection inutile après la désérialisation? Nous pourrions simplement lire les éléments du flux dans unArrayList
et le renvoyer directement au lieu de l'encapsuler dans notre classe de vue.Alternativement, avoir une classe de délégué similaire dédiée à la sérialisation peut être un choix de conception. Un bon exemple serait de réutiliser notre code de sérialisation. Par exemple, si nous avons une classe de générateur (similaire à StringBuilder pour String), nous pouvons écrire un délégué de sérialisation qui sérialise toute collection en écrivant un générateur vide dans le flux, suivi de la taille de la collection et des éléments renvoyés par l'itérateur de la collection. La désérialisation impliquerait la lecture du générateur, l'ajout de tous les éléments lus ultérieurement et le renvoi du résultat final
build()
des déléguésreadResolve
. Dans ce cas, nous aurions besoin d'implémenter la sérialisation uniquement dans la classe racine de la hiérarchie de collection, et aucun code supplémentaire ne serait nécessaire à partir des implémentations actuelles ou futures, à condition qu'elles implémentent abstraititerator()
etbuilder()
méthode (cette dernière pour recréer la collection du même type - ce qui serait une fonctionnalité très utile en soi). Un autre exemple serait d'avoir une hiérarchie de classes dont nous ne contrôlons pas totalement le code - notre (nos) classe (s) de base d'une bibliothèque tierce pourrait avoir n'importe quel nombre de champs privés dont nous ne savons rien et qui peuvent changer d'une version à l'autre, cassant nos objets sérialisés. Dans ce cas, il serait plus sûr d'écrire les données et de reconstruire l'objet manuellement lors de la désérialisation.la source
La méthode readResolve
Pour les classes Serializable et Externalizable, la méthode readResolve permet à une classe de remplacer / résoudre l'objet lu dans le flux avant qu'il ne soit renvoyé à l'appelant. En implémentant la méthode readResolve, une classe peut contrôler directement les types et les instances de ses propres instances en cours de désérialisation. La méthode est définie comme suit:
ANY-ACCESS-MODIFIER Objet readResolve () lance ObjectStreamException;
La méthode readResolve est appelée lorsque ObjectInputStream a lu un objet dans le flux et se prépare à le renvoyer à l'appelant. ObjectInputStream vérifie si la classe de l'objet définit la méthode readResolve. Si la méthode est définie, la méthode readResolve est appelée pour permettre à l'objet du flux de désigner l'objet à renvoyer. L'objet renvoyé doit être d'un type compatible avec toutes les utilisations. S'il n'est pas compatible, une exception ClassCastException sera levée lorsque l'incompatibilité de type est découverte.
Par exemple, une classe Symbol pourrait être créée pour laquelle une seule instance de chaque liaison de symbole existait dans une machine virtuelle. La méthode readResolve serait implémentée pour déterminer si ce symbole était déjà défini et remplacer l'objet Symbol équivalent préexistant pour maintenir la contrainte d'identité. De cette manière, l'unicité des objets Symbol peut être maintenue à travers la sérialisation.
la source
Comme déjà répondu,
readResolve
est une méthode privée utilisée dans ObjectInputStream lors de la désérialisation d'un objet. Ceci est appelé juste avant que l'instance réelle ne soit renvoyée. Dans le cas de Singleton, nous pouvons ici forcer le retour d'une référence d'instance de singleton déjà existante au lieu d'une référence d'instance désérialisée. De même, nous avonswriteReplace
pour ObjectOutputStream.Exemple pour
readResolve
:}
Production:
la source