Les erreurs de compilation liées aux opérateurs d’affectation sont souvent subtiles à détecter. Pour maîtriser les opérateurs d’affectation en Java, il est essentiel de bien comprendre comment le compilateur gère la promotion numérique et quand le transtypage (casting) est nécessaire.
L’Opérateur d’Affectation : Base de la Programmation Java
Un opérateur d’affectation est un opérateur binaire qui modifie, ou affecte, la variable située à gauche de l’opérateur avec le résultat de la valeur située à droite de l’équation. Contrairement à la plupart des autres opérateurs Java, l’opérateur d’affectation est évalué de droite à gauche.
L’opérateur d’affectation le plus simple est l’affectation =, que vous avez probablement déjà rencontré :
int troupeau = 1;
Cette instruction affecte à la variable troupeau la valeur 1.
Java va automatiquement promouvoir les types de données plus petits vers des types plus grands, comme vous l’avez vu dans la section précédente sur les opérateurs arithmétiques, mais il générera une exception de compilation s’il détecte que vous essayez de convertir d’un type plus grand vers un type plus petit sans transtypage.
Opérateur d’Affectation Simple
Opérateur | Exemple | Description |
---|---|---|
Affectation | int a = 50; | Affecte la valeur de droite à la variable de gauche |
Le Transtypage en Java
Jusqu’ici, ça semble simple, n’est-ce pas ? Eh bien, nous ne pouvons pas vraiment parler de l’opérateur d’affectation en détail avant d’avoir couvert le transtypage. Le transtypage est une opération unaire où un type de données est explicitement interprété comme un autre type. Le transtypage est optionnel et inutile lors de la conversion vers un type de données plus grand, mais il est requis lors de la conversion vers un type plus petit.
Le transtypage s’effectue en plaçant le type de données, entre parenthèses, à gauche de la valeur que vous souhaitez convertir. Voici quelques exemples :
int fourrure = (int)5;
int poils = (short) 2;
String type = (String) "Oiseau";
short queue = (short)(4 + 10);
long plumes = 10(long); // NE COMPILE PAS
Les espaces entre le transtypage et la valeur sont optionnels. Comme montré dans l’avant-dernier exemple, il est courant que la partie droite soit également entre parenthèses. Puisque le transtypage est une opération unaire, il ne serait appliqué qu’au 4 si nous n’encadrions pas 4 + 10 de parenthèses. Le dernier exemple ne compile pas car le type est du mauvais côté de la valeur.
Scénario du Monde Réel : Dépassement et Sous-dépassement
Lorsqu’un nombre est trop grand pour être stocké dans le type de données, un dépassement se produit et le système “revient au début” à la valeur négative la plus basse et compte à partir de là, similaire au fonctionnement de l’arithmétique modulaire. Il existe également un sous-dépassement analogue, lorsque le nombre est trop petit pour tenir dans le type de données.
Par exemple, l’instruction suivante affiche un nombre négatif :
System.out.print(2147483647+1); // -2147483648
Puisque 2147483647 est la valeur maximale pour un int, l’ajout de n’importe quelle valeur strictement positive le fera revenir au plus petit nombre négatif.
Les Opérateurs d’Affectation Composés
En plus de l’opérateur d’affectation simple (=), Java prend en charge de nombreux opérateurs d’affectation composés. Voici les opérateurs que vous devez connaître :
Opérateur | Exemple | Description |
---|---|---|
Affectation avec addition | a += 5 | Ajoute la valeur de droite à la variable de gauche et affecte la somme à la variable |
Affectation avec soustraction | b -= 0.2 | Soustrait la valeur de droite de la variable de gauche et affecte la différence à la variable |
Affectation avec multiplication | c *= 100 | Multiplie la valeur de droite avec la variable de gauche et affecte le produit à la variable |
Affectation avec division | d /= 4 | Divise la variable de gauche par la valeur de droite et affecte le quotient à la variable |
Ces opérateurs composés sont en réalité des versions simplifiées de l’opérateur d’affectation simple, avec une opération arithmétique ou logique intégrée. Par exemple, après la déclaration de chameau et girafe, les deux instructions suivantes sont équivalentes :
int chameau = 2, girafe = 3;
chameau = chameau * girafe; // Opérateur d'affectation simple
chameau *= girafe; // Opérateur d'affectation composé
Comprendre les Subtilités des Opérateurs Composés
Imaginez que vous ayez une tirelire. Au lieu d’écrire “le contenu de la tirelire = le contenu de la tirelire + nouvelle pièce”, vous pouvez simplement écrire “tirelire += nouvelle pièce”. C’est plus simple, non ?
Attention : la partie gauche de l’opérateur composé ne peut être appliquée qu’à une variable déjà définie. Par exemple, si chameau n’était pas déjà défini, l’expression chameau *= girafe ne compilerait pas.
Un Avantage Caché : La Conversion Automatique
Les opérateurs composés ont un atout dans leur manche : ils peuvent vous éviter d’avoir à faire un transtypage explicite. Regardez cet exemple. Pouvez-vous deviner pourquoi la dernière ligne ne compile pas ?
long chevre = 10;
int mouton = 5;
mouton = mouton * chevre; // NE COMPILE PAS
La dernière ligne pose problème car nous essayons d’affecter une valeur long à une variable int. On pourrait corriger avec un transtypage explicite vers (int), mais il existe une meilleure solution avec l’opérateur composé :
long chevre = 10;
int mouton = 5;
mouton *= chevre;
L’opérateur composé va d’abord convertir mouton en long, appliquer la multiplication de deux valeurs long, puis convertir automatiquement le résultat en int.
La Valeur de Retour des Opérateurs d’Affectation
Voici quelque chose d’intéressant : une affectation est elle-même une expression qui renvoie une valeur. Regardez cet exemple surprenant mais parfaitement valide :
long loup = 5;
long coyote = (loup=3);
System.out.println(loup); // Affiche 3
System.out.println(coyote); // Affiche 3
L’expression (loup=3) fait deux choses :
- Elle définit la valeur de la variable loup à 3
- Elle renvoie cette valeur 3, qui est ensuite affectée à coyote
Cette particularité peut être utilisée dans des conditions. Par exemple :
boolean enBonneSante = false;
if(enBonneSante = true)
System.out.print("Super !");
Attention ! Cet exemple n’est pas une vérification si enBonneSante est vrai – il affecte true à enBonneSante. Le résultat de l’affectation étant true, le message “Super !” sera toujours affiché.