t
t
t
t
t t 11) Le système d’E/S de Java
tttt
11) Le système d’E/S de Java
Texte original t Traducteur : Armel FORTUN
t
t
///
Ce chapitre contient 10 pages
1 2 3 4 5 6 7 8 9 10
\\\
t t t
t t t
t
t t t
To make things interesting, the array of Data objects inside Worm are initialized with random numbers. (This way you don’t suspect the compiler of keeping some kind of meta-information.) Each Worm segment is labeled with a char that’s automatically generated in the process of recursively generating the linked list of Worms. When you create a Worm, you tell the constructor how long you want it to be. To make the next reference it calls the Worm constructor with a length of one less, etc. The final next reference is left as null, indicating the end of the Worm. t Pour rendre les choses intéressantes, les tableaux d'objets Data à l'intérieur de Worm sont initialisés avec des nombres aléatoires. (De cette manière vous ne pourrez suspecter le compilateur de conserver une quelconque sorte de méta-information.) Chaque segment de Worm est étiqueté avec un char qui est généré automatiquement dans un processus de génération récursive de la liste liée de Worms. Quand vous créez un Worm, vous indiquez au constructeur la longueur désirée. Pour créer la référence next il fait appel au constructeur de Worms avec une longueur de moins un, etc. La référence next finale est laissée comme null, indiquant la fin du Worm.
t t t
The point of all this was to make something reasonably complex that couldn’t easily be serialized. The act of serializing, however, is quite simple. Once the ObjectOutputStream is created from some other stream, writeObject( ) serializes the object. Notice the call to writeObject( ) for a String, as well. You can also write all the primitive data types using the same methods as DataOutputStream (they share the same interface). t L'essentiel de tout cela est de rendre quelque chose raisonnablement complexe qui ne puisse pas facilement être sérialisé. L'action de sérialiser, cependant, est plutôt simple. Une fois que l'ObjectOutputStream est crée depuis un autre flux, writeObject() sérialise l'objet. Notez aussi l'appel de writeObject() pour un String. Vous pouvez aussi écrire tous les types de données primitives utilisant les même méthodes qu'DataOutputStream (ils partagent la même interface).
t t t
There are two separate code sections that look similar. The first writes and reads a file and the second, for variety, writes and reads a ByteArray. You can read and write an object using serialization to any DataInputStream or DataOutputStream including, as you will see in the Chapter 15, a network. The output from one run was: t Il y a deux portions de code séparées qui ont une apparence similaire. La première écrit et lit et la seconde, pour varier, écrit et lit un ByteArray. Vous pouvez lire et écrire un objet en utilisant la sérialisation vers n'importe quel DataInputStream ou DataOutputStream incluant, comme vous le verrez dans le Chapitre 15, un réseau. La sortie d'une exécution donne :
t t t
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w2 = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w3 = :a(262):b(100):c(396):d(480):e(316):f(398)
t
Worm constructor: 6
Worm constructor: 5
Worm constructor: 4
Worm constructor: 3
Worm constructor: 2
Worm constructor: 1
w = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w2 = :a(262):b(100):c(396):d(480):e(316):f(398)
Worm storage, w3 = :a(262):b(100):c(396):d(480):e(316):f(398)
t t t
You can see that the deserialized object really does contain all of the links that were in the original object. t Vous pouvez voir que l'objet déserialisé contient vraiment tous les liens qui étaient dans l'objet original.
t t t
Note that no constructor, not even the default constructor, is called in the process of deserializing a Serializable object. The entire object is restored by recovering data from the InputStream. t Notons qu'aucun constructeur, même pas le constructeur par défaut, n'est appelé dans le processus de désérialisation d'un objet Serializable. L'objet entier est restauré par récupération des données depuis l'InputStream.
t t t
Object serialization is byte-oriented, and thus uses the InputStream and OutputStream hierarchies. t La sérialisation objet est orientée-byte, et ainsi emploie les hiérarchies d'InputStream et d'OutputStream.
t t t

Finding the class

t

Trouver la classe

t t t
You might wonder what’s necessary for an object to be recovered from its serialized state. For example, suppose you serialize an object and send it as a file or through a network to another machine. Could a program on the other machine reconstruct the object using only the contents of the file? t Vous devez vous demander ce qui est nécessaire pour qu'un objet soit récupéré depuis son état sérialisé. Par exemple, supposons que vous sérialisez un objet et que vous l'envoyez comme un fichier à travers un réseau vers une autre machine. Un programme sur l'autre machine pourra-t-il reconstruire l'objet en utilisant seulement le contenu du fichier ?
t t t
The best way to answer this question is (as usual) by performing an experiment. The following file goes in the subdirectory for this chapter: t La meilleure manière de répondre a cette question est (comme d'habitude) en accomplissant une expérience. Le fichier suivant file dans le sous-répertoire pour ce chapitre :
t t t
//: c11:Alien.java
// A serializable class.
import java.io.*;

public class Alien implements Serializable {
} ///:~
t
//: c11:Alien.java
// Une classe sérializable.
import java.io.*;

public class Alien implements Serializable {
} ///:~
t t t
The file that creates and serializes an Alien object goes in the same directory: t Le fichier qui crée et sérialise un objet Alien va dans le même répertoire :
t t t
//: c11:FreezeAlien.java
// Create a serialized output file.
import java.io.*;

public class FreezeAlien {
  // Throw exceptions to console:
  public static void main(String[] args)
  throws IOException {
    ObjectOutput out =
      new ObjectOutputStream(
        new FileOutputStream("X.file"));
    Alien zorcon = new Alien();
    out.writeObject(zorcon);
  }
} ///:~
t
//: c11:FreezeAlien.java
// Crée un fichier de sortie sérialisé.
import java.io.*;

public class FreezeAlien {
  // Lance les exeptions vers la console:
  public static void main(String[] args)
  throws IOException {
    ObjectOutput out =
      new ObjectOutputStream(
        new FileOutputStream("X.file"));
    Alien zorcon = new Alien();
    out.writeObject(zorcon);
  }
} ///:~
t t t
Rather than catching and handling exceptions, this program takes the quick and dirty approach of passing the exceptions out of main( ), so they’ll be reported on the command line. t Plutôt que de saisir et de traiter les exeptions, ce programme prend une approche rapide et sale qui passe les exeptions en dehors de main(), ainsi elle seront reportés en ligne de commande.
t t t
Once the program is compiled and run, copy the resulting X.file to a subdirectory called xfiles, where the following code goes: t Une fois que le programme est compilé et exécuté, copiez le X.file résultant dans un sous répertoire appeléxfiles, où va le code suivant :
t t t
//: c11:xfiles:ThawAlien.java
// Try to recover a serialized file without the
// class of object that's stored in that file.
import java.io.*;

public class ThawAlien {
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    ObjectInputStream in =
      new ObjectInputStream(
        new FileInputStream("X.file"));
    Object mystery = in.readObject();
    System.out.println(mystery.getClass());
  }
} ///:~
t
//: c11:xfiles:ThawAlien.java
// Essaye de récupérer un fichier sérialisé sans
// la classe de l'objet qui est stocké dans ce fichier.
import java.io.*;

public class ThawAlien {
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    ObjectInputStream in =      new ObjectInputStream(
        new FileInputStream("X.file"));
    Object mystery = in.readObject();
    System.out.println(mystery.getClass());
  }
} ///:~
t t t
This program opens the file and reads in the object mystery successfully. However, as soon as you try to find out anything about the object—which requires the Class object for Alien—the Java Virtual Machine (JVM) cannot find Alien.class (unless it happens to be in the Classpath, which it shouldn’t be in this example). You’ll get a ClassNotFoundException. (Once again, all evidence of alien life vanishes before proof of its existence can be verified!) t Ce programme ouvre le fichier et lit dans l'objet mystery avec succès. Pourtant, dès que vous essayez de trouver quelque chose à propos de l'objet — qui nécessite l'objet Class pour Alien — la Machine Virtuelle Java (JVM) ne peut pas trouver Alien.class (à moins qu'il arrive qu'il soit dans le Classpath, ce qui n'est pas le cas dans cet exemple). Vous obtiendrez un ClassNotFoundException. (Une fois encore, toute les preuves de l'existence de vie alien disparaît avant que la preuve de son existence soit vérifiée !)
t t t
If you expect to do much after you’ve recovered an object that has been serialized, you must make sure that the JVM can find the associated .class file either in the local class path or somewhere on the Internet. t Si vous espérez en faire plus après avoir récupéré un objet qui a été sérialisé, vous devrez vous assurer que la JVM puisse trouver les fichiers .class soit dans le chemin de class local ou quelque part sur l'Internet.
t t t

Controlling serialization

t

Contrôler la sérialisation

t t t
As you can see, the default serialization mechanism is trivial to use. But what if you have special needs? Perhaps you have special security issues and you don’t want to serialize portions of your object, or perhaps it just doesn’t make sense for one subobject to be serialized if that part needs to be created anew when the object is recovered. t Comme vous pouvez le voir, le mécanisme de sérialisation par défaut est d'un usage trivial. Mais que faire si vous avez des besoins spéciaux ? Peut-être que vous avez des problèmes de sécurité spéciaux et que vous ne voulez pas sérialiser des parties de votre objet, ou peut-être que cela n'a pas de sens pour un sous-objet d'être sérialisé si cette partie doit être de nouveau crée quand l'objet est récupéré.
t t t
You can control the process of serialization by implementing the Externalizable interface instead of the Serializable interface. The Externalizable interface extends the Serializable interface and adds two methods, writeExternal( ) and readExternal( ), that are automatically called for your object during serialization and deserialization so that you can perform your special operations. t Vous pouvez contrôler le processus de sérialisation en implémentant l'interface Externalizable à la place de l'interface Serializable. L'interface Externalizable étend l'interface Serializable et ajoute deux méthodes, writeExternal() et readExternal(), qui sont automatiquement appelées pour votre objet pendant la sérialisation et la désérialisation afin que vous puissiez exécuter vos opérations spéciales.
t t t
The following example shows simple implementations of the Externalizable interface methods. Note that Blip1 and Blip2 are nearly identical except for a subtle difference (see if you can discover it by looking at the code): t L'exemple suivant montre des implémentations simple des méthodes de l'interface Externalizable. Notez que Blip1 et Blip2 sont presque identiques à l'exception d'une subtile différence (voyez si vous pouvez la découvrir en regardant le code) :
t t t
//: c11:Blips.java
// Simple use of Externalizable & a pitfall.
import java.io.*;
import java.util.*;

class Blip1 implements Externalizable {
  public Blip1() {
    System.out.println("Blip1 Constructor");
  }
  public void writeExternal(ObjectOutput out)
      throws IOException {
    System.out.println("Blip1.writeExternal");
  }
  public void readExternal(ObjectInput in)
     throws IOException, ClassNotFoundException {
    System.out.println("Blip1.readExternal");
  }
}

class Blip2 implements Externalizable {
  Blip2() {
    System.out.println("Blip2 Constructor");
  }
  public void writeExternal(ObjectOutput out)
      throws IOException {
    System.out.println("Blip2.writeExternal");
  }
  public void readExternal(ObjectInput in)
     throws IOException, ClassNotFoundException {
    System.out.println("Blip2.readExternal");
  }
}

public class Blips {
  // Throw exceptions to console:
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip1 b1 = new Blip1();
    Blip2 b2 = new Blip2();
    ObjectOutputStream o =
      new ObjectOutputStream(
        new FileOutputStream("Blips.out"));
    System.out.println("Saving objects:");
    o.writeObject(b1);
    o.writeObject(b2);
    o.close();
    // Now get them back:
    ObjectInputStream in =
      new ObjectInputStream(
        new FileInputStream("Blips.out"));
    System.out.println("Recovering b1:");
    b1 = (Blip1)in.readObject();
    // OOPS! Throws an exception:
//! System.out.println("Recovering b2:");
//! b2 = (Blip2)in.readObject();
  }
} ///:~
t
//: c11:Blips.java
// Emploi simple d'Externalizable & un piège.
import java.io.*;
import java.util.*;

class Blip1 implements Externalizable {
  public Blip1() {
    System.out.println("Blip1 Constructor");
  }
  public void writeExternal(ObjectOutput out)
      throws IOException {
    System.out.println("Blip1.writeExternal");
  }
  public void readExternal(ObjectInput in)
     throws IOException, ClassNotFoundException {
    System.out.println("Blip1.readExternal");
  }
}

class Blip2 implements Externalizable {
  Blip2() {
    System.out.println("Blip2 Constructor");
  }
  public void writeExternal(ObjectOutput out)
      throws IOException {
    System.out.println("Blip2.writeExternal");
  }
  public void readExternal(ObjectInput in)
     throws IOException, ClassNotFoundException {
    System.out.println("Blip2.readExternal");
  }
}

public class Blips {
  // Lance les exeptions vers la console :
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip1 b1 = new Blip1();
    Blip2 b2 = new Blip2();
    ObjectOutputStream o =      new ObjectOutputStream(
        new FileOutputStream("Blips.out"));
    System.out.println("Saving objects:");
    o.writeObject(b1);
    o.writeObject(b2);
    o.close();
    //Maintenant faites les revenir :
    ObjectInputStream in =      new ObjectInputStream(
        new FileInputStream("Blips.out"));
    System.out.println("Recovering b1:");
    b1 = (Blip1)in.readObject();
    // OOPS! Lance une exeption :
//! System.out.println("Recovering b2:");
//! b2 = (Blip2)in.readObject();
  }
} ///:~
t t t
The output for this program is: t La sortie pour ce programme est :
t t t
Constructing objects:
Blip1 Constructor
Blip2 Constructor
Saving objects:
Blip1.writeExternal
Blip2.writeExternal
Recovering b1:
Blip1 Constructor
Blip1.readExternal
t
Constructing objects:
Blip1 Constructor
Blip2 Constructor
Saving objects:
Blip1.writeExternal
Blip2.writeExternal
Recovering b1:
Blip1 Constructor
Blip1.readExternal
t t t
The reason that the Blip2 object is not recovered is that trying to do so causes an exception. Can you see the difference between Blip1 and Blip2? The constructor for Blip1 is public, while the constructor for Blip2 is not, and that causes the exception upon recovery. Try making Blip2’s constructor public and removing the //! comments to see the correct results. t La raison pour laquelle l'objet Blip2 n'est pas récupéré est que le fait d'essayer provoque une exeption. Vous pouvez voir la différence entreBlip1 et Blip2 ? Le constructeur de Blip1 est public, tandis que le constructeur de Blip2 ne l'est pas, et cela lance une exeption au recouvrement. Essayez de rendre le constructor de Blip2 public et retirez les commentaires //! pour voir les résultats correct.
t t t
When b1 is recovered, the Blip1 default constructor is called. This is different from recovering a Serializable object, in which the object is constructed entirely from its stored bits, with no constructor calls. With an Externalizable object, all the normal default construction behavior occurs (including the initializations at the point of field definition), and then readExternal( ) is called. You need to be aware of this—in particular, the fact that all the default construction always takes place—to produce the correct behavior in your Externalizable objects. t Quand b1 est récupéré, le constructeur par défaut Blip1 est appelé. Ceci est différent de récupérer un objet Serializable, dans lequel l'objet est construit entièrement de ses bits enregistrés, sans appel au constructeur. Avec un objet Externalizable, tous les comportements de construction par défaut se produisent (incluant les initialisations à ce point du champ de définition), et alors readExternal() est appelé. Vous devez prendre en compte ceci en particulier, le fait que toute la construction par défaut a toujours lieu pour produire le comportement correct dans vos objets Externalizable.
t t t
Here’s an example that shows what you must do to fully store and retrieve an Externalizable object: t Voici un exemple qui montre ce que vous devez faire pour complétement stocker et retrouver un objet Externalizable :
t t t
//: c11:Blip3.java
// Reconstructing an externalizable object.
import java.io.*;
import java.util.*;

class Blip3 implements Externalizable {
  int i;
  String s; // No initialization
  public Blip3() {
    System.out.println("Blip3 Constructor");
    // s, i not initialized
  }
  public Blip3(String x, int a) {
    System.out.println("Blip3(String x, int a)");
    s = x;
    i = a;
    // s & i initialized only in nondefault
    // constructor.
  }
  public String toString() { return s + i; }
  public void writeExternal(ObjectOutput out)
  throws IOException {
    System.out.println("Blip3.writeExternal");
    // You must do this:
    out.writeObject(s);
    out.writeInt(i);
  }
  public void readExternal(ObjectInput in)
  throws IOException, ClassNotFoundException {
    System.out.println("Blip3.readExternal");
    // You must do this:
    s = (String)in.readObject();
    i =in.readInt();
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip3 b3 = new Blip3("A String ", 47);
    System.out.println(b3);
    ObjectOutputStream o =
      new ObjectOutputStream(
        new FileOutputStream("Blip3.out"));
    System.out.println("Saving object:");
    o.writeObject(b3);
    o.close();
    // Now get it back:
    ObjectInputStream in =
      new ObjectInputStream(
        new FileInputStream("Blip3.out"));
    System.out.println("Recovering b3:");
    b3 = (Blip3)in.readObject();
    System.out.println(b3);
  }
} ///:~
t
//: c11:Blip3.java
// Reconstruction d'un objet externalizable.
import java.io.*;
import java.util.*;

class Blip3 implements Externalizable {
  int i;
  String s; // Aucune initialisation
  public Blip3() {
    System.out.println("Blip3 Constructor");
    // s, i n'est pas initialisé
  }
  public Blip3(String x, int a) {
    System.out.println("Blip3(String x, int a)");
    s = x;
    i = a;
    // s & i initialisé seulement dans le non
    // constructeur par défaut.
  }
  public String toString() { return s + i; }
  public void writeExternal(ObjectOutput out)
  throws IOException {
    System.out.println("Blip3.writeExternal");
    // Vous devez faire ceci :
    out.writeObject(s);
    out.writeInt(i);
  }
  public void readExternal(ObjectInput in)
  throws IOException, ClassNotFoundException {
    System.out.println("Blip3.readExternal");
    // Vous devez faire ceci :
    s = (String)in.readObject();
    i =in.readInt();
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    System.out.println("Constructing objects:");
    Blip3 b3 = new Blip3("A String ", 47);
    System.out.println(b3);
    ObjectOutputStream o =      new ObjectOutputStream(
        new FileOutputStream("Blip3.out"));
    System.out.println("Saving object:");
    o.writeObject(b3);
    o.close();
    // Maintenant faites le revenir :
    ObjectInputStream in =      new ObjectInputStream(
        new FileInputStream("Blip3.out"));
    System.out.println("Recovering b3:");
    b3 = (Blip3)in.readObject();
    System.out.println(b3);
  }
} ///:~
t t t
The fields s and i are initialized only in the second constructor, but not in the default constructor. This means that if you don’t initialize s and i in readExternal( ), it will be null (since the storage for the object gets wiped to zero in the first step of object creation). If you comment out the two lines of code following the phrases “You must do this” and run the program, you’ll see that when the object is recovered, s is null and i is zero. t Les champs s et i sont initialisés seulement dans le second constructeur, mais pas dans le constructeur par défaut. Ceci signifie que si vous n'initialisez pas s et i dans readExternal(), il sera alors null (parce que le stockage pour l'objet arrive nettoyé à zéro dans la première étape de la création de l'objet). Si vous enlevez les commentaires sur les deux lignes suivant les phrases « Vous devez faire ceci » et lancez le programme, vous verrez que lorsque l'objet est récupéré, s est null et i est zéro.
t t t
If you are inheriting from an Externalizable object, you’ll typically call the base-class versions of writeExternal( ) and readExternal( ) to provide proper storage and retrieval of the base-class components. t Si vous l'héritage se fait depuis un objet Externalizable, vous appellerez typiquement les versions classe-de-base de writeExternal() et readExternal() pour fournir un stockage et une récupération propre des composants de classe-de-base.
t t t
So to make things work correctly you must not only write the important data from the object during the writeExternal( ) method (there is no default behavior that writes any of the member objects for an Externalizable object), but you must also recover that data in the readExternal( ) method. This can be a bit confusing at first because the default construction behavior for an Externalizable object can make it seem like some kind of storage and retrieval takes place automatically. It does not. t Ainsi pour faire fonctionner correctement les choses vous ne devrez pas seulement écrire les données importantes depuis l'objet pendant la méthode writeExternal() (il n'y a pas de comportement par défaut qui écrit n'importe quels objets pour un objet Externalizable object), mais vous devrez aussi récupérer ces données dans la méthode readExternal(). Ceci peut être un petit peu confus au premier abord parce que le constructeur par défaut du comportement pour un objet Externalizable peut le faire ressembler à une sorte de stockage et de récupération ayant lieu automatiquement. Ce n'est pas le cas.
t t t

The transient keyword

t

Le mot-clé « transient »

t t t
When you’re controlling serialization, there might be a particular subobject that you don’t want Java’s serialization mechanism to automatically save and restore. This is commonly the case if that subobject represents sensitive information that you don’t want to serialize, such as a password. Even if that information is private in the object, once it’s serialized it’s possible for someone to access it by reading a file or intercepting a network transmission. t Quand vous contrôlez la sérialisation, il peut y avoir un sous-objet précis pour qui vous ne voulez pas que le mécanisme de sérialisation java sauve et restaure automatiquement. C'est communément le cas si le sous-objet représente des informations sensibles que vous ne désirez pas sérialiser, comme un mot de passe. Même si cette information est private dans l'objet, une fois qu'elle est sérialisée il est possible pour quelqu'un d'y accéder en lisant un fichier ou en interceptant une transmission réseau.
t t t
One way to prevent sensitive parts of your object from being serialized is to implement your class as Externalizable, as shown previously. Then nothing is automatically serialized and you can explicitly serialize only the necessary parts inside writeExternal( ). t Une manière de prévenir les parties sensibles de votre objet d'être sérialisé est d'implémenter votre classe comme Externalizable, comme montré précédemment. Ainsi rien n'est sérialisé automatiquement et vous pouvez sérialiser explicitement seulement les parties nécessaires dans writeExternal().
t t t
If you’re working with a Serializable object, however, all serialization happens automatically. To control this, you can turn off serialization on a field-by-field basis using the transient keyword, which says “Don’t bother saving or restoring this—I’ll take care of it.” t Si vous travaillez avec un objet Serializable, néanmoins, toutes les sérialisation arrivent de façon automatique. Pour contrôler ceci, vous pouvez fermer la sérialisation sur une base de champ-par-champ en utilisant le mot transient, lequel dit « Ne t'embarrasse pas a sauver ou restaurer ceci — Je me charge de ça. »
t t t
For example, consider a Login object that keeps information about a particular login session. Suppose that, once you verify the login, you want to store the data, but without the password. The easiest way to do this is by implementing Serializable and marking the password field as transient. Here’s what it looks like: t Par exemple, considérons un objet Login qui conserve les informations à propos d'un login de session particulier. Supposez que, dès que vous vérifiez le login, vous désirez stocker les données, mais sans le mot de passe. La manière la plus simple pour réaliser ceci est en d'implémentant Serializable et en marquant le champ password comme transient. Voici ce à quoi cela ressemble :
t t t
//: c11:Logon.java
// Demonstrates the "transient" keyword.
import java.io.*;
import java.util.*;

class Logon implements Serializable {
  private Date date = new Date();
  private String username;
  private transient String password;
  Logon(String name, String pwd) {
    username = name;
    password = pwd;
  }
  public String toString() {
    String pwd =
      (password == null) ? "(n/a)" : password;
    return "logon info: \n   " +
      "username: " + username +
      "\n   date: " + date +
      "\n   password: " + pwd;
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    Logon a = new Logon("Hulk", "myLittlePony");
    System.out.println( "logon a = " + a);
      ObjectOutputStream o =
        new ObjectOutputStream(
          new FileOutputStream("Logon.out"));
    o.writeObject(a);
    o.close();
    // Delay:
    int seconds = 5;
    long t = System.currentTimeMillis()
           + seconds * 1000;
    while(System.currentTimeMillis() < t)
      ;
    // Now get them back:
    ObjectInputStream in =
      new ObjectInputStream(
        new FileInputStream("Logon.out"));
    System.out.println(
      "Recovering object at " + new Date());
    a = (Logon)in.readObject();
    System.out.println( "logon a = " + a);
  }
} ///:~
t
//: c11:Logon.java
// Explique le mot « transient. »
import java.io.*;
import java.util.*;

class Logon implements Serializable {
  private Date date = new Date();
  private String username;
  private transient String password;
  Logon(String name, String pwd) {
    username = name;
    password = pwd;
  }
  public String toString() {
    String pwd =      (password == null) ? "(n/a)" : password;
    return "logon info: \n   " +
      "username: " + username +
      "\n   date: " + date +
      "\n   password: " + pwd;
  }
  public static void main(String[] args)
  throws IOException, ClassNotFoundException {
    Logon a = new Logon("Hulk", "myLittlePony");
    System.out.println( "logon a = " + a);
      ObjectOutputStream o =        new ObjectOutputStream(
          new FileOutputStream("Logon.out"));
    o.writeObject(a);
    o.close();
    // Délai :
    int seconds = 5;
    long t = System.currentTimeMillis()
           + seconds * 1000;
    while(System.currentTimeMillis() < t)
      ;
    // Maintenant faites les revenir :
    ObjectInputStream in =      new ObjectInputStream(
        new FileInputStream("Logon.out"));
    System.out.println(
      "Recovering object at " + new Date());
    a = (Logon)in.readObject();
    System.out.println( "logon a = " + a);
  }
} ///:~
t t t
You can see that the date and username fields are ordinary (not transient), and thus are automatically serialized. However, the password is transient, and so is not stored to disk; also the serialization mechanism makes no attempt to recover it. The output is: t Vous pouvez voir que les champs date et username sont normaux (pas transient), et ils sont ainsi sérialisés automatiquement. Pourtant, password est transient, et donc n'est pas stocké sur le disque; aussi le mécanisme de sérialisation ne fait aucune tentative pour le récupérer. La sortie donne :
t t t
logon a = logon info:
   username: Hulk
   date: Sun Mar 23 18:25:53 PST 1997
   password: myLittlePony
Recovering object at Sun Mar 23 18:25:59 PST 1997
logon a = logon info:
   username: Hulk
   date: Sun Mar 23 18:25:53 PST 1997
password: (n/a)
t
logon a = logon info:
   username: Hulk
   date: Sun Mar 23 18:25:53 PST 1997
   password: myLittlePony
Recovering object at Sun Mar 23 18:25:59 PST 1997
logon a = logon info:
   username: Hulk
   date: Sun Mar 23 18:25:53 PST 1997
   password: (n/a)
t t t
When the object is recovered, the password field is null. Note that toString( ) must check for a null value of password because if you try to assemble a String object using the overloaded ‘+’ operator, and that operator encounters a null reference, you’ll get a NullPointerException. (Newer versions of Java might contain code to avoid this problem.) t Lorsque l'objet est récupéré, le champ de password est null. Notez que toString() est obligé de contrôler la valeur null de password parcequ'il essaye d'assembler un objet String utilisant l'opérateur surchargé ‘ + ’, et que cet opérateur est confronté à une référence de type null, on aurait donc un NullPointerException. (Les nouvelles versions de Java contiendront peut être du code pour résoudre ce problème.)
t t t
You can also see that the date field is stored to and recovered from disk and not generated anew. t Vous pouvez aussi voir que le champ date est stocké sur et récupéré depuis le disque et n'en génère pas une nouvelle.
t t t
Since Externalizable objects do not store any of their fields by default, the transient keyword is for use with Serializable objects only. t Comme les objets Externalizable ne stockent pas tous leurs champs par défaut, le mot-clé transient est a employer avec les objets Serializable seulement.
t t t

An alternative to Externalizable

t

Une alternative à Externalizable

t t t
If you’re not keen on implementing the Externalizable interface, there’s another approach. You can implement the Serializable interface and add (notice I say “add” and not “override” or “implement”) methods called writeObject( ) and readObject( ) that will automatically be called when the object is serialized and deserialized, respectively. That is, if you provide these two methods they will be used instead of the default serialization. t Si vous n'êtes pas enthousiasmé par l'implémentation de l'interface Externalizable, il y a une autre approche. Vous pouvez implémenter l'interface Serializable et ajouter (notez que je dit « ajouter » et non pas « imposer » ou « implémenter ») des méthodes appelées writeObject() et readObject() qui seront automatiquement appelées quand l'objet est sérialisé et désérialisé, respectivement. C'est à dire, si vous fournissez ces deux méthodes elles seront employées à la place de la sérialisation par défaut.
t t t
The methods must have these exact signatures: t Ces méthodes devront avoir ces signatures exactes :
t t t
private void
  writeObject(ObjectOutputStream stream)
    throws IOException;

private void
  readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException
t
private void
  writeObject(ObjectOutputStream stream)
    throws IOException;

private void
  readObject(ObjectInputStream stream)
    throws IOException, ClassNotFoundException
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel