 |
 |
A) Passage et Retour d'Objets |
|
 |
|
Texte original |
 |
Traducteur : Jérome QUELIN |
|
 |
///
|
Ce chapitre contient 6 pages
1
2
3
4
5
6
|
|
|
 |
 |
 |
 |
 |
 |
|
 |
|
 |
 |
 |
This approach makes sense, then,
when:
|
 |
Cette approche est donc sensée quand :
|
 |
 |
 |
- You need immutable objects
and
- You often need
to make a lot of modifications
or
- It’s
expensive to create new immutable
objects.
|
 |
- On a besoin d'objets immuables et
- On a souvent besoin de faire beaucoup de modifications sur ces objets
ou
- Il est prohibitif de créer de nouveaux objets immuables.
|
 |
 |
 |
Immutable Strings
|
 |
Chaînes immuables
|
 |
 |
 |
Consider the following
code:
|
 |
Examinons le code suivant :
|
 |
 |
 |
//: appendixa:Stringer.java
public class Stringer { static String upcase(String s) { return s.toUpperCase(); } public static void main(String[] args) { String q = new String("howdy"); System.out.println(q); // howdy String qq = upcase(q); System.out.println(qq); // HOWDY System.out.println(q); // howdy } } ///:~
|
 |
//: appendixa:Stringer.java
public class Stringer { static String upcase(String s) { return s.toUpperCase(); } public static void main(String[] args) { String q = new String("howdy"); System.out.println(q); // howdy String qq = upcase(q); System.out.println(qq); // HOWDY System.out.println(q); // howdy } } ///:~
|
 |
 |
 |
When q is passed in to
upcase( ) it’s actually a copy of the reference to q.
The object this reference is connected to stays put in a single physical
location. The references are copied as they are passed around.
|
 |
Quand q est passé à upcase() c'est en
fait une copie de la référence sur q. L'objet auquel cette référence est connectée
reste dans la même localisation physique. Les références sont copiées quand elles sont passées en
argument.
|
 |
 |
 |
Looking at the definition for
upcase( ), you can see that the reference that’s passed in has
the name s, and it exists for only as long as the body of
upcase( ) is being executed. When upcase( ) completes,
the local reference s vanishes. upcase( ) returns the result,
which is the original string with all the characters set to uppercase. Of
course, it actually returns a reference to the result. But it turns out that the
reference that it returns is for a new object, and the original q is left
alone. How does this happen?
|
 |
En regardant la définition de upcase(), on peut voir que
la référence passée en argument porte le nom s, et qu'elle existe seulement
pendant que le corps de upcase() est exécuté. Quand upcase() se
termine, la référence locale s disparaît. upcase() renvoie le
résultat, qui est la chaîne originale avec tous ses caractères en majuscules. Bien sûr, elle
renvoie en fait une référence sur le résultat. Mais la référence qu'elle renvoie porte sur un
nouvel objet, et l'original q est laissé inchangé. Comment cela se
fait-il ?
|
 |
 |
 |
Implicit constants
|
 |
Constantes implicites
|
 |
 |
 |
If you say:
|
 |
Si on écrit :
|
 |
 |
 |
String s = "asdf"; String x = Stringer.upcase(s);
|
 |
String s = "asdf"; String x = Stringer.upcase(s);
|
 |
 |
 |
do you really want the
upcase( ) method to change the argument? In general, you
don’t, because an argument usually looks to the reader of the code as a
piece of information provided to the method, not something to be modified. This
is an important guarantee, since it makes code easier to write and
understand.
|
 |
est-ce qu'on veut réellement que la méthode
upcase()modifie l'argument ? En général, non, car pour le lecteur du
code, un argument est une information fournie à la méthode et non quelque chose qui puisse être
modifié. C'est une garantie importante, car elle rend le code plus facile à lire et à
comprendre.
|
 |
 |
 |
In C++, the availability of this
guarantee was important enough to put in a special keyword,
const, to allow the programmer to ensure that a
reference (pointer or reference in C++) could not be used to modify the original
object. But then the C++ programmer was required to be diligent and remember to
use const everywhere. It can be confusing and easy to
forget.
|
 |
En C++, cette guarantie a été jugée suffisamment importante pour justifier
l'introduction d'un mot-clef spécial, const, pour permettre au programmeur de
s'assurer qu'une référence (pointeur ou référence en C++) ne pouvait être utilisée pour modifier
l'objet original. Mais le programmeur C++ devait alors faire attention et se rappeler d'utiliser
const de partout. Cela peut être déroutant et facile à oublier.
|
 |
 |
 |
Overloading ‘+’ and the StringBuffer
|
 |
Surcharge de l'opérateur « + » et les StringBuffer
|
 |
 |
 |
Objects of the String class are
designed to be immutable, using the technique shown previously. If you examine
the online documentation for the String class (which is summarized
a little later in this appendix), you’ll see that every method in the
class that appears to modify a String really creates and returns a brand
new String object containing the modification. The original String
is left untouched. Thus, there’s no feature in Java like C++’s
const to make the compiler support the immutability of your objects. If
you want it, you have to wire it in yourself, like String
does.
|
 |
Les objets de la classe String sont conçus pour être
immuables, en utilisant les techniques montrées précédemment. Lorsqu'on examine la documentation en
ligne de la classe String (qui est résumée un peu plus loin dans cette annexe), on
se rend compte que chaque méthode de la classe qui semble modifier un objet String
crée et renvoie en fait un nouvel objet String contenant la modification ; la
String originale reste inchangée. Il n'y a donc pas de fonctionnalité en Java
telle que le const du C++ pour s'assurer de l'immuabilité des objets lors de la
compilation. Si on en a besoin, il faut l'implémenter soi-même, comme le fait la classe
String.
|
 |
 |
 |
Since String objects are
immutable, you can alias to a particular String
as many times as you want. Because it’s read-only there’s no
possibility that one reference will change something that will affect the other
references. So a read-only object solves the aliasing problem
nicely.
|
 |
Comme les objets String sont immuables, on
peut aliaser un objet String autant de fois qu'on veut. Puisqu'il est en
lecture seule, une référence ne peut rien modifier qui puisse affecter les autres références. Un
objet en lecture seule résoud donc élégamment le problème de l'aliasing.
|
 |
 |
 |
It
also seems possible to handle all the cases in which you need a modified object
by creating a brand new version of the object with the modifications, as
String does. However, for some operations this isn’t efficient. A
case in point is the operator ‘+’ that has been overloaded
for String objects. Overloading means that it has been given an extra
meaning when used with a particular class. (The ‘+’ and
‘+=’ for String are the only operators that are
overloaded in Java, and Java does not allow the programmer to overload any
others)[83].
|
 |
Il semble également possible de gérer tous les cas dans lesquels on a
besoin de modifier un objet en créant une nouvelle version de l'objet avec les modifications, comme
le fait la classe String. Ce n'est toutefois pas efficace pour certaines
opérations. C'est le cas de l'opérateur « + » qui a été surchargé pour les objets
String. Surchargé veut dire qu'un sens supplémentaire lui a été attribué s'il est
utilisé avec une classe particulière (les opérateurs « + » et « += » pour les
String sont les seuls opérateurs surchargés en Java, et Java ne permet pas au
programmeur d'en surcharger d'autres) [83].
|
 |
 |
 |
When used with String objects, the
‘+’ allows you to concatenate Strings
together:
|
 |
Quand il est utilisé avec des objets String, l'opérateur
« + » permet de concaténer des String :
|
 |
 |
 |
String s = "abc" + foo + "def" + Integer.toString(47);
|
 |
String s = "abc" + foo + "def" + Integer.toString(47);
|
 |
 |
 |
You could imagine how this might work: the String “abc” could have a method append( ) that creates a new String object containing “abc” concatenated with the contents of foo. The new String object would then create another new String that added “def,” and so on.
|
 |
On peut imaginer comment ceci pourrait être implémenté : la
String « abc » pourrait avoir une méthode append() qui
créerait un nouvel objet String contenant la chaîne « abc » concaténée
avec le contenu de foo. Le nouvel objet String devrait alors
créer une nouvelle String à laquelle serait ajoutée la chaîne « def »,
et ainsi de suite.
|
 |
 |
 |
This would certainly work, but it requires the creation of a lot of String objects just to put together this new String, and then you have a bunch of the intermediate String objects that need to be garbage-collected. I suspect that the Java designers tried this approach first (which is a lesson in software design—you don’t really know anything about a system until you try it out in code and get something working). I also suspect they discovered that it delivered unacceptable performance.
|
 |
Cela marcherait bien sûr, mais cela nécessiterait la création d'un grand
nombre d'objets String rien que pour assembler la nouvelle
String, et donc on se retrouverait avec un ensemble d'objets
String intermédiaires qui devraient être réclamés par le ramasse-miettes. Je
suspecte les concepteurs de Java d'avoir tenté cette approche en premier (une leçon de la
conception de logiciel - on ne sait réellement rien d'un système tant qu'on n'a pas essayé de le
coder et qu'on ne dispose pas d'un système fonctionnel). Je suspecte aussi qu'ils ont découvert que
les performances étaient inacceptables.
|
 |
 |
 |
The solution is a mutable companion class similar to the one shown previously. For String, this companion class is called StringBuffer, and the compiler automatically creates a StringBuffer to evaluate certain expressions, in particular when the overloaded operators + and += are used with String objects. This example shows what happens:
|
 |
La solution consiste en une classe compagnon modifiable similaire à celle
exposée précédemment. Pour la classe String, cette classe compagnon est appelée
StringBuffer, et le compilateur crée automatiquement un objet
StringBuffer pour évaluer certaines expressions, en particulier quand les
opérateurs surchargés + et += sont utilisés avec des objets String. L'exemple
suivant montre ce qui se passe :
|
 |
 |
 |
//: appendixa:ImmutableStrings.java // Demonstrating StringBuffer.
public class ImmutableStrings { public static void main(String[] args) { String foo = "foo"; String s = "abc" + foo + "def" + Integer.toString(47); System.out.println(s); // The "equivalent" using StringBuffer: StringBuffer sb = new StringBuffer("abc"); // Creates String! sb.append(foo); sb.append("def"); // Creates String! sb.append(Integer.toString(47)); System.out.println(sb); } } ///:~
|
 |
//: appendixa:ImmutableStrings.java // Démonstration de la classe StringBuffer.
public class ImmutableStrings { public static void main(String[] args) { String foo = "foo"; String s = "abc" + foo + "def" + Integer.toString(47); System.out.println(s); // L'« équivalent » en utilisant la classe StringBuffer : StringBuffer sb = new StringBuffer("abc"); // Crée une String! sb.append(foo); sb.append("def"); // Crée une String! sb.append(Integer.toString(47)); System.out.println(sb); } } ///:~
|
 |
 |
 |
In the creation of String s, the
compiler is doing the rough equivalent of the subsequent code that uses
sb: a StringBuffer is created and append( ) is used to
add new characters directly into the StringBuffer object (rather than
making new copies each time). While this is more efficient, it’s worth
noting that each time you create a quoted character string such as
“abc” and “def”, the compiler turns those
into String objects. So there can be more objects created than you
expect, despite the efficiency afforded through
StringBuffer.
|
 |
Durant la création de la String s, le compilateur fait à
peu près l'équivalent du code suivant qui utilise sb : une
StringBuffer est créée et append() est appelée pour ajouter les
nouveaux caractères directement dans l'objet StringBuffer (plutôt que de créer de
nouvelles copies à chaque fois). Bien que ceci soit beaucoup plus efficace, il est bon de noter que
chaque fois qu'on crée une chaîne de caractères quotée telle que « abc » ou
« def », le compilateur les transforme en objets
String. Il peut donc y avoir plus d'objets créés que ce qu'on pourrait croire, en
dépit de l'efficacité permise par la classe StringBuffer.
|
 |
 |
 |
The String and StringBuffer classes
|
 |
Les classes String et StringBuffer
|
 |
 |
 |
Here is an overview of the methods
available for both String and StringBuffer
so you can get a feel for the way they interact. These tables don’t
contain every single method, but rather the ones that are important to this
discussion. Methods that are overloaded are summarized in a single
row.
|
 |
Voici un aperçu des méthodes disponibles pour les deux
classes String et StringBuffer afin de se faire une idée de
la manière dont elles interagissent. Ces tables ne référencent pas toutes les méthodes disponibles,
mais seulement celles qui sont importantes pour notre sujet. Les méthodes surchargées sont résumées
sur une ligne.
|
 |
 |
 |
First, the String
class:
|
 |
|
 |
 |
 |
Method
|
Arguments,
Overloading
|
Use
|
Constructor
|
Overloaded: Default, String,
StringBuffer, char arrays, byte arrays.
|
Creating String
objects.
|
length( )
|
|
Number of characters in the
String.
|
charAt()
|
int Index
|
The char at a location in the
String.
|
getChars( ),
getBytes( )
|
The beginning and end from which to copy,
the array to copy into, an index into the destination array.
|
Copy chars or bytes into an
external array.
|
toCharArray( )
|
|
Produces a char[] containing the
characters in the String.
|
equals( ),
equals-IgnoreCase( )
|
A String to compare
with.
|
An equality check on the contents of the
two Strings.
|
compareTo( )
|
A String to compare
with.
|
Result is negative, zero, or positive
depending on the lexicographical ordering of the String and the argument.
Uppercase and lowercase are not equal!
|
regionMatches( )
|
Offset into this String, the other
String and its offset and length to compare. Overload adds “ignore
case.”
|
boolean result indicates whether
the region matches.
|
startsWith( )
|
String that it might start with.
Overload adds offset into argument.
|
boolean result indicates whether
the String starts with the argument.
|
endsWith( )
|
String that might be a suffix of
this String.
|
boolean result indicates whether
the argument is a suffix.
|
indexOf( ),
lastIndexOf( )
|
Overloaded: char, char and
starting index, String, String, and starting
index.
|
Returns -1 if the argument is not found
within this String, otherwise returns the index where the argument
starts. lastIndexOf( ) searches backward from end.
|
substring( )
|
Overloaded: Starting index, starting
index, and ending index.
|
Returns a new String object
containing the specified character set.
|
concat( )
|
The String to
concatenate
|
Returns a new String object
containing the original String’s characters followed by the
characters in the argument.
|
replace( )
|
The old character to search for, the new
character to replace it with.
|
Returns a new String object with
the replacements made. Uses the old String if no match is
found.
|
toLowerCase( )
toUpperCase( )
|
|
Returns a new String object with
the case of all letters changed. Uses the old String if no changes need
to be made.
|
trim( )
|
|
Returns a new String object with
the white space removed from each end. Uses the old String if no changes
need to be made.
|
valueOf( )
|
Overloaded: Object, char[],
char[] and offset and count, boolean, char, int,
long, float, double.
|
Returns a String containing a
character representation of the argument.
|
intern( )
|
|
Produces one and only one String
ref per unique character sequence.
|
|
 |
Méthode |
Arguments,
Surcharges |
Utilisation |
Constructeur |
Surchargés : Défaut, String,
StringBuffer, tableau de char, tableau de
byte. |
Création d'objets String. |
length() |
|
Nombre de caractères dans la String. |
charAt() |
int Index |
Le n-ième caractère dans la String. |
getChars(), getBytes() |
Le début et la fin de la zone à copier, le tableau dans lequel effectuer
la copie, un index dans le tableau destination. |
Copie des chars ou des bytes dans un
tableau externe. |
toCharArray() |
|
Produit un char[] contenant les caractères de la
String. |
equals(), equals-IgnoreCase() |
Une String avec laquelle comparer. |
Un test d'égalité sur le contenu de deux
String. |
compareTo() |
Une String avec laquelle comparer. |
Le résultat est négatif, zéro ou positif suivant la comparaison
lexicographique de la String et l'argument. Majuscules et minuscules sont
différenciées ! |
regionMatches() |
Déplacement dans la String, une autre
String ainsi que son déplacement et la longueur à comparer. Surchargé :
ajoute l'insensibilisation à la casse. |
Résultat boolean indiquant si les régions
correspondent. |
startsWith() |
La String avec laquelle la String
pourrait débuter. Surchargé : ajoute un déplacement pour l'argument. |
Résultat boolean indiquant si la String
débute avec l'argument. |
endsWith() |
La String qui pourrait être un suffixe de cette
String. |
Résultat boolean indiquant si l'argument est un suffixe
de la String. |
indexOf(), lastIndexOf() |
Surchargés : char, char et index de
départ, String, String, et index de départ. |
Renvoie -1 si l'argument n'est pas trouvé dans la String,
sinon renvoie l'index où l'argument commence. lastIndexOf() recherche en partant
de la fin. |
substring() |
Surchargé : index de départ, index de départ et index de
fin. |
Renvoie un nouvel objet String contenant l'ensemble des
caractères spécifiés. |
concat() |
La String à concaténer. |
Renvoie un nouvel objet String contenant les caractères
de l'objet String intial suivis des caractères de l'argument. |
replace() |
L'ancien caractère à rechercher, le nouveau caractère avec lequel le
remplacer. |
Renvoie un nouvel objet String avec les remplacements
effectués. Utilise l'ancienne String si aucune corrrespondance n'est
trouvée. |
toLowerCase(), toUpperCase() |
|
Renvoie un nouvel objet String avec la casse de tous les
caractères modifiée. Utilise l'ancienne String si aucun changement n'a été
effectué. |
trim() |
|
Renvoie un nouvel objet String avec les espaces enlevés à
chaque extrémité. Utilise l'ancienne String si aucun changement n'a été
effectué. |
valueOf() |
Surchargés : Object, char[],
char[] et déplacement et compte, boolean, char,
int, long, float,
double. |
Renvoie une String contenant une représentation sous
forme de chaîne de l'argument. |
intern() |
|
Produit une et une seule référence String pour chaque
séquence unique de caractères. |
|
 |
 |
 |
You can see that every String
method carefully returns a new String object when it’s necessary to
change the contents. Also notice that if the contents don’t need changing
the method will just return a reference to the original String. This
saves storage and overhead.
|
 |
On peut voir que chaque méthode de la classe String
renvoie un nouvel objet String quand il est nécessaire d'en modifier le contenu.
Remarquez aussi que si le contenu n'a pas besoin d'être modifié la méthode renverra juste une
référence sur la String originale. Cela permet d'économiser sur le stockage et le
surcoût d'une création.
|
 |
 |
 |
Here’s the
StringBuffer class:
|
 |
Et voici la classe StringBuffer :
|
 |
 |
 |
Method |
Arguments, overloading |
Use |
Constructor
|
Overloaded: default, length of buffer to
create, String to create from.
|
Create a new StringBuffer
object.
|
toString( )
|
|
Creates a String from this
StringBuffer.
|
length( )
|
|
Number of characters in the
StringBuffer.
|
capacity( )
|
|
Returns current number of spaces
allocated.
|
ensure- Capacity( )
|
Integer indicating desired
capacity.
|
Makes the StringBuffer hold at
least the desired number of spaces.
|
setLength( )
|
Integer indicating new length of
character string in buffer.
|
Truncates or expands the previous
character string. If expanding, pads with nulls.
|
charAt( )
|
Integer indicating the location of the
desired element.
|
Returns the char at that location
in the buffer.
|
setCharAt( )
|
Integer indicating the location of the
desired element and the new char value for the element.
|
Modifies the value at that
location.
|
getChars( )
|
The beginning and end from which to copy,
the array to copy into, an index into the destination array.
|
Copy chars into an external array.
There is no getBytes( ) as in String.
|
append( )
|
Overloaded: Object, String,
char[], char[] with offset and length, boolean,
char, int, long, float,
double.
|
The argument is converted to a string and
appended to the end of the current buffer, increasing the buffer if
necessary.
|
insert( )
|
Overloaded, each with a first argument of
the offset at which to start inserting: Object, String,
char[], boolean, char, int, long,
float, double.
|
The second argument is converted to a
string and inserted into the current buffer beginning at the offset. The buffer
is increased if necessary.
|
reverse( )
|
|
The order of the characters in the buffer
is reversed.
|
|
 |
Méthode |
Arguments,
Surcharges |
Utilisation |
Constructeur |
Surchargés : défaut, longueur du buffer à créer,
String à partir de laquelle créer. |
Crée un nouvel objet StringBuffer. |
toString() |
|
Crée un objet String à partir de l'objet
StringBuffer. |
length() |
|
Nombre de caractères dans l'objet
StringBuffer. |
capacity() |
|
Renvoie l'espace actuellement alloué. |
ensure-Capacity() |
Entier indiquant la capacité désirée. |
Fait que l'objet StringBuffer alloue au minimum un
certain espace. |
setLength() |
Entier indiquant la nouvelle longueur de la chaîne de caractères dans le
buffer. |
Tronque ou accroît la chaîne de caractères. Si accroissement, complète
avec des caractères nulls. |
charAt() |
Entier indiquant la localisation de l'élement désiré. |
Renvoie le char à l'endroit spécifié dans le
buffer. |
setCharAt() |
Entier indiquant la localisation de l'élément désiré et la nouvelle valeur
char de cet élément. |
Modifie la valeur à un endroit précis. |
getChars() |
Le début et la fin à partir de laquelle copier, le tableau dans lequel
copier, un index dans le tableau de destination. |
Copie des chars dans un tableau extérieur. Il n'existe
pas de getBytes() comme dans la classe String. |
append() |
Surchargés : Object, String,
char[], char[] avec déplacement et longueur,
boolean, char, int, long,
float, double. |
L'argument est converti en chaîne de caractères et concaténé à la fin du
buffer courant, en augmentant la taille du buffer si nécessaire. |
insert() |
Surchargés, chacun avec un premier argument contenant le déplacement
auquel on débute l'insertion : Object, String,
char[], boolean, char, int,
long, float, double. |
Le deuxième argument est converti en chaîne de caractères et inséré dans
le buffer courant au déplacement spécifié. La taille du buffer est augmentée si
nécessaire. |
reverse() |
|
L'ordre des caractères du buffer est inversé. |
|
 |
 |
 |
The most commonly used method is
append( ), which is used by the compiler when evaluating
String expressions that contain the ‘+’ and
‘+=’ operators. The insert( ) method has a
similar form, and both methods perform significant manipulations to the buffer
instead of creating new objects.
|
 |
La méthode la plus fréquemment utilisée est append(), qui
est utilisée par le compilateur quand il évalue des expressions String contenant
les opérateurs « + » et « += ». La méthode insert() a une
forme similaire, et les deux méthodes réalisent des modifications significatives sur le buffer au
lieu de créer de nouveaux objets.
|
 |
 |
 |
Strings are special
|
 |
Les Strings sont spéciales
|
 |
 |
 |
By now you’ve seen that the
String class is not just another class in Java. There are a lot of
special cases in String, not the least of which is that it’s a
built-in class and fundamental to Java. Then there’s the fact that a
quoted character string is converted to a String by the compiler and the
special overloaded operators + and +=. In this appendix
you’ve seen the remaining special case: the carefully built immutability
using the companion StringBuffer and some extra magic in the
compiler.
|
 |
La classe String n'est donc pas une simple classe dans
Java. La classe String est spéciale à bien des égards, en particulier parce que
c'est une classe intégrée et fondamentale dans Java. Il y a aussi le fait qu'une chaîne de
caractères entre quotes est convertie en String par le compilateur et les
opérateurs + et +=. Dans cette annexe vous avez pu voir d'autres spécificités : l'immuabilité
précautionneusement assurée par la classe compagnon StringBuffer et d'autres
particularités magiques du compilateur.
|
 |
 |
 |
Summary
|
 |
Résumé
|
 |
 |
 |
Because everything is a reference in
Java, and because every object is created on the heap and garbage-collected only
when it is no longer used, the flavor of object manipulation changes, especially
when passing and returning objects. For example, in C or C++, if you wanted to
initialize some piece of storage in a method, you’d probably request that
the user pass the address of that piece of storage into the method. Otherwise
you’d have to worry about who was responsible for destroying that storage.
Thus, the interface and understanding of such methods is more complicated. But
in Java, you never have to worry about responsibility or whether an object will
still exist when it is needed, since that is always taken care of for you. Your
can create an object at the point that it is needed, and no sooner, and never
worry about the mechanics of passing around responsibility for that object: you
simply pass the reference. Sometimes the simplification that this provides is
unnoticed, other times it is staggering.
|
 |
Puisque dans Java tout est référence, et puisque chaque objet est créé dans
le segment et réclamée par le ramasse-miettes seulement quand il n'est plus utilisé, la façon de
manipuler les objets change, spécialement lors du passage et du retour d'objets. Par exemple, en C
ou en C++, si on veut initialiser un endroit de stockage dans une méthode, il faut demander à
l'utilisateur de passer l'adresse de cet endroit de stockage à la méthode, ou alors il faut se
mettre d'accord sur qui a la responsabilité de détruire cet espace de stockage. L'interface et la
compréhension de telles méthodes sont donc bien plus compliquées. Mais en Java, on n'a pas à se
soucier de savoir si un objet existera toujours lorsqu'on en aura besoin, puisque tout est déjà
géré pour nous. On peut ne créer un objet que quand on en a besoin, et pas avant, sans se soucier
de déléguer les responsabilités sur cet objet : on passe simplement une référence. Quelquefois
la simplification que cela engendre passe inaperçue, d'autres fois elle est flagrante.
|
 |
 |
 |
The downside to all this underlying magic
is twofold:
|
 |
Les inconvénients de cette magie sous-jacente sont
doubles :
|
 |
 |
 |
- You always take the
efficiency hit for the extra memory management (although this can be quite
small), and there’s always a slight amount of uncertainty about the time
something can take to run (since the garbage collector can be forced into action
whenever you get low on memory). For most applications, the benefits outweigh
the drawbacks, and particularly time-critical sections can be written using
native methods (see Appendix B).
- Aliasing: sometimes
you can accidentally end up with two references to the same object, which is a
problem only if both references are assumed to point to a distinct
object. This is where you need to pay a little closer attention and, when
necessary, clone( ) an object to prevent the other reference from
being surprised by an unexpected change. Alternatively, you can support aliasing
for efficiency by creating immutable objects whose operations can return a new
object of the same type or some different type, but never change the original
object so that anyone aliased to that object sees no
change.
|
 |
- Il y a toujours une pénalité d'efficacité engendrée pour cette gestion
supplémentaire de la mémoire (bien qu'elle puisse être relativement faible), et il y a toujours une
petite incertitude sur le temps d'exécution (puisque le ramasse-miettes peut être obligé d'entrer
en action si la quantité de mémoire disponible n'est pas suffisante). Pour la plupart des
applications, les bénéfices compensent largement les inconvénients, et les parties de l'application
critiques quant au temps peuvent être écrites en utilisant des méthodes native
(voir l'annexe B).
- Aliasing : on peut se retrouver accidentellement avec deux références
sur le même objet, ce qui est un problème si les deux références sont supposées pointer sur deux
objets distincts. Cela demande de faire un peu plus attention, et, si nécessaire,
clone() l'objet pour empêcher toute modification intempestive de l'objet par
l'autre référence. Cependant on peut supporter l'aliasing pour l'efficacité qu'il procure en
évitant cet inconvénient en créant des objets immuables dont les opérations renvoient un nouvel
objet du même type ou d'un type différent, mais ne changent pas l'objet original afin que toute
référence liée à cet objet ne voie pas de changements.
|
 |
 |
 |
Some people say that
cloning in Java is a botched design, and to heck with it, so they implement
their own version of
cloning[84] and
never call the Object.clone( ) method, thus eliminating the need to
implement Cloneable and catch the CloneNotSupportedException. This
is certainly a reasonable approach and since clone( ) is supported
so rarely within the standard Java library, it is apparently a safe one as well.
But as long as you don’t call Object.clone( ) you don’t
need to implement Cloneable or catch the exception, so that would seem
acceptable as
well.
|
 |
Certaines personnes insinuent que la conception du clonage a été baclée en
Java, et pour ne pas s'embêter avec, implémentent leur propre version du clonage href="#fn84" name="fnB84">[84], sans jamais appeler la méthode
Object.clone(), éliminant ainsi le besoin d'implémenter Cloneable
et d'intercepter l'exception CloneNotSupportedException. Ceci est certainement une
approche raisonnable et comme clone() est très peu implémentée dans la
bibliothèque standard Java, elle est aussi relativement sûre. Mais tant qu'on n'appelle pas
Object.clone() on n'a pas besoin d'implémenter Cloneable ou
d'intercepter l'exception, donc cela semble acceptable aussi.
|
 |
 |
 |
 |
 |
 |
 |
 |
|
 |
 |
 |