Quelle est la différence entre Serializable
et Externalizable
en Java ?
Réponses
Trop de publicités?Pour ajouter aux autres réponses, en mettant en œuvre java.io.Serializable
vous obtenez une capacité de sérialisation "automatique" pour les objets de votre classe. Il n'est pas nécessaire d'implémenter une autre logique, cela fonctionne tout simplement. Le moteur d'exécution Java utilisera la réflexion pour déterminer comment marshal et unmarshal vos objets.
Dans les versions antérieures de Java, la réflexion était très lente, et la sérialisation de grands graphes d'objets (par exemple dans les applications RMI client-serveur) posait un problème de performance. Pour gérer cette situation, le module java.io.Externalizable
a été fournie, ce qui revient à java.io.Serializable
mais avec des mécanismes personnalisés pour réaliser les fonctions de marshalling et de unmarshalling (vous devez implémenter readExternal
et writeExternal
sur votre classe). Cela vous donne les moyens de contourner le goulot d'étranglement des performances de la réflexion.
Dans les versions récentes de Java (à partir de la version 1.3, en tout cas), les performances de la réflexion sont nettement meilleures qu'auparavant, et le problème est donc beaucoup moins important. Je pense que vous auriez du mal à obtenir un avantage significatif de l'option Externalizable
avec une JVM moderne.
De plus, le mécanisme de sérialisation Java intégré n'est pas le seul, vous pouvez obtenir des remplacements tiers, tels que JBoss Serialization, qui est considérablement plus rapide et remplace directement le mécanisme par défaut.
Un gros inconvénient de Externalizable
c'est que vous devez maintenir cette logique vous-même - si vous ajoutez, supprimez ou modifiez un champ dans votre classe, vous devez modifier votre fichier writeExternal
/ readExternal
des méthodes pour en tenir compte.
En résumé, Externalizable
est une relique de l'époque de Java 1.1. On n'en a plus vraiment besoin.
La sérialisation fournit une fonctionnalité par défaut pour stocker et recréer ultérieurement l'objet. Elle utilise un algorithme complexe pour définir le graphe complet des objets à stocker. Par exemple, supposons que vous ayez une liste chaînée et que vous codiez comme ci-dessous, la sérialisation par défaut découvrira tous les objets qui sont liés et les sérialisera. Dans la sérialisation par défaut, l'objet est construit entièrement à partir de ses bits stockés, sans appel de constructeur.
ObjectOutputStream oos = new ObjectOutputStream(
new FileOutputStream("/Users/Desktop/files/temp.txt"));
oos.writeObject(linkedListHead); //writing head of linked list
oos.close();
Mais si vous voulez une sérialisation restreinte ou si vous ne voulez pas qu'une partie de votre objet soit sérialisée, utilisez Externalizable. L'interface Externalizable étend l'interface Serializable et ajoute deux méthodes, writeExternal() et readExternal(). Celles-ci sont automatiquement appelées pendant la sérialisation ou la désérialisation. En travaillant avec Externalizable, nous devons nous rappeler que le constructeur par défaut doit être public, sinon le code lèvera une exception. Veuillez suivre le code ci-dessous :
public class MyExternalizable implements Externalizable
{
private String userName;
private String passWord;
private Integer roll;
public MyExternalizable()
{
}
public MyExternalizable(String userName, String passWord, Integer roll)
{
this.userName = userName;
this.passWord = passWord;
this.roll = roll;
}
@Override
public void writeExternal(ObjectOutput oo) throws IOException
{
oo.writeObject(userName);
oo.writeObject(roll);
}
@Override
public void readExternal(ObjectInput oi) throws IOException, ClassNotFoundException
{
userName = (String)oi.readObject();
roll = (Integer)oi.readObject();
}
public String toString()
{
StringBuilder b = new StringBuilder();
b.append("userName: ");
b.append(userName);
b.append(" passWord: ");
b.append(passWord);
b.append(" roll: ");
b.append(roll);
return b.toString();
}
public static void main(String[] args)
{
try
{
MyExternalizable m = new MyExternalizable("nikki", "student001", 20);
System.out.println(m.toString());
ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("/Users/Desktop/files/temp1.txt"));
oos.writeObject(m);
oos.close();
System.out.println("***********************************************************************");
ObjectInputStream ois = new ObjectInputStream(new FileInputStream("/Users/Desktop/files/temp1.txt"));
MyExternalizable mm = (MyExternalizable)ois.readObject();
mm.toString();
System.out.println(mm.toString());
}
catch (ClassNotFoundException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
catch(IOException ex)
{
Logger.getLogger(MyExternalizable.class.getName()).log(Level.SEVERE, null, ex);
}
}
}
Ici, si vous commentez le constructeur par défaut, le code lèvera l'exception ci-dessous :
java.io.InvalidClassException: javaserialization.MyExternalizable;
javaserialization.MyExternalizable; no valid constructor.
Nous pouvons observer que comme le mot de passe est une information sensible, je ne le sérialise pas dans la méthode writeExternal(ObjectOutput oo) et je ne fixe pas la valeur de celui-ci dans readExternal(ObjectInput oi). C'est la flexibilité qui est fournie par Externalizable.
Le résultat du code ci-dessus est le suivant :
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Nous pouvons observer que nous ne fixons pas la valeur de passWord et qu'elle est donc nulle.
On peut également obtenir la même chose en déclarant le champ du mot de passe comme transitoire.
private transient String passWord;
J'espère que cela vous aidera. Je m'excuse si j'ai fait des erreurs. Merci.
La sérialisation utilise certains comportements par défaut pour stocker et recréer ultérieurement l'objet. Vous pouvez spécifier dans quel ordre ou comment traiter les références et les structures de données complexes, mais en fin de compte, il s'agit d'utiliser le comportement par défaut pour chaque champ de données primitives.
L'externalisation est utilisée dans les rares cas où vous voulez vraiment stocker et reconstruire votre objet d'une manière complètement différente et sans utiliser les mécanismes de sérialisation par défaut pour les champs de données. Par exemple, imaginez que vous ayez votre propre schéma unique d'encodage et de compression.
http://java.sun.com/j2se/1.3/docs/guide/serialization/spec/serial-arch.doc10.html#4539 http://java.sun.com/j2se/1.3/docs/guide/serialization/spec/serial-arch.doc11.html#4333
La sérialisation par défaut est quelque peu verbeuse, et suppose le scénario d'utilisation le plus large possible de l'objet sérialisé, et par conséquent le format par défaut (Serializable) annote le flux résultant avec des informations sur la classe de l'objet sérialisé.
L'externalisation donne au producteur du flux d'objets un contrôle complet sur les méta-données précises de la classe (s'il y en a) au-delà de l'identification minimale requise de la classe (par exemple son nom). Ceci est clairement souhaitable dans certaines situations, comme les environnements fermés, où le producteur du flux d'objets et son consommateur (qui réifie l'objet à partir du flux) sont appariés, et où des métadonnées supplémentaires sur la classe ne servent à rien et dégradent les performances.
De plus (comme le souligne Uri), l'externalisation permet également un contrôle complet de l'encodage des données dans le flux correspondant aux types Java. Pour un exemple (artificiel), vous pouvez souhaiter enregistrer le booléen true comme 'Y' et false comme 'N'. L'externalisation vous permet de le faire.
Par souci d'exhaustivité, le transient
Le mot clé permet également de combler l'écart entre les deux.
Si vous ne voulez sérialiser qu'une partie de votre objet, il suffit de définir des champs spécifiques en tant que transient
en les marquant comme ne devant pas être persistés, et mettre en oeuvre Serializable
.
- Réponses précédentes
- Plus de réponses