Accès rapide :
La vidéo
Déclaration de variables
Les types numériques entiers
Les quatre types entiers en Java
Passage d'un type à un autre
Les différentes bases numériques
Groupage de chiffres
Constantes de type long
Operateurs arithmétiques sur entiers
Les opérateurs arithmétiques
Dépassement d'étendues
Cas de la division entière
Opérateurs de comparaisons
Cette vidéo vous montre comment déclarer des variables et comment utiliser les différents types entiers en Java (byte, short, int et long). Les syntaxes relatives aux différentes bases numériques sont étudiées ainsi qu'une première série d'opérateurs relatifs à la manipulation d'entiers.
Un programme informatique manipule souvent un très grand nombre d'informations. Imaginons, par exemple, un site de vente en ligne : celui-ci va donc devoir gérer les articles en vente sur ce site. Ce site de vente en ligne devrait aussi gérer les commandes de chaque utilisateur. Les articles, les commandes, les utilisateurs manipulés par ce programme sont appelés des données. Ces données sont stockées dans différents emplacements en mémoire.
La mémoire de votre ordinateur contient un très grand nombre de cases mémoire : on appelle chaque case mémoire un octet. D'où le fait qu'on quantifie la taille de la mémoire en Ko (kilooctet, soit 210 octets), en Mo (megaoctet, soit 210 Ko), en Go (gigaoctet, soit 210 Mo) ou encore to (teraoctect, soit 210 Go). Une donnée sera donc stockée dans la mémoire à partir d'un octet particulier et pourra occuper plusieurs octets consécutifs. On appelle une « adresse mémoire » le numéro de la case mémoire (sa position dans la mémoire) à partir de laquelle est stocké une donnée (une information). Il s'agit d'une valeur entière qui, vous le comprenez, peut être très grande.
Si vous utilisiez, avec un langage de programmation de très bas niveau, comme l'assembleur par exemple, vous devriez mémoriser les emplacements mémoire (les adresses mémoire) de chacune de vos données. Vous comprendrez alors aisément que l'exercice risque d'être véritablement compliqué.
C'est pour répondre à cette difficulté que les langages évolués proposent la notion de variable. Une variable est associée à une adresse mémoire, mais ce n'est plus vous qui gérerez cet aspect, ce sera le compilateur Java. Une variable possède un nom, ce qui sera beaucoup plus facile à mémoriser et à utiliser. A condition, bien sûr, que vous ayez donné un nom pertinent à votre variable.
Du plus, en Java, une variable sera associée à un type de données (une catégorie de données). Cela sous-entend que votre variable occupera un nombre
d'octets bien précis en mémoire. Par exemple, un entier de type int
occupe 4 octets en mémoire.
Pour déclarer une variable, il faut d'abord préciser son type, puis son nom et terminer cette déclaration par un caractère ;
.
On peut aussi directement initialiser cette variable pour lui donner une valeur initiale : dans ce cas, affecter la valeur initiale à la variable en
utilisant le caractère =
juste avant le ;
. Voici quelques exemples de déclaration de variables.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Demo { public static void main( String [] args ) { int counter = 10; // Déclare une variable entière nommée counter et initialisée à 10 String name = "Jean"; // Déclare une variable de type chaîne de caractères appelée name double pi; // Déclare une variable flottante appelée pi et non initialisée pi = 3.1415; // On change la valeur de pi System.out.println( counter ); System.out.println( name ); System.out.println( pi ); } } |
System.out.println( variable );
permet d'afficher sur la console le contenu d'une variable.
Voici le résultat produit par ce programme.
10 Jean 3.1415
Il est aussi possible de déclarer plusieurs variables sur une même ligne de déclaration. Dans ce cas, elles auront toutes le même type de données.
Voici un petit exemple déclarant deux variables entières nommées x
et y
.
1 |
int x=10, y=15;
|
Il existe de très nombreux types de données en Java. Il est même possible de définir vos propres types de données avec, entre autre, la notion de classes. Nous commencerons, dans ce chapitre, à parler des types numériques entiers.
Il existe quatre types entiers en Java, à l'instar des langages C et C++ dont Java s'inspire. C'est quatre types entiers sont : byte
,
short
, int
et long
. La différence entre ces quatre types de données réside dans le nombre d'octets utilisé par
la variable comme le montre le tableau ci-dessous.
byte | short | int | long | |
---|---|---|---|---|
Taille (bits) | 8 | 16 | 32 | 64 |
Etendue des valeurs | -128 .. 127 | -32768 .. 32767 | -231 .. 231-1 | -263 .. 263-1 |
char
mais bien byte
.
La raison en est simple : le contrôle de typage du compilateur Java est plus strict qu'en C et du coup il y a une distinction entre le type
entier sur un octet (byte
) et le type caractère (char
). Sémantiquement c'est plus propre.
signed
et unsigned
, réservés en C, n'existent pas en Java. Tout type entier est obligatoirement signé, ce
qui veut dire qu'on pourra manipuler des valeurs négatives, nulles ou positives pour chacun de ces quatre types. A mon sens, ce point-là est
dommage : j'aurais apprécié de pouvoir plus fortement typer mes variables en interdisant, dans certains situations, les valeurs négatives, mais bon ...
Bien entendu, si vous cherchez à stocker une valeur trop grande, en rapport au type utilisé, dans une variable, une erreur de compilation sera produite. C'est ce que montre l'exemple ci-dessous.
1 2 3 4 5 6 7 8 9 10 |
public class Demo { public static void main( String [] args ) { byte c = 1024; // Valeur maximale autorisée : 127 short s = 100000; // Valeur maximale autorisée : 32767 } } |
Voici le résultat de la compilation de ce programme.
$> javac Demo.java Demo.java:4: error: incompatible types: possible lossy conversion from int to byte byte c = 1024; ^ Demo.java:5: error: incompatible types: possible lossy conversion from int to short short s = 100000; ^ 2 errors $>
Imaginons que vous cherchiez à transférer la valeur d'une variable entière dans une autre variable entière. Dans ce cas, il y a deux possibilités :
soit la taille de la variable dans laquelle on affecte est plus grande (ou égale) à la taille de la variable initiale, et dans ce cas, le changement de type est implicitement autorisé.
soit la taille de la variable dans laquelle on affecte est plus petite à la taille de la variable initiale, et dans ce cas il peut y avoir une perte de précisions lors de l'affectation. Du coup le changement de type devra être explicitement acté via un opérateur de transtypage (on utilise aussi souvent la terminologie anglo-saxonne en parlant d'opérateur de cast).
Un opérateur de transtypage s'introduit en mettant le type de destination entre parenthèses, comme le montre l'exemple suivant.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 |
public class Demo { public static void main( String [] args ) { byte c = 10; short s = c; // Autorisé, car taille byte < taille short System.out.println( s ); // Affiche 10 long l = 10; // Ici, on demande explicitement de réduire la taille de la donnée int i = (int) l; // de 8 octets vers 4 octets, via l'opérateur de transtypage (int) System.out.println( i ); // Affiche 10 i = 200000; s = (short) i; // Attention, il va y avoir une perte d'information ! System.out.println( s ); // Affiche 3392, car un short ne peut pas dépasser 32767 } } |
Java permet d'utiliser plusieurs bases numériques pour exprimer vos valeurs entières. Il y en a trois qui sont reprises du langage C : base octale, base décimale et base hexadécimale. Depuis Java SE 7.0, une quatrième base, la base binaire, a été rajoutée au langage.
La base binaire : elle ne supporte que deux chiffres, le 0 et le 1. Pour exprimer une valeur en base binaire, il est nécessaire de préfixer
votre valeur par 0b
.
La base octale : comme son nom l'indique, cette base numérique contient 8 chiffres (de 0 à 7). Les chiffres 8 et 9 sont donc non
autorisés : si vous les utilisez, une erreur de compilation sera produite.
Pour exprimer une valeur en base octale, il est nécessaire de préfixer votre valeur par 0
.
La base décimale : bien entendu dix chiffres de 0 à 9. Que dire de plus ....
La base hexadécimale : 16 chiffres de 0 à 9 puis de A à F. Cette base numérique est très intéressante dans certains cas : communication avec un matériel électronique, codification de couleurs ARGB, ...
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 |
public class Demo { public static void main( String [] args ) { int binaryValue = 0b10; // == 2 int octalValue = 010; // == 8 int decimalValue = 10; int hexadecimalValue = 0x10; // == 16 System.out.println( binaryValue ); System.out.println( octalValue ); System.out.println( decimalValue ); System.out.println( hexadecimalValue ); hexadecimalValue = 0xff; // On change la valeur : 255 en décimal System.out.println( hexadecimalValue ); } } |
Depuis Java SE 7.0, il est possible d'utiliser le caractère _
pour grouper les digits (les chiffres) d'une valeur numérique.
Vous pouvez grouper vos chiffres par blocs de taille quelconque. Vous n'êtes même pas obligé de définir de groupes de tailles identiques :
cela peut, par exemple, s'avérer très pratique avec l'utilisation du binaire dans le cadre de la communication avec un matériel électronique.
Il est possible d'utiliser le groupage de chiffres, quelle que soit la base numérique utilisées. Voici quelques exemples d'utilisations.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
public class Demo { public static void main( String [] args ) { int counter = 1_000_000_000; // Imaginez-vous compter les 0 en l'abscence du groupage. System.out.println( counter ); int color = 0xff_ff_00_ff; // Un beau fuchsia exprimé en codage ARGB pour Android. System.out.println( color ); int binaryValue = 0b00000000_11111111_01010101_10101010; // Bits groupés par octet. System.out.println( binaryValue ); } } |
int
est signé
(le bit 32 étant fixé à 1, la valeur est affichée négativement).
1000000000 -65281 16733610
Pour réaliser un groupage à l'affichage, il est nécessaire d'utiliser un formateur, comme le montre l'exemple suivant. La ligne commençant par
import
correspond à une importation de la librairie java.text.NumberFormat
.
1 2 3 4 5 6 7 8 9 10 11 12 |
import java.text.NumberFormat; public class Demo { public static void main( String [] args ) { int counter = 1_000_000_000; NumberFormat formatter = NumberFormat.getIntegerInstance(); System.out.println( formatter.format( counter ) ); } } |
Analysons le programme qui suit : qu'en pensez-vous ?
1 2 3 4 5 6 7 8 9 |
public class Demo { public static void main( String [] args ) { long counter = 10_000_000_000; System.out.println( counter ); } } |
En fait, ce programme ne compile pas. La raison est un peu subtile. La ligne long counter = 10_000_000_000;
s'exécute en deux temps.
Dans un premier temps, le compilateur vérifie la valeur entière 10_000_000_000
. Or pour le compilateur, par défaut, une valeur entière
est typée int
: du coup 10 milliard est une valeur en dehors des bornes autorisées (-2^31 à 2^31-1).
Le message affiché par le compilateur est le suivant.
$> javac Demo.java Demo.java:5: error: integer number too large: 10000000000 long counter = 10_000_000_000; ^ 1 error $>
Pour régler ce problème, il suffit de saisir dans le code Java une valeur entière typée long
.
Cela se réalise en ajoutant un caractère L
à la fin de la valeur. Ce caractère L
(L pour long) peut être saisi en
minuscule ou bien en majuscule. Notez néanmoins que le l
(en minuscule) peut être confondu avec un 1
.
Je vous conseille donc d'utiliser une majuscule. Voici un code qui compile parfaitement.
1 2 3 4 5 6 7 8 9 |
public class Demo { public static void main( String [] args ) { long counter = 10_000_000_000L; System.out.println( counter ); } } |
Dans un second temps, cette valeur typée long
est stockée dans la variable counter
elle-même type long
,
donc tout va bien. Notez bien que le fait de typer la variable n'impose pas ce type à la définition de la valeur. Ca peut paraitre surprenant,
mais c'est comme ça.
_
) entre le dernier chiffre de la valeur numérique et le caractère L
.
Un underscore doit forcément être placé entre deux chiffres. Le caractère L
n'est pas considéré comme un caractère de chiffre.
Bien entendu, vous pouvez utiliser vos variables pour faire des calculs. Pour ce faire, vous disposez d'opérateurs arithmétiques : +
,
-
, *
, /
et %
pour, respectivement, l'addition, la soustraction, la multiplication, la division
et le calcul du reste de la division entière. Voici un petit exemple.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 |
public class Demo { public static void main( String [] args ) { int firstValue = 11; int secondValue = 3; int div = firstValue / secondValue; int rest = firstValue % secondValue; int computedValue = div * secondValue + rest; System.out.println( "11 / 3 == " + div ); // Affiche 3 System.out.println( "11 % 3 == " + rest ); // Affiche 2 System.out.println( "computedValue == " + computedValue ); // Affiche 11 } } |
Des règles de priorités existent entre les opérateurs. Bien entendu la multiplication (ou la division) est prioritaire par rapport à l'addition (ou la soustraction). Dans l'exemple précédent, il n'est donc pas nécessaire de forcer sur la priorité de la multiplication en utilisant des parenthèses : c'est implicite. En cas de priorités identiques, les opérateurs proposés sont évalués de la gauche vers la droite.
Si vous avez le moindre doute sur la priorité d'évaluation de vos opérateurs, utilisez les parenthèses pour forcer les priorités. Voici un exemple, mais j'insiste bien sur le fait qu'ici ce n'est pas nécessaire.
1 |
int computedValue = ( div * secondValue ) + rest;
|
byte
produit un entier typé int
.
La raison est qu'on peut très facilement dépasser de l'étendue du type byte
étant donné le peu de place occupé.
Il est donc nécessaire de transtyper le résultat en byte
si c'est ce que vous souhaitez récupérer.
Il en va de même pour les autres opérateurs arithmétiques (soustraction, ...).
Dans le même ordre d'idée, l'addition de deux short
produit aussi un résultat typé int
.
L'exemple ci-dessous vous montre comment réaliser les transtypages (conversions vers le type souhaité).
1 2 3 4 5 6 7 8 9 10 11 12 13 |
public class Demo { public static void main( String [] args ) { byte b1 = 10; byte b2 = 20; byte res = (byte) ( b1 + b2 ); // Transtypage en byte System.out.println( res ); } } |
int i = Integer.parseInt("10");
.
Le langage Java défini, comme en C, deux sortes d'opérateurs de division : vous avez la possibilité de faire des divisions entières ou des divisions flottantes. Dans l'exemple ci-dessous, il n'y a aucun doute à avoir, on divise deux entiers et on demande à récupérer un entier : la division sera donc entière.
1 |
int res = 1 / 3; // res vaut 0, car division entière |
Par contre, cet exemple est plus sournois. A votre avis, quel est le résultat affiché, en sachant que le type double
représente
un flottant en double précision ?
1 2 3 4 5 6 7 8 9 10 |
public class Demo { public static void main( String [] args ) { double res = 1 / 3; System.out.println( res ); } } |
Même si pour la majorité des débutants Java que j'ai pu sonder sur cette question répondent 0.3333333
, et bien ce n'est pas la bonne réponse.
Le résultat affiché sera 0.0
. Mais pourquoi ? En faire, le compilateur va d'abord évaluer la partie droite : il y voit deux entiers
divisés entre eux : cela suffit à trancher et à choisir une division de type entière. Le résultat vaudra donc l'entier 0
.
Ensuite le compilateur s'aperçoit qu'il doit stocker cette valeur dans une variable typée double
et donc il affecte 0.0,
le transtypage étant ici implicite.
Vous pouvez aussi comparer vos entiers. Pour ce faire, six opérateurs vous sont proposés : l'égalité (opérateur ==
), la différence
(opérateur !=
), l'infériorité (opérateur <=
), l'infériorité stricte (opérateur <
),
la supériorité (opérateur >=
), la supériorité stricte (opérateur >
). Voici un exemple d'utilisation.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 |
public class Demo { public static void main( String [] args ) { int numerator1 = 1; int denominator1 = 3; int numerator2 = 2; int denominator2 = 1; int leftPart = numerator1 * denominator2; int rightPart = denominator1 * numerator2; if ( leftPart == rightPart ) { System.out.println( "Les fractions sont équivalentes" ); } else if ( leftPart < rightPart ) { System.out.println( "La première fraction est plus petite" ); } else { System.out.println( "La première fraction est plus grande" ); } } } |
if
permet de réaliser un test. Dans l'exemple ci-dessous trois cas peuvent être considérés. Bien entendu, étant donné les
valeurs des fractions, l'affichage produit sera « La première fraction est plus petite
».
Améliorations / Corrections
Vous avez des améliorations (ou des corrections) à proposer pour ce document : je vous remerçie par avance de m'en faire part, cela m'aide à améliorer le site.
Emplacement :
Description des améliorations :