Up Next

B.3.1  Valeurs, variables

Par valeur on entend en général le résultat de l’évaluation d’une expression du langage de programmation. Si on prend un point de vue mathématique, une valeur peut être à peu près n’importe quoi, un entier (de ℤ), un ensemble d’entiers etc. Si on prend un point de vue technique, une valeur est ce que l’ordinateur manipule facilement, ce qui entraîne des contraintes : par exemple, un entier n’a pas plus de 32 chiffres binaires (pas plus de 32 bits). Dans les descriptions qui suivent nous entendons valeur plutôt dans ce sens technique. Par variable on entend en général (selon le point de vue technique) une case qui possède un nom où peut être rangée une valeur. Une variable est donc une portion nommée de la mémoire de la machine.

B.3.1.1  Scalaires et objets

Il y a en Java deux grandes catégories de valeurs les scalaires et les objets. La distinction est en fait technique, elle tient à la façon dont ces valeurs sont traitées par la machine, ou plus exactement sont rangées dans la mémoire. Les valeurs scalaires se suffisent à elle-mêmes. Les valeurs des objets sont des références. Une référence « pointe » vers quelque chose (une zone de la mémoire) — référence est un nom civilisé pour pointeur ou adresse en mémoire. Écrivons par exemple

  int x = 1 ;
  int [] t = {1, 2, 3} ;

Les variables x et t sont deux cases, qui contiennent chacune une valeur, la première valeur étant scalaire et la seconde une référence. Un schéma résume la situation.

Le tableau {1, 2, 3} correspond à une zone de mémoire qui contient des trois entiers, mais la valeur qui est rangée dans la variable t est une référence pointant vers cette zone. Le schéma est une simplification de l’état de la mémoire, les zones mémoires apparaissent comme des cases (les variables portent un nom) et les références apparaissent comme des flèches qui pointent vers les cases.

Si x et y sont deux variables, la construction y = x se traduit par une copie de la valeur contenue dans la variable x dans la variable y, que cette valeur soit une référence ou non. Ainsi, le code

  int y = x ;
  int [] u = t ;

produit l’état mémoire simplifié suivant.

Le schéma permet par exemple de comprendre pourquoi (ou plutôt comment) le programme suivant affiche 4.

  int [] t = {1, 2, 3} ;
  int [] u = t ;
  u[1] = 4 ;
  System.out.println(t[1]) ;

Il existe une référence qui ne pointe nulle part null, nous pouvons l’employer partout où une référence est attendue.

  int [] t = null ;

Dans les schémas nous représentons null ainsi :

Puisque null ne pointe nulle part il n’est pas possible de le « déréférencer » c’est à dire d’aller voir où il pointe. Un essai par exemple de t[0] déclenche une erreur à l’exécution.

Égalité des valeurs

L’opérateur d’égalité == de Java s’applique aux valeurs — ainsi que l’opérateur différence !=. Si l’égalité de deux scalaires ne pose aucun problème, il faut comprendre que == entre deux objets traduit l’égalité des références et que deux références sont égales, si et seulement si elles pointent vers la même zone de mémoire. Autrement dit, le programme

  int [] t = {1, 2, 3} ;
  int [] u = t ;
  int [] v = {1, 2, 3} ;
  System.out.println("t==u : " + (t == u) + ", t==v : " + (t == v)) ;

affiche t==u : true, t==v : false. Les références t et u sont égales parce qu’elles pointent vers le même objet. Les références t et v qui pointent vers des objets distincts sont distinctes. Cela peut se comprendre si on revient aux états mémoire simplifiés.

On dit parfois que == est l’égalité physique. L’égalité physique donne parfois des résultats surprenants. Soit le programme Test simple suivant

class Test {
  public static void main (String [] arg) {
    String t = "coucou" ;
    String u = "coucou" ;
    String v = "cou" ;
    String w = v + v ;
    System.out.println("t==u : " + (t == u) + ", t==w : " + (t == w)) ;
  }
}

Une fois compilé et lancé, ce programme affiche t==u : true, t==w : false. Ce qui révèle que les chaînes (objets) référencés par t et u sont exactement les mêmes, tandis que w est une autre chaîne.

La plupart du temps, un programme a besoin de savoir si deux chaînes ont exactement les mêmes caractères et non pas si elles occupent la même zone de mémoire. Il en résulte principalement qu’il ne faut pas tester l’égalité des chaînes (et à vrai dire des objets en général) par ==. Dans le cas des chaînes, il existe une méthode equals spécialisée (voir B.6.1.3) qui compare les chaînes caractère par caractère. La méthode equals est l’égalité structurelle des chaînes.


Up Next