De façon informelle, les types permettent de classifier les données manipulées par les programmes : caractères, entiers, flottants, tableaux, etc. Les données, c'est ce qui occupe la mémoire ; c'est ce qui est modifié, selon le point de vue impératif. Cette classification a au moins un intérêt, qui est de pouvoir interpréter et utiliser correctement ces données, alors qu'elles sont représentées en mémoire, de façon uniforme, par des suites de 0 et de 1. Par exemple, la même suite de 0 et de 1 doit être interprétée différemment selon qu'il s'agit d'un nombre entier ou d'un nombre flottant. De plus, ce ne sont pas les mêmes opérations qui seront exécutées sur des entiers ou sur des flottants : ce sont des « unités fonctionnelles » différentes du microprocesseur qui exécuteront une addition sur des entiers et une addition sur des flottants. Cette notion de type est commune à tous les langages : c'est le typage des données. En Java, ce typage répartit les données en deux grandes catégories : les données primitives et les objets.
Java, comme la plupart des langages, ne dispose pas d'un type primitif représentant des entiers de taille quelconque, mais de quatre types entiers de taille fixe : byte (un octet), short (deux octets), int (quatre octets), long (huit octets), le plus courant étant int. Ce sont tous des types d'entiers signés (c'est-à-dire positifs ou négatifs).
Quand un type entier est codé sur bits,
entiers peuvent être
représentés. Pour des types non-signés, on peut ainsi représenter
l'intervalle
; la suite de bits
représente l'entier
.
Pour des types signés, les entiers dans l'intervalle
sont représentables ; les entiers
sont représentés
de la même façon que dans le cas non-signé et l'on a
; les
entiers
sont représentés en complément à deux et l'on a
; cela signifie que
représente
l'entier
; par exemple 111..1
représente
.
La notation décimale peut être utilisée pour noter les valeurs de type int ; un L (ou un l, moins lisible) doit être suffixé pour représenter une valeur de type long : 12 est un int, et 12L est un long.
Pour manipuler directement l'écriture binaire d'un entier, on utilise les opérateurs suivants :
&
effectue un et sur chacun des bits de ses deux
opérandes ; par exemple, 6&3
= &
2
;
|
effectue un ou sur
chacun des bits de ses deux opérandes ; par exemple, 6|3
=
|
7
;
^
effectue un
ou exclusif sur chacun des bits de ses deux opérandes ; par exemple,
6^3
= ^
5
;
>>n
effectue un décalage à droite de n
crans de tous les bits (ceux le plus à droite tombent, le bit le plus
à gauche est reproduit sur les >>
14>>2
= >>2
= -15>>2
= >>2
= >>>n
effectue un décalage à droite non signé de
n crans de tous les bits (ceux le plus à droite tombent, des
zéros rentrent par la gauche) ; si >>>
-15>>>2
= >>>2
= <<n
effectue un décalage à gauche de n
crans de tous les bits (ceux le plus à gauche tombent, des zéros
rentrent par la droite) ; par exemple, 3<<2
= <<2
=
12
;
~
effectue un
complément de tous les bits (les zéros deviennent des 1 et
réciproquement) ; par exemple, ~5
= ~
-6
; de façon générale, -
~
Ces opérations sont utilisées pour travailler sur les bits de la façon suivante :
i |= (1<<n)
;
i &= ~(1<<n)
;
i ^= (1<<n)
;
if (i&(1<<n)!=0) ...
.
et aussi dans les cas fréquents suivants où elles accélèrent le programme :
>>
<<
Les flottants sont des représentations en mémoire d'une partie des
nombres rationnels ; il est évidemment impossible de représenter des
nombres réels quelconques, pour des raisons de cardinalité. Seuls les
rationnels dont la forme irréductible est , peuvent avoir une
représentation exacte ; les autres ont nécessairement une représentation
approchée (par exemple, le nombre décimal
a
comme représentation en base 2, la
partie soulignée étant répétée indéfiniment). Cette représentation fait
l'objet de la norme IEEE 754, proposée par William Kahan (Turing
Award 1989), publiée en 1985 et adoptée par la plupart des fabricants
d'ordinateurs. Cette norme distingue deux niveaux de précision : simple
(sur 4 octets) et double (sur 8 octets), qui sont
implantés en Java par les types primitifs float et
double. Il est souhaitable que le numéricien programmeur ait
une idée de la représentation des flottants, sans qu'il doive
nécessairement en connaître tous les détails.
Un nombre flottant est caractérisé par trois blocs de bits, qui déterminent respectivement son signe, son exposant et sa mantisse. Chacun de ses blocs est de taille fixe :
simple précision | double précision | |
taille | 32 bits | 64 bits |
signe | 1 bit, ![]() |
1 bit, ![]() |
exposant | 8 bits,
![]() |
11 bits,
![]() |
mantisse | 23 bits,
![]() |
52 bits,
![]() |
La valeur d'un flottant est
, où, dans le cas de la simple précision :
Dans l'exposant, soustraire 127 permettrait de représenter le plus petit
exposant, , par les bits 0000 0000 et le plus grand
exposant,
, par les bits 1111 1111 ;
est par exemple
représenté par 0111 1111. En fait, 0000 0000 et
1111 1111 ont des significations spéciales, pour représenter 0,
, et NaN (c'est-à-dire Not a Number) ; les
exposants extrêmes des flottants normalisés sont donc
(environ
, par 0000 0001) et
(environ
, par
1111 1110).
La valeur de la mantisse étant toujours
, zéro n'est pas
représentable dans ce schéma ; par convention, le bit de signe suivi de
31 bits nuls représentent la valeur
(et non
)2.3.
Si les bits d'exposant valent 1, et les bits de mantisse valent
0, la valeur est
, qui est obtenue dans le cas
d'une division par 0. Enfin, si les bits d'exposant valent 1,
et les bits de mantisse ne sont pas tous nuls, la valeur est NaN,
qui peut être obtenue comme le résultat d'opérations illicites, comme
,
, ou
.
Bien que portant les mêmes noms (addition, multiplication), les
opérations flottantes ne sont pas ces opérations mathématiques et n'ont
pas les mêmes propriétés. Par exemple, l'addition n'est pas associative
: on peut vérifier que
, tandis
que
. Autre exemple : la série
converge !
Les valeurs de type double peuvent être notées avec un signe, un point décimal et un exposant optionnel, par exemple -2.3e+4. Pour le type float, la constante doit être terminée par F (ou f) : 3.141592653 est un double, 6.02e23F est un float.
Les caractères sont représentés par les valeurs du type char,
codé sur deux octets. La plupart des alphabets des langues occidentales
peuvent être représentés dans un jeu de caractères codés sur un octet,
mais un même jeu de caractères ne peut pas coder simultanément tous les
alphabets existants ; dans un souci d'internationalisation, rendu
nécessaire à cause de l'Internet, Java utilise deux octets pour coder
les caractères : c'est le codage Unicode, qui
autorise
caractères.
Les constantes de type caractère sont notées entre deux apostrophes (en
anglais single quote) : 'A', 'Z', 'a',
';', '4', etc. S'y ajoutent des caractères spéciaux
comme '\n'
pour le retour à la ligne et '\t'
pour
une tabulation.
Compte-tenu de ces nouveaux opérateurs, la table définissant les précédences est la suivante ; les opérateurs sont rangés par lignes ; les opérateurs sur la même ligne ont la même précédence et sont associés comme indiqué dans la seconde colonne. Les opérateurs d'une ligne ont une précédence plus élevée que les opérateurs des lignes suivantes.
Opérateurs | Associativité |
() [] . | gauche à droite |
! ~ ++ - +
![]() ![]() |
droite à gauche |
* / % | gauche à droite |
+ - | gauche à droite |
« » »> | gauche à droite |
< <= > >= | gauche à droite |
== != | gauche à droite |
& | gauche à droite |
^ | gauche à droite |
| | gauche à droite |
&& | gauche à droite |
|| | gauche à droite |
? : | droite à gauche |
= += -= /= %= &&= ||= | |
&= ^= |=
«= »=
»>= |
droite à gauche |