Ce processus peut également être implémenté sur le réseau. Vous pouvez d'abord créer un objet sur une machine Windows, le sérialiser, puis l'envoyer à une machine Unix via le réseau, puis "l'assembler" avec précision là-bas. L'un d'entre eux, comme RMI, Socket, JMS et EJB, pourquoi ils peuvent transférer des objets Java entre eux est bien sûr dû au mécanisme de sérialisation des objets.
Le mécanisme de sérialisation des objets Java a généralement deux utilisations :
JavaBeans de Java : les informations d'état du Bean sont généralement configurées au moment de la conception, et les informations d'état du Bean doivent être stockées afin de restaurer ces informations d'état lorsque. le programme est en cours d'exécution, cela nécessite de sauvegarder l'état de l'objet dans un fichier, puis l'objet peut être reconstruit et l'état du programme peut être restauré en lisant l'état de l'objet.
RMI permet d'exploiter des objets sur une machine distante comme s'ils étaient sur la machine locale ; ou pour les programmes qui utilisent des sockets pour transmettre des objets sur le réseau, ceux-ci nécessitent la mise en œuvre du mécanisme de sérialisation.
Nous pouvons sérialiser une classe en laissant la classe implémenter l'interface Java.io.Serialisisable. Cette interface est une interface de marqueur. Autrement dit, l'interface n'a pas besoin d'implémenter de méthode pour que la classe l'implémente. Il est principalement utilisé pour informer la machine virtuelle Java (JVM) qu'un objet doit être sérialisé.
Pour cela, il y a quelques points sur lesquels nous devons être clairs :
Toutes les classes ne peuvent pas être sérialisées. Sous cmd, nous entrons dans Serialver Java.net.Socket pour savoir si le socket. peut être sérialisé. Information, en fait, le socket n'est pas sérialisable.
Java possède de nombreuses classes de base qui ont implémenté l'interface sérialisable, telles que chaîne, vecteur, etc. Mais par exemple, hashtable n'implémente pas l'interface sérialisable.
Il existe deux classes principales pour lire ou écrire des objets dans des flux : ObjectOutputStream et ObjectInputStream. ObjectOutputStream fournit la méthode writeObject pour écrire des objets dans le flux de sortie, et ObjectInputStream fournit la méthode readObject pour lire les objets à partir du flux d'entrée. Les objets utilisant ces méthodes doivent déjà être sérialisés. Autrement dit, l'interface Serialisable doit avoir été implémentée. Si vous souhaitez écrire un objet de table de hachage, vous obtiendrez une exception.
Le processus de sérialisation consiste à écrire des objets dans le flux d'octets et à lire des objets à partir du flux d'octets. Après avoir converti l'état de l'objet en flux d'octets, vous pouvez utiliser diverses classes de flux d'octets dans le package Java.io pour l'enregistrer dans un fichier, le rediriger vers un autre thread ou envoyer les données de l'objet à un autre hôte via une connexion réseau. La fonction de sérialisation d'objets est très simple et puissante et possède des applications dans RMI, Socket, JMS et EJB. Le problème de la sérialisation des objets n’est pas le sujet le plus passionnant de la programmation réseau, mais il est très important et a de nombreuses implications pratiques.
La sérialisation d'objets peut implémenter des objets distribués. Les principales applications incluent : RMI utilise la sérialisation d'objets pour exécuter des services sur l'hôte distant, tout comme lors de l'exécution d'objets sur la machine locale.
La sérialisation des objets Java conserve non seulement les données d'un objet, mais enregistre également de manière récursive les données de chaque objet référencé par l'objet. L'intégralité de la hiérarchie des objets peut être écrite dans un flux d'octets, qui peut être enregistré dans un fichier ou transmis via une connexion réseau. La sérialisation d'objets peut être utilisée pour effectuer une « copie complète » de l'objet, c'est-à-dire copier l'objet lui-même et l'objet référencé lui-même. La sérialisation d'un objet peut entraîner la séquence d'objets entière.
La sérialisation Java est relativement simple et ne nécessite généralement pas l'écriture de code personnalisé pour enregistrer et restaurer l'état de l'objet. Les objets de classe qui implémentent l'interface Java.io.Serializing peuvent être convertis ou restaurés à partir d'un flux d'octets sans ajouter de code à la classe. Ce n'est que dans de rares cas qu'un code personnalisé sera nécessaire pour enregistrer ou restaurer l'état de l'objet. Notez ici : toutes les classes ne peuvent pas être sérialisées et certaines classes ne peuvent pas être sérialisées. Par exemple, les classes impliquant des threads ont une relation très complexe avec une JVM spécifique.
Mécanisme de sérialisation :
La sérialisation est divisée en deux parties : la sérialisation et la désérialisation. La sérialisation est la première partie du processus, consistant à diviser les données en un flux d'octets afin qu'elles puissent être stockées dans un fichier ou transmises sur le réseau. La désérialisation consiste à ouvrir le flux d'octets et à reconstruire l'objet. La sérialisation des objets convertit non seulement les types de données de base en représentations en octets, mais restaure parfois également les données. La restauration des données nécessite une instance d'objet des données restaurées. Le processus de sérialisation dans ObjectOutputStream est connecté au flux d'octets, y compris les informations sur le type d'objet et la version. Lors de la désérialisation, la JVM utilise les informations d'en-tête pour générer une instance d'objet, puis copie les données du flux d'octets de l'objet vers les membres de données de l'objet. Ci-dessous, nous l'expliquerons en deux parties :
Traitement des flux d'objets : (processus de sérialisation et processus de désérialisation)
Le package Java.io dispose de deux classes pour sérialiser les objets. ObjectOutputStream est responsable de l'écriture des objets dans les flux d'octets et ObjectInputStream reconstruit les objets à partir des flux d'octets.
Commençons par comprendre la classe ObjectOutputStream. La classe ObjectOutputStream étend l'interface DataOutput.
La méthode writeObject() est la méthode la plus importante et est utilisée pour la sérialisation des objets. Si l'objet contient des références à d'autres objets, la méthode writeObject() sérialise ces objets de manière récursive. Chaque ObjectOutputStream gère une table de référence d'objet sérialisée pour éviter l'envoi de plusieurs copies du même objet. (C'est important) Puisque writeObject() peut sérialiser un ensemble complet d'objets référencés, la même instance ObjectOutputStream peut être accidentellement demandée pour sérialiser le même objet. À ce stade, la sérialisation de déréférencement est effectuée au lieu de réécrire le flux d’octets de l’objet.
Maintenant, découvrons la classe ObjectOutputStream à partir d'un exemple.
// 序列化 today's date 到一个文件中. FileOutputStream f = new FileOutputStream ("tmp" ); ObjectOutputStream s = new ObjectOutputStream (f); s.writeObject("Today" ); s.writeObject(new Date ()); s.flush();
Maintenant, comprenons la classe ObjectInputStream. C'est similaire à ObjectOutputStream. Il étend l'interface DataInput. Les méthodes d'ObjectInputStream reflètent les méthodes publiques de DataInputStream pour lire les types de données de base Java. La méthode readObject() désérialise un objet d'un flux d'octets. Chaque fois que la méthode readObject() est appelée, l'objet suivant du flux est renvoyé. Le flux d'octets de l'objet ne transmet pas le bytecode de la classe, mais inclut le nom de la classe et sa signature. Lorsque readObject() reçoit l'objet, la JVM charge la classe spécifiée dans l'en-tête. Si cette classe n'est pas trouvée, readObject() renvoie ClassNotFoundException. Si vous devez transmettre des données d'objet et du bytecode, vous pouvez utiliser le framework RMI. Les méthodes restantes d'ObjectInputStream sont utilisées pour personnaliser le processus de désérialisation.
Un exemple est le suivant :
//从文件中反序列化 string 对象和 date 对象 FileInputStream in = new FileInputStream ("tmp" ); ObjectInputStream s = new ObjectInputStream (in); String today = (String )s.readObject(); Date date = (Date )s.readObject();
Exemple : Une classe de sérialisation très simple.
public class simpleSerializableClass implements Serializable { String sToday="Today:" ; transient Date dtToday=new Date (); }
Lors de la sérialisation, toutes les données membres de la classe doivent être sérialisables, à l'exception des membres déclarés comme transitoires ou statiques. Déclarer une variable comme transitoire indique à la JVM que nous serons responsables de la sérialisation de la variable. Une fois qu'un membre de données est déclaré comme transitoire, le processus de sérialisation ne peut pas l'ajouter au flux d'octets de l'objet. Aucune donnée n'est envoyée depuis le membre de données transitoire. Lorsque les données sont désérialisées ultérieurement, le membre de données doit être reconstruit (car il fait partie de la définition de classe), mais il ne contient aucune donnée car ce membre de données n'écrit aucune donnée dans le flux. N'oubliez pas que les flux d'objets ne sérialisent pas les objets statiques ou transitoires. Notre classe utilisera les méthodes writeObject() et readObject() pour gérer ces données membres. Lorsque vous utilisez les méthodes writeObject() et readObject(), veillez à lire ces données membres dans l'ordre dans lequel elles sont écrites.
Une partie du code sur la façon d'utiliser la sérialisation personnalisée est la suivante
//重写writeObject()方法以便处理transient的成员。 public void writeObject(ObjectOutputStream outputStream) throws IOException { outputStream.defaultWriteObject();//使定制的writeObject()方法可以 //利用自动序列化中内置的逻辑。 outputStream.writeObject(oSocket.getInetAddress()); outputStream.writeInt(oSocket.getPort()); } //重写readObject()方法以便接收transient的成员。 private void readObject(ObjectInputStream inputStream) throws IOException , ClassNotFoundException { inputStream.defaultReadObject();//defaultReadObject()补充自动序列化 InetAddress oAddress=(InetAddress )inputStream.readObject(); int iPort =inputStream.readInt(); oSocket = new Socket (oAddress,iPort); iID=getID(); dtToday =new Date (); }
Personnaliser entièrement le processus de sérialisation :
Si une classe doit être entièrement responsable de sa propre sérialisation, implémentez l'externalisable interface au lieu de l'interface sérialisable. La définition de l'interface externalisable comprend deux méthodes writeExternal() et readExternal(). Ces méthodes peuvent être utilisées pour contrôler la manière dont les données membres de l'objet sont écrites dans le flux d'octets. Lorsqu'une classe implémente Externalisable, l'en-tête est écrit dans le flux d'objets, puis la classe est entièrement responsable de la sérialisation et de la restauration des données membres Except. pour l’en-tête, il n’y a aucune sérialisation automatique. Quelque chose à noter ici. Déclarer une classe pour implémenter l'interface Externalisable présente un risque de sécurité important. Les méthodes writeExternal() et readExternal() sont déclarées publiques et des classes malveillantes peuvent utiliser ces méthodes pour lire et écrire des données d'objet. Soyez extrêmement prudent si l’objet contient des informations sensibles. Cela inclut l'utilisation de sockets sécurisés ou le chiffrement de l'intégralité du flux d'octets. Jusqu'à présent, nous avons appris les bases de la sérialisation.
Pour des explications plus détaillées sur les exemples de base de sérialisation d'objets dans les didacticiels Java et les articles connexes, veuillez faire attention au site Web PHP chinois !