Guide de l’interface externalizable en Java

Guide de l'interface externalizable en Java

1. introduction

Dans ce didacticiel,we’ll have a quick look at java’s java.io.Externalizable interface. L'objectif principal de cette interface est de faciliter la sérialisation et la désérialisation personnalisées.

Avant de continuer, assurez-vous de consulter l'article deserialization in Java. Le chapitre suivant explique comment sérialiser un objet Java avec cette interface.

Après cela, nous allons discuter des principales différences par rapport à l'interfacejava.io.Serializable.

2. The InterfaceExternalizable

Externalizable s'étend de l'interface du marqueurjava.io.Serializable. Any class that implements Externalizable interface should override the writeExternal(), readExternal() methods. De cette façon, nous pouvons modifier le comportement de sérialisation par défaut de la JVM.

2.1. La sérialisation

Jetons un œil à cet exemple simple:

public class Country implements Externalizable {

    private static final long serialVersionUID = 1L;

    private String name;
    private int code;

    // getters, setters

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeUTF(name);
        out.writeInt(code);
    }

    @Override
    public void readExternal(ObjectInput in)
      throws IOException, ClassNotFoundException {
        this.name = in.readUTF();
        this.code = in.readInt();
    }
}

Ici, nous avons défini une classeCountry qui implémente l'interfaceExternalizable et implémente les deux méthodes mentionnées ci-dessus.

In the writeExternal() method, we’re adding the object’s properties to the ObjectOutput stream. Cela a des méthodes standard commewriteUTF() pourString etwriteInt() pour les valeurs int.

Ensuite,for deserializing the object, we’re reading from the ObjectInput streamutilise les méthodesreadUTF(), readInt() pour lire les propriétés dans le même ordre exact dans lequel elles ont été écrites.

Il est recommandé d’ajouter lesserialVersionUID manuellement. S'il est absent, la JVM en ajoutera automatiquement un.

Le numéro généré automatiquement dépend du compilateur. Cela signifie qu'il peut provoquer unInvalidClassException improbable.

Testons le comportement que nous avons implémenté ci-dessus:

@Test
public void whenSerializing_thenUseExternalizable()
  throws IOException, ClassNotFoundException {

    Country c = new Country();
    c.setCode(374);
    c.setName("Armenia");

    FileOutputStream fileOutputStream
     = new FileOutputStream(OUTPUT_FILE);
    ObjectOutputStream objectOutputStream
     = new ObjectOutputStream(fileOutputStream);
    c.writeExternal(objectOutputStream);

    objectOutputStream.flush();
    objectOutputStream.close();
    fileOutputStream.close();

    FileInputStream fileInputStream
     = new FileInputStream(OUTPUT_FILE);
    ObjectInputStream objectInputStream
     = new ObjectInputStream(fileInputStream);

    Country c2 = new Country();
    c2.readExternal(objectInputStream);

    objectInputStream.close();
    fileInputStream.close();

    assertTrue(c2.getCode() == c.getCode());
    assertTrue(c2.getName().equals(c.getName()));
}

Dans cet exemple, nous créons d'abord un objetCountry et l'écrivons dans un fichier. Ensuite, nous désérialisons l'objet du fichier et vérifions que les valeurs sont correctes.

La sortie de l'objetc2 imprimé:

Country{name='Armenia', code=374}

Cela montre que nous avons réussi à désérialiser l'objet.

2.2. Héritage

Lorsqu'une classe hérite de l'interfaceSerializable, la JVM collecte automatiquement tous les champs des sous-classes et les rend sérialisables.

Gardez à l'esprit que nous pouvons également l'appliquer àExternalizable. We just need to implement the read/write methods for every sub-class of the inheritance hierarchy.

Regardons la classeRegion ci-dessous qui étend notre classeCountry de la section précédente:

public class Region extends Country implements Externalizable {

    private static final long serialVersionUID = 1L;

    private String climate;
    private Double population;

    // getters, setters

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        super.writeExternal(out);
        out.writeUTF(climate);
    }

    @Override
    public void readExternal(ObjectInput in)
      throws IOException, ClassNotFoundException {

        super.readExternal(in);
        this.climate = in.readUTF();
    }
}

Ici, nous avons ajouté deux propriétés supplémentaires et sérialisé la première.

Notez quewe also called super.writeExternal(out), super.readExternal(in) within serializer methods to save/restore the parent class fields as well.

Lançons le test unitaire avec les données suivantes:

Region r = new Region();
r.setCode(374);
r.setName("Armenia");
r.setClimate("Mediterranean");
r.setPopulation(120.000);

Voici l’objet désérialisé:

Region{
  country='Country{
    name='Armenia',
    code=374}'
  climate='Mediterranean',
  population=null
}

Notez quesince we didn’t serialize the population field in Region class, the value of that property is null.

3. Externalizable contreSerializable

Passons en revue les principales différences entre les deux interfaces:

  • Responsabilité de la sérialisation

La différence clé ici réside dans la manière dont nous gérons le processus de sérialisation. Lorsqu'une classe implémente l'interfacejava.io.Serializable, la JVM prend l'entière responsabilité de la sérialisation de l'instance de classe. In case of Externalizable, it’s the programmer who should take care of the whole serialization and also deserialization process.

  • Cas d'utilisation

Si nous avons besoin de sérialiser l'objet entier, l'interfaceSerializable convient mieux. D'autre part,for custom serialization, we can control the process using Externalizable.

  • Performance

L'interfacejava.io.Serializable utilise la réflexion et les métadonnées qui entraînent des performances relativement lentes. Par comparaison, lesExternalizable interface gives you full control over the serialization process.

  • Ordre de lecture

While using Externalizable, it’s mandatory to read all the field states in the exact order as they were written. Sinon, nous obtiendrons une exception.

Par exemple, si nous modifions l'ordre de lecture des propriétéscode etname dans la classeCountry, unjava.io.EOFException sera lancé.

En attendant, l’interfaceSerializable n’a pas cette exigence.

  • Sérialisation personnalisée

Nous pouvons réaliser une sérialisation personnalisée avec l'interfaceSerializable en marquant le champ avec le mot-clétransient. The JVM won’t serialize the particular field but it’ll add up the field to file storage with the default value. C’est pourquoi il est recommandé d’utiliserExternalizable en cas de sérialisation personnalisée.

4. Conclusion

Dans ce petit guide de l'interfaceExternalizable, nous avons discuté des fonctionnalités clés, des avantages et des exemples illustrés d'utilisation simple. Nous avons également fait une comparaison avec l'interfaceSerializable.

Comme d'habitude, le code source complet du tutoriel est disponibleover on GitHub.