Copie
En java, les références sont complètement opaques, on ne peut pas comme en C les manipuler (en C, opérateurs&
, *
et ->
)
Cela a une importance lorsqu'on duplique des variables :
int a = 42; int b = a;Pour les types primitifs, la JVM stocke deux fois la valeur 42 dans deux endroits différents de la mémoire.
int a = 42; int b = a; a = 43; System.out.println(a); // affiche 43 System.out.println(b); // affiche 42Mais si on fait la même chose avec une classe :
class Point { public int x, y; public Point(int x, int y) { this.x = x; this.y = y; } public String toString(){ return "(" + this.x + "," + this.y + ")"; } // noter au passage la redéfinition d'une méthode de Object } Point a = new Point(1, 1); Point b = a; a.x = 2; System.out.println(a); // affiche (2,1) System.out.println(b); // affiche (2,1)
Comme
a
et b
pointent vers la même chose, toute modification de l'un sera répercutée sur l'autre.
Clone
La classeObject
fournit une méthode clone()
dont toutes les classes héritent, mais elle ne fait que copier les références (shallow copy).
L'API java fournit des méthodes de recopie pour certaines classes.
Par exemple, pour dupliquer 2 tableaux, on dispose de
System.arraycopy()
.
Mais si on a besoin de recopier des objets de nos propres classes, on doit l'implémenter.
Le sujet est traité en détail dans la page java.lang.Object.
Comparaison
Lorsqu'on utilise l'opérateur de comparaison==
pour les types primitifs, java compare leurs valeurs (est évalué à true
s'ils ont exactement les mêmes bits), donc on a le résultat attendu.
Mais si on compare 2 types référence, java compare leurs références, pas leurs valeurs.
String s = "hello"; String letter = "o"; String t = "hell" + letter; System.out.println("avec == \t" + (s == t ? "equal" : "not equal")); System.out.println("avec equals \t" + (s.equals(t) ? "equal" : "not equal"));à l'exécution :
avec == not equal avec equals equalComme on pouvait s'y attendre, le test avec
==
indique que s
et t
ne sont pas égales.
Pour faire le test correctement, on a utilisé la méthode
equals()
.
Cette méthode fait partie de la classe java.lang.Object
, donc toutes les classes en héritent, mais dans le cas général, elle n'est pas plus utile, car l'implémentation par défaut utilise simplement ==
pour faire la comparaison.
Le test a marché uniquement parceque la classe
String
réimplémente equals().
Pour comparer les valeurs des tableaux, il faut par exemple utiliser
java.util.Arrays.equals()
ou java.util.Arrays.deepEquals()
pour les tableaux à plusieurs dimensions.
Passage en paramètre
Le même phénomène se produit lorsqu'on passe une variable en paramètre :void changePrimitive(int x){ x--; } int a = 42; System.out.println(a); // affiche 42 changePrimitive(a); System.out.println(a); // affiche 42Mais avec un type référence :
void changeReference(Point p) { p.x--; } Point a = new Point(1, 1); System.out.println(a); // affiche (1,1) changeReference(a); System.out.println(a); // affiche (0,1)
Autoboxing
Il peut être utile de traduire des types primitifs en objet.Pour ça, java fournit des wrapper classes pour chaque type primitif :
Boolean
, Byte
, Short
, Character
, Integer
, Long
, Float
, et Double
.
Passer du type primitif à sa représentation objet s'appelle le boxing, l'inverse unboxing.
On peut le faire "à la main" :
myInt = new Integer(-1); // deprecated, faire à la place : Integer.valueOf(-1) int i = myInt.intValue();Mais pas très pratique, java le fait automatiquement (autoboxing) :
Integer i = 0; // int literal 0 boxed to an Integer object Number n = 0.0f; // float literal boxed to Float and widened to Number Integer i = 1; // this is a boxing conversion int j = i; // i is unboxed here i++; // i is unboxed, incremented, and then boxed up again Integer k = i+2; // i is unboxed and the sum is boxed up again i = null; j = i;Exemple d'autoboxing très fréquemment utilisé :
int i = 2; // opération à priori impossible dans un langage typé. String s = "i = " + i; // ou alors : System.out.println("i = " + i);L'opérateur de concaténation appelle implicitement
toString()
sur chacun des opérandes. Pour les types primitifs, un autoboxing est effectué.