 |
 |
 |
 |
 |
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.
|
|
 |
 |
 |
border="1">
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. |
|