t
t
t
t
t t A) Passage et Retour d'Objets
tttt
A) Passage et retour d'objets
Texte original t Traducteur : Jérome QUELIN
t
t
///
Ce chapitre contient 6 pages
1 2 3 4 5 6
\\\
t t t
t t t
t
t t t
This approach makes sense, then, when: t Cette approche est donc sensée quand :
t t t
  1. You need immutable objects and
  2. You often need to make a lot of modifications or
  3. It’s expensive to create new immutable objects.
t
  1. On a besoin d'objets immuables et
  2. On a souvent besoin de faire beaucoup de modifications sur ces objets ou
  3. Il est prohibitif de créer de nouveaux objets immuables.
t t t

Immutable Strings

t

Chaînes immuables

t t t
Consider the following code: t Examinons le code suivant :
t t t
//: 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
  }
} ///:~
t
//: 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
  }
} ///:~
t t t
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. t 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.
t t t
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? t 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 ?
t t t

Implicit constants

t

Constantes implicites

t t t
If you say: t Si on écrit :
t t t
String s = "asdf";
String x = Stringer.upcase(s);
t
String s = "asdf";
String x = Stringer.upcase(s);
t t t
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. t 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.
t t t
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. t 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.
t t t

Overloading ‘+’ and the StringBuffer

t

Surcharge de l'opérateur « + » et les StringBuffer

t t t
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. t 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.
t t t
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. t 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.
t t t
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]. t 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].
t t t
When used with String objects, the ‘+’ allows you to concatenate Strings together: t Quand il est utilisé avec des objets String, l'opérateur « + » permet de concaténer des String :
t t t
String s = "abc" + foo + "def" + Integer.toString(47);
t
String s = "abc" + foo + "def" + Integer.toString(47);
t t t
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.
t 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.
t t t
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.
t 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.
t t t
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:

t 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 :
t t t
//: 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);
  }
} ///:~
t
//: 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);
  }
} ///:~
t t t
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. t 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.
t t t

The String and StringBuffer classes

t

Les classes String et StringBuffer

t t t
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. t 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.
t t t
First, the String class: t
t t t
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.
t
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.
t t t
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. t 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.
t t t
Here’s the StringBuffer class: t Et voici la classe StringBuffer :
t t t
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.
t
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é.
t t t
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. t 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.
t t t

Strings are special

t

Les Strings sont spéciales

t t t
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. t 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.
t t t

Summary

t

Résumé

t t t
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. t 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.
t t t
The downside to all this underlying magic is twofold: t Les inconvénients de cette magie sous-jacente sont doubles :
t t t
  1. 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).
  2. 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.
t
  1. 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).
  2. 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.
t t t
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. t 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.
t t t
t t t
t t
\\\
///
t t t
t
     
Sommaire Le site de Bruce Eckel