4. Types de données Java et cast
Table des matières
- 4.1 Types primitifs
- 4.2 Types référence
- 4.3 Tableau des types primitifs
- 4.4 Notes
- 4.5 Récapitulatif
- 4.6 Arithmétique et promotion numérique primitive
- 4.6.1 Règles de promotion numérique en Java
- 4.6.1.1 Règle 1 – Types numériques mixtes → le plus petit type est promu vers le plus grand
- 4.6.1.2 Règle 2 – Entier + flottant → l’entier est promu vers le flottant
- 4.6.1.3 Règle 3 – byte, short et char sont promus en int lors des opérations arithmétiques
- 4.6.1.4 Règle 4 – Le type du résultat correspond au type promu des opérandes
- 4.6.2 Récapitulatif du comportement de promotion numérique
- 4.6.1 Règles de promotion numérique en Java
- 4.7 Cast en Java
- 4.8 Résumé
Comme nous l’avons vu dans les Blocs Syntaxiques, Java propose deux catégories de types de données :
- Types primitifs
- Types référence
👉 Pour une vue complète des types primitifs avec leur taille, plage de valeurs, valeurs par défaut et exemples, voir le Tableau des types primitifs.
4.1 Types primitifs
Les primitives représentent des valeurs brutes uniques stockées directement en mémoire.
Chaque type primitif possède une taille fixe qui détermine le nombre d’octets qu’il occupe.
Conceptuellement, un primitif est simplement une cellule mémoire contenant une valeur :
+-------+
| 42 | ← valeur de type short (2 octets en mémoire)
+-------+
4.2 Types référence
Un type référence ne contient pas l’objet lui-même, mais une référence (pointeur) vers celui-ci.
La référence a une taille fixe (dépendante de la JVM, souvent 4 ou 8 octets) qui pointe vers un emplacement mémoire où l’objet réel est stocké.
- Exemple : une variable de type
Stringpointe vers un objet chaîne dans le tas (heap), qui est lui-même composé en interne d’un tableau de primitiveschar.
Diagramme :
Référence (4 ou 8 octets)
+---------+
| address | ───────────────► Objet dans le tas (Heap)
+---------+ +-------------------+
| "Hello" |
| ['H','e','l','l','o'] ← tableau de char
+-------------------+
4.3 Tableau des types primitifs
| Mot-clé | Type | Taille | Valeur min | Valeur max | Valeur par défaut | Exemple |
|---|---|---|---|---|---|---|
byte |
int 8 bits | 1 octet | –128 | 127 | 0 | byte b = 100; |
short |
int 16 bits | 2 octets | –32 768 | 32 767 | 0 | short s = 2000; |
int |
int 32 bits | 4 octets | –2 147 483 648 (–2^31) | 2 147 483 647 (2^31–1) | 0 | int i = 123456; |
long |
int 64 bits | 8 octets | –2^63 | 2^63–1 | 0L | long l = 123456789L; |
float |
flottant 32 bits | 4 octets | voir note | voir note | 0.0f | float f = 3.14f; |
double |
flottant 64 bits | 8 octets | voir note | voir note | 0.0 | double d = 2.718; |
char |
UTF-16 | 2 octets | '\u0000' (0) |
'\uffff' (65 535) |
'\u0000' |
char c = 'A'; |
boolean |
true/false | dépend de la JVM (souvent 1 octet) | false | true | false | boolean b = true; |
4.4 Notes
float et double n’ont pas de bornes entières fixes comme les types entiers.
Ils suivent la norme IEEE 754 :
- Plus petites valeurs positives non nulles :
Float.MIN_VALUE ≈ 1.4E–45-
Double.MIN_VALUE ≈ 4.9E–324 -
Plus grandes valeurs finies :
Float.MAX_VALUE ≈ 3.4028235E+38Double.MAX_VALUE ≈ 1.7976931348623157E+308
Ils supportent également des valeurs spéciales : +Infinity, -Infinity, et NaN (Not a Number).
- FP = floating point (virgule flottante).
- La taille de
booleandépend de la JVM mais le type se comporte logiquement commetrue/false. - Les valeurs par défaut s’appliquent aux champs (variables de classe).
Les variables locales doivent être explicitement initialisées avant utilisation.
4.5 Récapitulatif
- Primitif = valeur réelle, stockée directement en mémoire.
- Référence = pointeur vers un objet ; l’objet lui-même peut contenir des primitives et d’autres références.
- Pour les détails des primitives, voir le Tableau des types primitifs.
4.6 Arithmétique et promotion numérique primitive
Lorsqu’on applique des opérateurs arithmétiques ou de comparaison à des types primitifs, Java convertit (ou promeut) automatiquement les valeurs vers des types compatibles selon des règles de promotion numérique bien définies.
Ces règles garantissent des calculs cohérents et évitent la perte de données lors du mélange de types numériques différents.
4.6.1 🔹 Règles de promotion numérique en Java
4.6.1.1 Règle 1 – Types numériques mixtes → le plus petit type est promu vers le plus grand
Si deux opérandes appartiennent à des types numériques différents, Java promeut automatiquement le type le plus petit vers le type le plus grand avant d’effectuer l’opération.
| Exemple | Explication |
|---|---|
int x = 10; double y = 5.5; double result = x + y; |
La valeur int x est promue en double, donc le résultat est un double (15.5). |
Ordre de promotion valide (du plus petit au plus grand) :
byte → short → int → long → float → double
4.6.1.2 Règle 2 – Entier + flottant → l’entier est promu vers le flottant
Si un opérande est de type entier (byte, short, char, int, long) et l’autre de type flottant (float, double),
la valeur entière est promue vers le type flottant avant l’opération.
| Exemple | Explication |
|---|---|
float f = 2.5F; int n = 3; float result = f * n; |
n (int) est promu en float. Le résultat est un float (7.5). |
double d = 10.0; long l = 3; double result = d / l; |
l (long) est promu en double. Le résultat est un double (3.333...). |
4.6.1.3 Règle 3 – byte, short et char sont promus en int lors des opérations arithmétiques
Lorsqu’on effectue une opération arithmétique sur des variables (et non des constantes littérales) de type byte, short ou char,
Java les promeut automatiquement en int, même si les deux opérandes sont plus petits que int.
| Exemple | Explication |
|---|---|
byte a = 10, b = 20; byte c = a + b; |
❌ Erreur de compilation : le résultat de a + b est un int, pas un byte. Il faut caster → byte c = (byte)(a + b); |
short s1 = 1000, s2 = 2000; short sum = (short)(s1 + s2); |
Les opérandes sont promus en int, un cast explicite est nécessaire pour affecter à short. |
char c1 = 'A', c2 = 2; int result = c1 + c2; |
'A' (65) et 2 sont promus en int, résultat = 67. |
Note
Cette règle s’applique uniquement lorsqu’on utilise des variables. Lorsque l’on utilise des littéraux constants, le compilateur peut parfois évaluer l’expression à la compilation et l’affecter sans problème.
byte a = 10 + 20; // ✅ OK : expression constante qui tient dans un byte
byte b = 10;
byte c = 20;
byte d = b + c; // ❌ Erreur : b + c est évalué à l’exécution → int
4.6.1.4 Règle 4 – Le type du résultat correspond au type promu des opérandes
Une fois les promotions appliquées, et lorsque les deux opérandes sont du même type,
le résultat de l’expression a ce même type promu.
| Exemple | Explication |
|---|---|
int i = 5; double d = 6.0; var result = i * d; |
i est promu en double, le résultat est un double. |
float f = 3.5F; long l = 4L; var result = f + l; |
l est promu en float, le résultat est un float. |
int x = 10, y = 4; var div = x / y; |
Les deux sont int, le résultat est un int (2), la partie fractionnaire est tronquée. |
Warning
La division entière produit toujours un résultat entier. Pour obtenir un résultat décimal, au moins un opérande doit être flottant :
double result = 10.0 / 4; // ✅ 2.5
int result2 = 10 / 4; // ❌ 2 (fraction ignorée)
4.6.2 ✅ Récapitulatif du comportement de promotion numérique
| Situation | Résultat de promotion | Exemple |
|---|---|---|
| Mélange de petits et grands types numériques | Le plus petit est promu vers le plus grand | int + double → double |
| Entier + flottant | L’entier est promu vers le flottant | long + float → float |
| Arithmétique sur byte, short, char | Promu en int | byte + byte → int |
| Résultat après promotion | Le type du résultat correspond au type promu | float + long → float |
4.6.2.1 🧠 Points clés
- Toujours tenir compte de la promotion de type lorsqu’on mélange des types dans une expression arithmétique.
- Pour les petits types (
byte,short,char), la promotion enintest automatique dès qu’il y a une opération avec des variables. - Utilisez le cast explicite seulement lorsque vous êtes sûr que le résultat tient dans le type cible.
- Rappelez-vous : la division entière tronque, la division en flottant conserve les décimales.
- Comprendre ces règles est essentiel pour éviter les pertes de précision inattendues ou les erreurs de compilation à l’examen de certification Java.
4.7 Cast en Java
En Java, le cast est le processus par lequel on convertit explicitement une valeur d’un type vers un autre.
Cela s’applique à la fois aux types primitifs (nombres) et aux types référence (objets dans une hiérarchie de classes).
4.7.1 Cast primitif
Le cast primitif modifie le type d’une valeur numérique.
Il existe deux catégories de cast :
| Type | Description | Exemple | Explicite ? | Risque |
|---|---|---|---|---|
| Widening | plus petit type → plus grand type | int → double | Non | Aucune perte |
| Narrowing | plus grand type → plus petit type | double → int | Oui | Perte possible |
4.7.1.1 Cast large implicite
Conversion automatique d’un type “plus petit” vers un type compatible “plus grand”.
Gérée par le compilateur, ne nécessite pas de syntaxe explicite.
int i = 100;
double d = i; // cast implicite : int → double
System.out.println(d); // 100.0
✅ Sûr – pas de dépassement (même s’il faut garder en tête la précision des flottants).
4.7.1.2 Cast étroit explicite
Conversion manuelle d’un type « plus grand » vers un type « plus petit ».
Nécessite une cast expression car cela peut provoquer une perte de données.
double d = 9.78;
int i = (int) d; // explicit cast: double → int
System.out.println(i); // 9 (fraction discarded)
Warning
⚠ Utiliser uniquement lorsque vous êtes certain que la valeur tient dans le type cible.
4.7.1.3 Cast étroit Implicite à la Compilation
Dans certains cas spécifiques, le compilateur autorise une conversion de narrowing sans cast explicite.
Si une variable est déclarée final et initialisée avec une constant expression dont la valeur tient dans le type cible, le compilateur peut effectuer la conversion en toute sécurité au moment de la compilation.
final int k = 10;
byte b = k; // allowed: value 10 fits into byte range
final int x = 200;
byte c = x; // does NOT compile: 200 is outside byte range
Cela fonctionne parce que le compilateur connaît la valeur exacte d’une variable final et peut vérifier qu’elle se situe dans l’intervalle du type plus petit.
Ce type de narrowing est autorisé entre :
- byte
- short
- char
- int
Cependant, cela ne s’applique pas à :
- long
- float
- double
Par exemple :
final float f = 10.0f;
int n = f; // does not compile
Même si la valeur semble compatible, les types à virgule flottante ne sont pas éligibles pour cette forme de narrowing implicite.
4.7.2 Perte de données, dépassement et sous-dépassement
Lorsqu’une valeur dépasse la capacité d’un type, on peut obtenir :
- Dépassement (overflow) : résultat supérieur à la valeur maximale représentable
- Sous-dépassement (underflow) : résultat inférieur à la valeur minimale représentable
-
Troncature : les données qui ne tiennent pas sont perdues (par exemple, les décimales)
-
Exemple – overflow/underflow avec int
int max = Integer.MAX_VALUE;
int overflow = max + 1; // retour (“wrap-around”) vers une valeur négative
int min = Integer.MIN_VALUE;
int underflow = min - 1; // retour (“wrap-around”) vers une valeur positive
- Exemple – troncature
double d = 9.99;
int i = (int) d; // 9 (fraction supprimée)
Note
Les types flottants (float, double) ne font pas de wrap-around :
- overflow → Infinity / -Infinity
- underflow (valeurs très petites) → 0.0 ou valeurs dénormalisées.
4.7.3 Cast de valeurs versus variables
Java traite :
- Les littéraux entiers comme des
intpar défaut - Les littéraux flottants comme des
doublepar défaut
Le compilateur n’exige pas de cast lorsqu’un littéral tient dans la plage du type cible :
byte first = 10; // OK : 10 tient dans un byte
short second = 9 * 10; // OK : expression constante évaluée à la compilation
Mais :
long a = 5729685479; // ❌ erreur : littéral int hors plage
long b = 5729685479L; // ✅ littéral long (suffixe L)
float c = 3.14; // ❌ double → float : nécessite F ou cast
float d = 3.14F; // ✅ littéral float
int e = 0x7FFF_FFFF; // ✅ max int en hexadécimal
int f = 0x8000_0000; // ❌ hors plage int (nécessite L)
Cependant, lorsque les règles de promotion numérique s’appliquent :
Avec des variables de type
byte,shortetchardans une expression arithmétique, les opérandes sont promus enintet le résultat est unint.
byte first = 10;
short second = 9 + first; // ❌ 9 (littéral int) + first (byte → int) = int
// second = (short) (9 + first); // ✅ cast de l’expression entière
short b = 10;
short a = 5 + b; // ❌ 5 (int) + b (short → int) = int
short a2 = (short) (5 + b); // ✅ cast de l’expression entière
Warning
Le cast est un opérateur unaire :
short a = (short) 5 + b;
Le cast s’applique uniquement à 5 → le résultat de l’expression reste un int → l’affectation échoue toujours.
4.7.4 Cast de référence d’objets
Le cast s’applique aussi aux références d’objets dans une hiérarchie de classes.
Il ne change pas l’objet en mémoire — seulement le type de référence utilisé pour y accéder.
Règles importantes :
- Le type réel de l’objet détermine quels champs/méthodes existent réellement.
- Le type de la référence détermine ce que vous pouvez appeler/accéder à cet endroit du code.
4.7.4.1 Upcasting (cast large de référence)
Conversion d’une sous-classe vers une super-classe.
Implicite et toujours sûre : chaque Dog est aussi un Animal.
class Animal { }
class Dog extends Animal { }
Dog dog = new Dog();
Animal a = dog; // upcast implicite : Dog → Animal
4.7.4.2 Downcasting (cast étroit de référence)
Conversion d’une super-classe vers une sous-classe.
- Explicite
- Peut échouer à l’exécution avec
ClassCastExceptionsi l’objet n’est pas réellement de ce type
Animal a = new Dog();
Dog d = (Dog) a; // OK : a référence réellement un Dog
Animal x = new Animal();
Dog d2 = (Dog) x; // ⚠ Erreur à l’exécution : ClassCastException
Pour plus de sécurité, utilisez instanceof :
if (x instanceof Dog) {
Dog safeDog = (Dog) x; // cast sûr
}
4.7.5 Résumé des points clés
| Type de cast | S’applique à | Direction | Syntaxe | Sûr ? | Effettué par |
|---|---|---|---|---|---|
| Widening Primitive | Primitifs | petit → grand | Implice | Oui | Compilateur |
| Narrowing Primitive | Primitifs | grand → petit | Explicite | Non | Programmeur |
| Upcasting | Objets | sous-classe → super-classe | Implice | Oui | Compilateur |
| Downcasting | Objets | super-classe → sous-classe | Explicite | Vérification à l’exécution | Programmeur |
4.7.6 Exemples
// Cast primitif
short s = 50;
int i = s; // widening
byte b = (byte) i; // narrowing (perte possible)
// Cast d’objet
Object obj = "Hello";
String str = (String) obj; // OK : obj référence une String
Object n = Integer.valueOf(10);
// String fail = (String) n; // ClassCastException à l’exécution
4.8 Résumé
- Le cast primitif change le type numérique.
- Le cast de référence change la “vue” d’un objet dans la hiérarchie.
- Upcasting → sûr et implicite.
- Downcasting → explicite, à utiliser avec prudence (souvent après
instanceof).