Quelle est la différence entre Serializable
et Externalizable
en Java?
Quelle est la différence entre Serializable
et Externalizable
en Java?
Réponses:
Pour ajouter aux autres réponses, en implémentant java.io.Serializable
, vous obtenez une capacité de sérialisation "automatique" pour les objets de votre classe. Pas besoin d'implémenter une autre logique, cela ne fera que fonctionner. Le runtime Java utilisera la réflexion pour comprendre comment marshaler et démarsaler vos objets.
Dans la version antérieure de Java, la réflexion était très lente, et donc la sérialisation de graphiques d'objets volumineux (par exemple dans les applications RMI client-serveur) était un peu un problème de performances. Pour gérer cette situation, l' java.io.Externalizable
interface a été fournie, qui est similaire java.io.Serializable
mais avec des mécanismes personnalisés pour effectuer les fonctions de marshaling et de démarshalling (vous devez implémenter readExternal
etwriteExternal
méthodes sur votre classe). Cela vous donne les moyens de contourner le goulot d'étranglement des performances de réflexion.
Dans les versions récentes de Java (à partir de la version 1.3, certainement), les performances de réflexion sont bien meilleures qu'elles ne l'étaient auparavant, et c'est donc beaucoup moins un problème. Je soupçonne que vous auriez du mal à tirer un avantage significatif d' Externalizable
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 constitue un remplacement direct par défaut.
Un gros inconvénient Externalizable
est que vous devez maintenir cette logique vous-même - si vous ajoutez, supprimez ou modifiez un champ dans votre classe, vous devez changer vos méthodes writeExternal
/ readExternal
pour en tenir compte.
En résumé, Externalizable
est une relique des jours Java 1.1. Il n'y en a vraiment plus besoin.
Externalizable
aide beaucoup .
Externalizable
me convient beaucoup mieux, car je ne veux pas générer de tableaux avec des espaces vides ou des objets d'espace réservé, ainsi qu'avec l'interface explicite, vous pouvez gérer l'héritage, ce qui signifie que mon sous synchronisé -class peut facilement ajouter un verrouillage autour de l'appel writeExternal()
. Donc oui, l'externalisable est toujours très pertinent, certainement pour les objets grands ou complexes.
La sérialisation fournit des fonctionnalités par défaut pour stocker et recréer ultérieurement l'objet. Il utilise un format détaillé pour définir le graphique entier des objets à stocker, par exemple, supposons que vous ayez une liste liée et que vous codiez comme ci-dessous, puis la sérialisation par défaut découvrira tous les objets liés et sérialisera. Dans la sérialisation par défaut, l'objet est entièrement construit à 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 (). Ceux-ci sont automatiquement appelés lors de la sérialisation ou de 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 le mot de passe étant une information sensible, je ne le sérialise donc pas dans la méthode writeExternal (ObjectOutput oo) et ne fixe pas la valeur de celui-ci dans readExternal (ObjectInput oi). C'est la flexibilité offerte par Externalizable.
La sortie du code ci-dessus est comme ci-dessous:
userName: nikki passWord: student001 roll: 20
***********************************************************************
userName: nikki passWord: null roll: 20
Nous pouvons observer que nous ne définissons pas la valeur de passWord, il est donc nul.
La même chose peut également être obtenue en déclarant le champ de mot de passe comme transitoire.
private transient String passWord;
J'espère que ça aide. Je m'excuse si j'ai fait des erreurs. Merci.
Différences clés entre Serializable
etExternalizable
Serializable
est une interface de marqueur sans aucune méthode. Externalizable
L'interface contient deux méthodes: writeExternal()
et readExternal()
.Serializable
interface. Le processus de sérialisation défini par le programmeur sera lancé pour les classes implémentant l' Externalizable
interface.Externalizable
interface. Vous pouvez prendre en charge différentes versions de votre objet. Si vous implémentez Externalizable
, il est de votre responsabilité de sérialisersuper
classeSerializable
utilise la réflexion pour construire l'objet et ne nécessite pas de constructeur arg. MaisExternalizable
exige un constructeur public sans argument.Consultez le blog de Hitesh Garg
pour plus de détails.
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 gérer les références et les structures de données complexes, mais finalement cela revient à utiliser le comportement par défaut pour chaque champ de données primitif.
L'externalisation est utilisée dans les rares cas où vous souhaitez 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 disposiez de votre propre schéma d'encodage et de compression.
La sérialisation d'objets utilise les interfaces sérialisables et externalisables. Un objet Java est uniquement sérialisable. si une classe ou l'une de ses superclasses implémente soit l'interface java.io.Serializable, soit sa sous-interface, java.io.Externalizable. La plupart des classes java sont sérialisables .
NotSerializableException
: packageName.ClassName
«Pour participer à un objet de classe dans le processus de sérialisation, la classe doit implémenter une interface sérialisable ou externalisable.La sérialisation des objets produit un flux contenant des informations sur les classes Java pour les objets qui sont enregistrés. Pour les objets sérialisables, des informations suffisantes sont conservées pour restaurer ces objets même si une version différente (mais compatible) de l'implémentation de la classe est présente. L'interface sérialisable est définie pour identifier les classes qui implémentent le protocole sérialisable:
package java.io;
public interface Serializable {};
InvalidClassException
«Dans le processus de désérialisation, si la valeur de la classe serialVersionUID locale est différente de la classe de l'expéditeur correspondant. alors le résultat est en conflit comme
java.io.InvalidClassException: com.github.objects.User; local class incompatible: stream classdesc serialVersionUID = 5081877, local class serialVersionUID = 50818771
Pour les objets externalisables, seule l'identité de la classe de l'objet est enregistrée par le conteneur; la classe doit sauvegarder et restaurer le contenu. L'interface externalisable est définie comme suit:
package java.io;
public interface Externalizable extends Serializable
{
public void writeExternal(ObjectOutput out)
throws IOException;
public void readExternal(ObjectInput in)
throws IOException, java.lang.ClassNotFoundException;
}
OptionalDataException
«Les champs doivent être dans le même ordre et type que nous les avons écrits. S'il y a une incompatibilité de type dans le flux, il lance OptionalDataException.
@Override public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
Les champs d'instance de la classe qui ont écrit (exposés) pour ObjectOutput
être sérialisés.
Exemple « implémente Serializable
class Role {
String role;
}
class User extends Role implements Serializable {
private static final long serialVersionUID = 5081877L;
Integer id;
Address address;
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
}
class Address implements Serializable {
private static final long serialVersionUID = 5081877L;
String country;
}
Exemple « implémente Externalizable
class User extends Role implements Externalizable {
Integer id;
Address address;
// mandatory public no-arg constructor
public User() {
System.out.println("Default Constructor get executed.");
}
public User( String role ) {
this.role = role;
System.out.println("Parametarised Constructor.");
}
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeInt( id );
out.writeUTF( role );
out.writeObject(address);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.id = in.readInt();
this.address = (Address) in.readObject();
this.role = in.readUTF();
}
}
Exemple
public class CustomClass_Serialization {
static String serFilename = "D:/serializable_CustomClass.ser";
public static void main(String[] args) throws IOException {
Address add = new Address();
add.country = "IND";
User obj = new User("SE");
obj.id = 7;
obj.address = add;
// Serialization
objects_serialize(obj, serFilename);
objects_deserialize(obj, serFilename);
// Externalization
objects_WriteRead_External(obj, serFilename);
}
public static void objects_serialize( User obj, String serFilename ) throws IOException{
FileOutputStream fos = new FileOutputStream( new File( serFilename ) );
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
// java.io.NotSerializableException: com.github.objects.Address
objectOut.writeObject( obj );
objectOut.flush();
objectOut.close();
fos.close();
System.out.println("Data Stored in to a file");
}
public static void objects_deserialize( User obj, String serFilename ) throws IOException{
try {
FileInputStream fis = new FileInputStream( new File( serFilename ) );
ObjectInputStream ois = new ObjectInputStream( fis );
Object readObject;
readObject = ois.readObject();
String calssName = readObject.getClass().getName();
System.out.println("Restoring Class Name : "+ calssName); // InvalidClassException
User user = (User) readObject;
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
public static void objects_WriteRead_External( User obj, String serFilename ) throws IOException {
FileOutputStream fos = new FileOutputStream(new File( serFilename ));
ObjectOutputStream objectOut = new ObjectOutputStream( fos );
obj.writeExternal( objectOut );
objectOut.flush();
fos.close();
System.out.println("Data Stored in to a file");
try {
// create a new instance and read the assign the contents from stream.
User user = new User();
FileInputStream fis = new FileInputStream(new File( serFilename ));
ObjectInputStream ois = new ObjectInputStream( fis );
user.readExternal(ois);
System.out.format("Obj[Id:%d, Role:%s] \n", user.id, user.role);
Address add = (Address) user.address;
System.out.println("Inner Obj : "+ add.country );
ois.close();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
@voir
L'interface externalisable n'a pas été réellement fournie pour optimiser les performances du processus de sérialisation! mais pour fournir des moyens d'implémenter votre propre traitement personnalisé et offrir un contrôle complet sur le format et le contenu du flux pour un objet et ses super types!
La mise en œuvre d'AMF (ActionScript Message Format) à distance pour transférer des objets de script d'action natifs sur le réseau en est un exemple.
https://docs.oracle.com/javase/8/docs/platform/serialization/spec/serialTOC.html
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 en conséquence le format par défaut (sérialisable) 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étadonnées de classe précises (le cas échéant) au-delà de l'identification minimale requise de la classe (par exemple, son nom). Cela est clairement souhaitable dans certaines situations, telles que les environnements fermés, où le producteur du flux d'objet et son consommateur (qui réifie l'objet du flux) sont mis en correspondance, et 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 du codage des données dans le flux correspondant aux types Java. Pour un exemple (artificiel), vous souhaiterez peut-être enregistrer booléen vrai comme «Y» et faux comme «N». L'externalisation vous permet de le faire.
Lorsque vous envisagez des options pour améliorer les performances, n'oubliez pas la sérialisation personnalisée. Vous pouvez laisser Java faire ce qu'il fait bien, ou du moins assez bien, gratuitement , et fournir un support personnalisé pour ce qu'il fait mal. Il s'agit généralement de beaucoup moins de code que la prise en charge externe complète.
Il y a tellement de différences entre Serializable et Externalizable, mais lorsque nous comparons la différence entre Serializable personnalisé (écrasé writeObject () & readObject ()) et Externalizable, nous constatons que l'implémentation personnalisée est étroitement liée à la classe ObjectOutputStream où, comme dans le cas externalisable, nous-mêmes fournir une implémentation d'ObjectOutput qui peut être une classe ObjectOutputStream ou une autre comme org.apache.mina.filter.codec.serialization.ObjectSerializationOutputStream
En cas d'interface externalisable
@Override
public void writeExternal(ObjectOutput out) throws IOException {
out.writeUTF(key);
out.writeUTF(value);
out.writeObject(emp);
}
@Override
public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
this.key = in.readUTF();
this.value = in.readUTF();
this.emp = (Employee) in.readObject();
}
**In case of Serializable interface**
/*
We can comment below two method and use default serialization process as well
Sequence of class attributes in read and write methods MUST BE same.
// below will not work it will not work .
// Exception = java.io.StreamCorruptedException: invalid type code: 00\
private void writeObject(java.io.ObjectOutput stream)
*/
private void writeObject(java.io.ObjectOutputStream Outstream)
throws IOException {
System.out.println("from writeObject()");
/* We can define custom validation or business rules inside read/write methods.
This way our validation methods will be automatically
called by JVM, immediately after default serialization
and deserialization process
happens.
checkTestInfo();
*/
stream.writeUTF(name);
stream.writeInt(age);
stream.writeObject(salary);
stream.writeObject(address);
}
private void readObject(java.io.ObjectInputStream Instream)
throws IOException, ClassNotFoundException {
System.out.println("from readObject()");
name = (String) stream.readUTF();
age = stream.readInt();
salary = (BigDecimal) stream.readObject();
address = (Address) stream.readObject();
// validateTestInfo();
}
J'ai ajouté un exemple de code pour mieux expliquer. veuillez archiver / retirer le boîtier d'objet d'Externalisable. Ceux-ci ne sont directement liés à aucune implémentation.
Là où Outstream / Instream sont étroitement liés aux classes. Nous pouvons étendre ObjectOutputStream / ObjectInputStream mais ce sera un peu difficile à utiliser.
Fondamentalement, Serializable
c'est une interface de marqueur qui implique qu'une classe est sûre pour la sérialisation et la JVM détermine comment elle est sérialisée. Externalizable
contient 2 méthodes, readExternal
et writeExternal
. Externalizable
permet à l'implémenteur de décider comment un objet est sérialisé, où comme Serializable
sérialise les objets par défaut.
Quelques différences:
Pour la sérialisation, il n'y a pas besoin de constructeur par défaut de cette classe car Object car JVM le construit à l'aide de Reflection API. En cas d'externalisation, un constructeur sans arg est nécessaire, car le contrôle est en main du programme et plus tard, affectez les données désérialisées à l'objet via des setters.
Dans la sérialisation, si l'utilisateur souhaite ignorer certaines propriétés à sérialiser, il doit marquer ces propriétés comme transitoires, l'inverse n'est pas requis pour l'externalisation.
Lorsqu'une prise en charge de la compatibilité descendante est attendue pour n'importe quelle classe, il est recommandé d'utiliser Externalizable. La sérialisation prend en charge la persistance de defaultObject et si la structure de l'objet est brisée, cela entraînera un problème lors de la désérialisation.