 |
 |
11) Le système d’E/S de Java |
|
 |
|
Texte original |
 |
Traducteur :
Armel Fortun |
|
 |
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
From a design standpoint, things get
really weird here. First of all, you might think that because these methods are
not part of a base class or the Serializable interface, they ought to be
defined in their own interface(s). But notice that they are defined as
private, which means they are to be called only by other members of this
class. However, you don’t actually call them from other members of this
class, but instead the writeObject( ) and readObject( )
methods of the ObjectOutputStream and ObjectInputStream objects
call your object’s writeObject( ) and
readObject( ) methods. (Notice my tremendous restraint in not
launching into a long diatribe about using the same method names here. In a
word: confusing.) You might wonder how the ObjectOutputStream and
ObjectInputStream objects have access to private methods of your
class. We can only assume that this is part of the serialization
magic.
|
 |
D'un point de vue conceptuel, les choses sont vraiment mystérieuses ici.
Pour commencer, vous allez penser que parce que ces méthodes ne font pas partie des classes de base
ou de l'interface Serializable, elles devraient être définies dans leur propre
interface(s). Mais notez qu'elles sont définies comme private, ce qui veux dire
qu'elles doivent êtres appelées seulement par les autres membres de cette classe. Cependant, vous
ne faites pas réellement appel à elles depuis les autres membres de cette classe, mais à la place
des méthodes writeObject() et readObject() des objets
ObjectOutputStream et ObjectInputStream appellent vos objets
writeObject() et les méthodes readObject(). (Remarquez mon énorme
retenue de ne pas ma lancer dans une longue diatribe au sujet de l'emploi des même noms de méthodes
ici. En un mot : embrouillant.) Vous pourrez vous demander comment les objets
ObjectOutputStream et ObjectInputStream ont accès aux méthodes
private de votre class. Nous pouvons seulement supposer que cela fait partie de la magie de la
sérialisation.
|
 |
 |
 |
In any event, anything defined in an
interface is automatically public so if writeObject( )
and readObject( ) must be private, then they can’t be
part of an interface. Since you must follow the signatures exactly, the
effect is the same as if you’re implementing an
interface.
|
 |
De toute façon, tout ce qui est défini dans une interface
est automatiquement public donc writeObject() et
readObject() doivent être private, à ce moment là ils feront
partie d'une interface. Puisque vous devez suivre exactement les signatures,
l'effet est le même que si vous implémentiez une interface.
|
 |
 |
 |
It would appear that when you call
ObjectOutputStream.writeObject( ), the Serializable object
that you pass it to is interrogated (using reflection, no doubt) to see if it
implements its own writeObject( ). If so, the normal serialization
process is skipped and the writeObject( ) is called. The same sort
of situation exists for readObject( ).
|
 |
Il apparaîtra que lorsque vous appelez
ObjectOutputStream.writeObject(), l'objet Serializable que vous
lui transmettez est interrogé (utilisant la réflexion, pas de doute) pourvoir si il implémente son
propre writeObject(). Si c'est le cas, le processus normale de sérialisation est
omis et est le writeObject()appelé. Le même type de situation existe pour
readObject().
|
 |
 |
 |
There’s one other twist. Inside
your writeObject( ), you can choose to perform the default
writeObject( ) action by calling defaultWriteObject( ).
Likewise, inside readObject( ) you can call
defaultReadObject( ). Here is a simple example that demonstrates how
you can control the storage and retrieval of a Serializable
object:
|
 |
Il y a une autre entorse. À l'intérieur de votre writeObject(
), vous pouvez choisir d'exécuter l'action writeObject() par défaut en
appelant defaultWriteObject(). Également, dans readObject()vous
pouvez appeler defaultReadObject(). Voici un exemple simple qui démontre comment
vous pouvez contrôler le stockage et la récupération d'un objet Serializable
:
|
 |
 |
 |
//: c11:SerialCtl.java
// Controlling serialization by adding your own
// writeObject() and readObject() methods.
import java.io.*;
public class SerialCtl implements Serializable {
String a;
transient String b;
public SerialCtl(String aa, String bb) {
a = "Not Transient: " + aa;
b = "Transient: " + bb;
}
public String toString() {
return a + "\n" + b;
}
private void
writeObject(ObjectOutputStream stream)
throws IOException {
stream.defaultWriteObject();
stream.writeObject(b);
}
private void
readObject(ObjectInputStream stream)
throws IOException, ClassNotFoundException {
stream.defaultReadObject();
b = (String)stream.readObject();
}
public static void main(String[] args)
throws IOException, ClassNotFoundException {
SerialCtl sc =
new SerialCtl("Test1", "Test2");
System.out.println("Before:\n" + sc);
ByteArrayOutputStream buf =
new ByteArrayOutputStream();
ObjectOutputStream o =
new ObjectOutputStream(buf);
o.writeObject(sc);
// Now get it back:
ObjectInputStream in =
new ObjectInputStream(
new ByteArrayInputStream(
buf.toByteArray()));
SerialCtl sc2 = (SerialCtl)in.readObject();
System.out.println("After:\n" + sc2);
}
} ///:~
|
 |
//: c11:SerialCtl.java // Contrôler la sérialisation en ajoutant vos propres // méthodes writeObject() et readObject(). import java.io.*;
public class SerialCtl implements Serializable { String a; transient String b; public SerialCtl(String aa, String bb) { a = "Not Transient: " + aa; b = "Transient: " + bb; } public String toString() { return a + "\n" + b; } private void writeObject(ObjectOutputStream stream) throws IOException { stream.defaultWriteObject(); stream.writeObject(b); } private void readObject(ObjectInputStream stream) throws IOException, ClassNotFoundException { stream.defaultReadObject(); b = (String)stream.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { SerialCtl sc = new SerialCtl("Test1", "Test2"); System.out.println("Before:\n" + sc); ByteArrayOutputStream buf = new ByteArrayOutputStream(); ObjectOutputStream o = new ObjectOutputStream(buf); o.writeObject(sc); // Maintenant faites les revenir : ObjectInputStream in = new ObjectInputStream( new ByteArrayInputStream( buf.toByteArray())); SerialCtl sc2 = (SerialCtl)in.readObject(); System.out.println("After:\n" + sc2); } } ///:~
|
 |
 |
 |
In this example, one String field
is ordinary and the other is transient, to prove that the
non-transient field is saved by the
defaultWriteObject( )
method and the transient field is saved and restored explicitly. The
fields are initialized inside the constructor rather than at the point of
definition to prove that they are not being initialized by some automatic
mechanism during deserialization.
|
 |
Dans cet exemple, un champ String est normal et le second
est transient, pour prouver que le champ non-transient est sauvé
par la méthode defaultWriteObject() et le que le champ transient
est sauvé et récupéré explicitement. Les champs sont initialisés dans le constructeur plutôt qu'au
point de définition pour prouver qu'ils n'ont pas été initialisés par un certain mécanisme
automatique durant la sérialisation.
|
 |
 |
 |
If you are going to use the default
mechanism to write the non-transient parts of your object, you must call
defaultWriteObject( ) as the first operation in
writeObject( ) and
defaultReadObject( )
as the first operation in readObject( ). These are strange method
calls. It would appear, for example, that you are calling
defaultWriteObject( ) for an ObjectOutputStream and passing
it no arguments, and yet it somehow turns around and knows the reference to your
object and how to write all the non-transient parts.
Spooky.
|
 |
Si vous employez le mécanisme par défaut pour écrire les parties
non-transient de votre objet, vous devrez appeler
defaultWriteObject() comme la première action dans writeObject()
et defaultReadObject() comme la première action dans
readObject(). Ce sont d'étranges appels à des méthodes. Il apparaît, par exemple,
que vous appelez defaultWriteObject() pour un ObjectOutputStream
et ne lui passez aucun argument, mais il tourne d'une manière ou d'une autre autour et connaît la
référence à votre objet et comment écrire toutes les parties non-transient.
Étrange.
|
 |
 |
 |
The storage and retrieval of the
transient objects uses more familiar code. And yet, think about what
happens here. In main( ), a SerialCtl object is created, and
then it’s serialized to an ObjectOutputStream. (Notice in this case
that a buffer is used instead of a file—it’s all the same to the
ObjectOutputStream.) The serialization occurs in the
line:
|
 |
Le stockage et la récupération des objets transient
utilisent un code plus familier. Et cependant, pensez à ce qu'il se passe ici. Dans
main(), un objet SerialCtl est créé, puis est sérialisé en un
ObjectOutputStream. (Notez dans ce cas qu'un tampon est utilisé à la place d'un
fichier — c'est exactement pareil pour tout l' ObjectOutputStream.) La
sérialisation survient à la ligne :
|
 |
 |
 |
o.writeObject(sc);
|
 |
o.writeObject(sc);
|
 |
 |
 |
The writeObject( ) method
must be examining sc to see if it has its own writeObject( )
method. (Not by checking the interface—there isn’t one—or the
class type, but by actually hunting for the method using reflection.) If it
does, it uses that. A similar approach holds true for readObject( ).
Perhaps this was the only practical way that they could solve the problem, but
it’s certainly strange.
|
 |
La méthode writeObject() doit examiner sc
pour voir si il possède sa propre méthode writeObject(). (Non pas en contrôlant
l'interface — il n'y en a pas — ou le type de classe, mais en recherchant en fait la
méthode en utilisant la réflexion.) Si c'est le cas, elle l'utilise. Une approche similaire garde
true pour readObject(). Peut-être que c'est la seule réelle manière dont ils
peuvent résoudre le problème, mais c'est assurément étrange.
|
 |
 |
 |
Versioning
|
 |
Versioning
|
 |
 |
 |
It’s possible that you might want
to change the version of a serializable class (objects of the original class
might be stored in a database, for example). This is supported but you’ll
probably do it only in special cases, and it requires an extra depth of
understanding that we will not attempt to achieve here. The JDK HTML documents
downloadable from java.sun.com cover this topic quite
thoroughly.
|
 |
Il est possible que vous désiriez changer la version d'une classe
sérialisable (les objets de la classe original peuvent être stockés dans un base de donnée, par
exemple). Ceci est supporté mais vous devrez probablement le faire seulement dans les cas spéciaux,
et cela requiert un profondeur supplémentaire de compréhension qui ne sera pas tenté d'atteindre
ici. Les documents HTML du JDK téléchargeables depuis java.sun.com couvrent ce sujet de
manière très approfondie.
|
 |
 |
 |
You will also notice in the JDK HTML
documentation many comments that begin with:
|
 |
Vous pourrez aussi noter dans la documentation HTML du JDK que de nombreux
commentaires commencent par :
|
 |
 |
 |
Warning: Serialized
objects of this class will not be compatible with future Swing releases. The
current serialization support is appropriate for short term storage or RMI
between applications. ...
|
 |
Attention : Les objets sérialisés de cette classe ne
seront pas compatibles avec les futures versions de Swing. Le support actuel de la sérialisation
est approprié pour le stockage à court terme ou le RMI entre les applications. ...
|
 |
 |
 |
This is because the versioning mechanism
is too simple to work reliably in all situations, especially with JavaBeans.
They’re working on a correction for the design, and that’s what the
warning is about.
|
 |
Ceci parce que le mécanisme de versionning est trop simple pour fonctionner
de manière fiable dans toutes les situations, surtout avec les JavaBeans. Ils travaillent sur un
correction de la conception, et c'est le propos de l'avertissement.
|
 |
 |
 |
Using persistence
|
 |
Utiliser la persistence
|
 |
 |
 |
It’s quite appealing to use
serialization technology to store some of the state of
your program so that you can easily restore the program to the current state
later. But before you can do this, some questions must be answered. What happens
if you serialize two objects that both have a reference to a third object? When
you restore those two objects from their serialized state, do you get only one
occurrence of the third object? What if you serialize your two objects to
separate files and deserialize them in different parts of your
code?
|
 |
Il est plutôt attrayant de faire appel à la technologie de la sérialisation
pour stocker certains états de votre programme afin que vous puissiez facilement récupérer le
programme dans l'état actuel plus tard. Mais avant de de pouvoir faire cela, il faut répondre à
certaines questions. Qu'arrive-t-il si vous sérialisez deux objets qui ont tous les deux une
référence à un troisième objet ? Quand vous récupérez ces deux objets depuis leur état sérialisé,
aurez vous une seule occurrence du troisième objet ? Que ce passe-t-il si vous sérialisez vos deux
objets pour séparer les fichiers et les désérialisez dans différentes parties de votre code
?
|
 |
 |
 |
Here’s an example that shows the
problem:
|
 |
Voici un exemple qui montre le problème :
|
 |
 |
 |
//: c11:MyWorld.java
import java.io.*;
import java.util.*;
class House implements Serializable {}
class Animal implements Serializable {
String name;
House preferredHouse;
Animal(String nm, House h) {
name = nm;
preferredHouse = h;
}
public String toString() {
return name + "[" + super.toString() +
"], " + preferredHouse + "\n";
}
}
public class MyWorld {
public static void main(String[] args)
throws IOException, ClassNotFoundException {
House house = new House();
ArrayList animals = new ArrayList();
animals.add(
new Animal("Bosco the dog", house));
animals.add(
new Animal("Ralph the hamster", house));
animals.add(
new Animal("Fronk the cat", house));
System.out.println("animals: " + animals);
ByteArrayOutputStream buf1 =
new ByteArrayOutputStream();
ObjectOutputStream o1 =
new ObjectOutputStream(buf1);
o1.writeObject(animals);
o1.writeObject(animals); // Write a 2nd set
// Write to a different stream:
ByteArrayOutputStream buf2 =
new ByteArrayOutputStream();
ObjectOutputStream o2 =
new ObjectOutputStream(buf2);
o2.writeObject(animals);
// Now get them back:
ObjectInputStream in1 =
new ObjectInputStream(
new ByteArrayInputStream(
buf1.toByteArray()));
ObjectInputStream in2 =
new ObjectInputStream(
new ByteArrayInputStream(
buf2.toByteArray()));
ArrayList animals1 =
(ArrayList)in1.readObject();
ArrayList animals2 =
(ArrayList)in1.readObject();
ArrayList animals3 =
(ArrayList)in2.readObject();
System.out.println("animals1: " + animals1);
System.out.println("animals2: " + animals2);
System.out.println("animals3: " + animals3);
}
} ///:~
|
 |
//: c11:MyWorld.java import java.io.*; import java.util.*;
class House implements Serializable {}
class Animal implements Serializable { String name; House preferredHouse; Animal(String nm, House h) { name = nm; preferredHouse = h; } public String toString() { return name + "[" + super.toString() + "], " + preferredHouse + "\n"; } }
public class MyWorld { public static void main(String[] args) throws IOException, ClassNotFoundException { House house = new House(); ArrayList animals = new ArrayList(); animals.add( new Animal("Bosco the dog", house)); animals.add( new Animal("Ralph the hamster", house)); animals.add( new Animal("Fronk the cat", house)); System.out.println("animals: " + animals);
ByteArrayOutputStream buf1 = new ByteArrayOutputStream(); ObjectOutputStream o1 = new ObjectOutputStream(buf1); o1.writeObject(animals); o1.writeObject(animals); // Écrit un 2éme jeu // Écrit vers un flux différent : ByteArrayOutputStream buf2 = new ByteArrayOutputStream(); ObjectOutputStream o2 = new ObjectOutputStream(buf2); o2.writeObject(animals); // Now get them back: ObjectInputStream in1 = new ObjectInputStream( new ByteArrayInputStream( buf1.toByteArray())); ObjectInputStream in2 = new ObjectInputStream( new ByteArrayInputStream( buf2.toByteArray())); ArrayList animals1 = (ArrayList)in1.readObject(); ArrayList animals2 = (ArrayList)in1.readObject(); ArrayList animals3 = (ArrayList)in2.readObject(); System.out.println("animals1: " + animals1); System.out.println("animals2: " + animals2); System.out.println("animals3: " + animals3); } } ///:~
|
 |
 |
 |
One thing that’s interesting here
is that it’s possible to use object serialization to and from a byte array
as a way of doing a “deep copy” of any object that’s
Serializable. (A deep copy means that you’re duplicating the entire
web of objects, rather than just the basic object and its references.) Copying
is covered in depth in Appendix A.
|
 |
Une chose intéressante ici est qu'il est possible d'utiliser la
sérialisation d'objet depuis et vers un tableau de bytes comme une manière de faire une
« copie en profondeur » de n'importe quel objet qui estSerializable.
(une copie en profondeur veux dire que l'on copie la structure complète des objets, plutôt que
seeulement l'objet de base et ses références.) La copie est abordée en profondeur dans l'Annexe
A.
|
 |
 |
 |
Animal objects contain fields of
type House. In main( ), an ArrayList of these
Animals is created and it is serialized twice to one stream and then
again to a separate stream. When these are deserialized and printed, you see the
following results for one run (the objects will be in different memory locations
each run):
|
 |
Les objets Animal contiennent des champs de type
House. Dans main(), une ArrayList de ces
Animals est crée et est sérialisée deux fois vers un flux et ensuite vers un flux
distinct. Quand ceci est désérialisé et affiché, on obtient les résultats suivant pour une
exécution (les objets seront dans des emplacements mémoire différents à chaque exécution)
:
|
 |
 |
 |
animals: [Bosco the dog[Animal@1cc76c], House@1cc769
, Ralph the hamster[Animal@1cc76d], House@1cc769
, Fronk the cat[Animal@1cc76e], House@1cc769
]
animals1: [Bosco the dog[Animal@1cca0c], House@1cca16
, Ralph the hamster[Animal@1cca17], House@1cca16
, Fronk the cat[Animal@1cca1b], House@1cca16
]
animals2: [Bosco the dog[Animal@1cca0c], House@1cca16
, Ralph the hamster[Animal@1cca17], House@1cca16
, Fronk the cat[Animal@1cca1b], House@1cca16
]
animals3: [Bosco the dog[Animal@1cca52], House@1cca5c
, Ralph the hamster[Animal@1cca5d], House@1cca5c
, Fronk the cat[Animal@1cca61], House@1cca5c
]
|
 |
animals: [Bosco the dog[Animal@1cc76c], House@1cc769 , Ralph the hamster[Animal@1cc76d], House@1cc769 , Fronk the cat[Animal@1cc76e], House@1cc769 ] animals1: [Bosco the dog[Animal@1cca0c], House@1cca16 , Ralph the hamster[Animal@1cca17], House@1cca16 , Fronk the cat[Animal@1cca1b], House@1cca16 ] animals2: [Bosco the dog[Animal@1cca0c], House@1cca16 , Ralph the hamster[Animal@1cca17], House@1cca16 , Fronk the cat[Animal@1cca1b], House@1cca16 ] animals3: [Bosco the dog[Animal@1cca52], House@1cca5c , Ralph the hamster[Animal@1cca5d], House@1cca5c , Fronk the cat[Animal@1cca61], House@1cca5c ]
|
 |
 |
 |
Of course you expect that the
deserialized objects have different addresses from their originals. But notice
that in animals1 and animals2 the same addresses appear, including
the references to the House object that both share. On the other hand,
when animals3 is recovered the system has no way of knowing that the
objects in this other stream are aliases of the objects in the first stream, so
it makes a completely different web of objects.
|
 |
Bien sur vous vous attendez à ce que les objets déserialisés aient des
adresses différentes des originaux. Mais notez que dans animals1 et
animals2 les mêmes adresses apparaissent, incluant les références à l'objet
House que tous les deux partagent. D'un autre coté, quand
animals3 est récupéré le système n'a pas de moyen de savoir que les objets de
l'autre flux sont des alias des objets du premier flux, donc il crée un réseau d'objets
complétement différent.
|
 |
 |
 |
As long as you’re serializing
everything to a single stream, you’ll be able to recover the same web of
objects that you wrote, with no accidental duplication of objects. Of course,
you can change the state of your objects in between the time you write the first
and the last, but that’s your responsibility—the objects will be
written in whatever state they are in (and with whatever connections they have
to other objects) at the time you serialize them.
|
 |
Aussi longtemps que vos sérialisez tout dans un flux unique, vous pourrez
récupérer le même réseau d'objets que vous avez écrits, sans aucune duplication accidentelle
d'objets. Bien sûr, vous pouvez modifier l'état de vos objets entre la période d'écriture du
premier et du dernier, mais c'est de votre responsabilité — les objets seront écrit dans
l'état où ils sont quel qu'il soit (et avec les connexions quelles qu'elles soient qu'ils ont avec
les autres objets) au moment ou vous les sérialiserez.
|
 |
 |
 |
The safest thing to do if you want to
save the state of a system is to serialize as an “atomic” operation.
If you serialize some things, do some other work, and serialize some more, etc.,
then you will not be storing the system safely. Instead, put all the objects
that comprise the state of your system in a single container and simply write
that container out in one operation. Then you can restore it with a single
method call as well.
|
 |
La chose la plus sûre à faire si vous désirez sauver l'état d'un système
est de sérialiser comme une opération « atomique. » Si vous sérialisez quelque chose, faites
une autre action, et en sérialisez une autre en plus, etc., alors vous ne stockerez pas le système
sûrement. Au lieu de cela, mettez tous les objets qui comprennent l'état de votre système dans un
simple conteneur et écrivez simplement ce conteneur à l'extérieur en une seule opération. Ensuite
vous pourrez aussi bien le récupérer avec un simple appel à une méthode.
|
 |
 |
 |
The following example is an imaginary
computer-aided design (CAD) system that demonstrates the approach. In addition,
it throws in the issue of static fields—if you look at the
documentation you’ll see that Class is Serializable, so it
should be easy to store the static fields by simply serializing the
Class object. That seems
like a sensible approach, anyway.
|
 |
L'exemple suivant est un système imaginaire de conception assistée par
ordinateur (CAD) qui démontre cette approche. En plus, il projette dans le sujet des champs
static — si vous regardez la documentation vous verrez que
Class est Serializable, donc il sera facile de stocker les champs
static en sérialisant simplement l'objet Class. Cela semble comme
une approche sensible, en tous cas.
|
 |
 |
 |
//: c11:CADState.java
// Saving and restoring the state of a
// pretend CAD system.
import java.io.*;
import java.util.*;
abstract class Shape implements Serializable {
public static final int
RED = 1, BLUE = 2, GREEN = 3;
private int xPos, yPos, dimension;
private static Random r = new Random();
private static int counter = 0;
abstract public void setColor(int newColor);
abstract public int getColor();
public Shape(int xVal, int yVal, int dim) {
xPos = xVal;
yPos = yVal;
dimension = dim;
}
public String toString() {
return getClass() +
" color[" + getColor() +
"] xPos[" + xPos +
"] yPos[" + yPos +
"] dim[" + dimension + "]\n";
}
public static Shape randomFactory() {
int xVal = r.nextInt() % 100;
int yVal = r.nextInt() % 100;
int dim = r.nextInt() % 100;
switch(counter++ % 3) {
default:
case 0: return new Circle(xVal, yVal, dim);
case 1: return new Square(xVal, yVal, dim);
case 2: return new Line(xVal, yVal, dim);
}
}
}
class Circle extends Shape {
private static int color = RED;
public Circle(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Square extends Shape {
private static int color;
public Square(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
color = RED;
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
class Line extends Shape {
private static int color = RED;
public static void
serializeStaticState(ObjectOutputStream os)
throws IOException {
os.writeInt(color);
}
public static void
deserializeStaticState(ObjectInputStream os)
throws IOException {
color = os.readInt();
}
public Line(int xVal, int yVal, int dim) {
super(xVal, yVal, dim);
}
public void setColor(int newColor) {
color = newColor;
}
public int getColor() {
return color;
}
}
public class CADState {
public static void main(String[] args)
throws Exception {
ArrayList shapeTypes, shapes;
if(args.length == 0) {
shapeTypes = new ArrayList();
shapes = new ArrayList();
// Add references to the class objects:
shapeTypes.add(Circle.class);
shapeTypes.add(Square.class);
shapeTypes.add(Line.class);
// Make some shapes:
for(int i = 0; i < 10; i++)
shapes.add(Shape.randomFactory());
// Set all the static colors to GREEN:
for(int i = 0; i < 10; i++)
((Shape)shapes.get(i))
.setColor(Shape.GREEN);
// Save the state vector:
ObjectOutputStream out =
new ObjectOutputStream(
new FileOutputStream("CADState.out"));
out.writeObject(shapeTypes);
Line.serializeStaticState(out);
out.writeObject(shapes);
} else { // There's a command-line argument
ObjectInputStream in =
new ObjectInputStream(
new FileInputStream(args[0]));
// Read in the same order they were written:
shapeTypes = (ArrayList)in.readObject();
Line.deserializeStaticState(in);
shapes = (ArrayList)in.readObject();
}
// Display the shapes:
System.out.println(shapes);
}
} ///:~
|
 |
//: c11:CADState.java // Sauve et récupère l'état de la // simulation d'un système de CAD. import java.io.*; import java.util.*;
abstract class Shape implements Serializable { public static final int RED = 1, BLUE = 2, GREEN = 3; private int xPos, yPos, dimension; private static Random r = new Random(); private static int counter = 0; abstract public void setColor(int newColor); abstract public int getColor(); public Shape(int xVal, int yVal, int dim) { xPos = xVal; yPos = yVal; dimension = dim; } public String toString() { return getClass() + " color[" + getColor() + "] xPos[" + xPos + "] yPos[" + yPos + "] dim[" + dimension + "]\n"; } public static Shape randomFactory() { int xVal = r.nextInt() % 100; int yVal = r.nextInt() % 100; int dim = r.nextInt() % 100; switch(counter++ % 3) { default: case 0: return new Circle(xVal, yVal, dim); case 1: return new Square(xVal, yVal, dim); case 2: return new Line(xVal, yVal, dim); } } }
class Circle extends Shape { private static int color = RED; public Circle(int xVal, int yVal, int dim) { super(xVal, yVal, dim); } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } }
class Square extends Shape { private static int color; public Square(int xVal, int yVal, int dim) { super(xVal, yVal, dim); color = RED; } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } }
class Line extends Shape { private static int color = RED; public static void serializeStaticState(ObjectOutputStream os) throws IOException { os.writeInt(color); } public static void deserializeStaticState(ObjectInputStream os) throws IOException { color = os.readInt(); } public Line(int xVal, int yVal, int dim) { super(xVal, yVal, dim); } public void setColor(int newColor) { color = newColor; } public int getColor() { return color; } }
public class CADState { public static void main(String[] args) throws Exception { ArrayList shapeTypes, shapes; if(args.length == 0) { shapeTypes = new ArrayList(); shapes = new ArrayList(); // Ajoute des références aux objets de class : shapeTypes.add(Circle.class); shapeTypes.add(Square.class); shapeTypes.add(Line.class); // Fait quelques formes : for(int i = 0; i < 10; i++) shapes.add(Shape.randomFactory()); // Établit toutes les couleurs statiques en GREEN: for(int i = 0; i < 10; i++) ((Shape)shapes.get(i)) .setColor(Shape.GREEN); // Sauve le vecteur d'état : ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("CADState.out")); out.writeObject(shapeTypes); Line.serializeStaticState(out); out.writeObject(shapes); } else { // C'est un argument de ligne de commande ObjectInputStream in = new ObjectInputStream( new FileInputStream(args[0])); // Read in the same order they were written: shapeTypes = (ArrayList)in.readObject(); Line.deserializeStaticState(in); shapes = (ArrayList)in.readObject(); } // Affiche les formes : System.out.println(shapes); } } ///:~
|
 |
 |
 |
The Shape class implements
Serializable, so anything that is inherited from
Shape is automatically Serializable as well. Each Shape
contains data, and each derived Shape class contains a static
field that determines the color of all of those types of Shapes. (Placing
a static field in the base class would result in only one field, since
static fields are not duplicated in derived classes.) Methods in the base
class can be overridden to set the color for the various types (static
methods are not dynamically bound, so these are normal methods). The
randomFactory( ) method creates a different Shape each time
you call it, using random values for the Shape data.
|
 |
La classe Shape implemente
Serializable, donc tout ce qui est hérité de Shape est aussi
automatiquement Serializable. Chaque Shape contient des données, et chaque classe
Shape dérivée contient un champ static qui détermine la couleur
de tous ces types de Shapes. (Placer un champ static dans la classe de base ne
donnera qu'un seul champ, puisque les champs static ne sont pas reproduit dans les classes
dérivés.) Les méthodes dans les classes de base peuvent être surpassées [overridden] pour
établir les couleurs des types variables (les méthodes static ne sont pas
dynamiquement délimitées, donc ce sont des méthodes normales). La méthode
randomFactory() crée un Shape différent chaque fois que vous y
faites appel, utilisant des valeurs aléatoires pour les données du
Shape.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |