Programmation par les Objets en Java
Débuter en Java (TD1)
Najib Tounsi
(Lien permanent: http://www.mescours.ma/Java/TD/tdJava1.html
(.pdf
))
L'objectif de ce TD est d'écrire quelques programmes simples pour se familiariser avec le langage Java. Classes, fonctions, surcharge, passage des paramètres, Wrappers.
Note: Le travail de compilation / exécution se fera en mode commande, e.g. Terminal de Linux / MacOS, ou cmd de Windows. Ce mode est plus simple et préférable au début. Cela permet de porter l'attention plus sur le langage que sur l'environnement de développement.
L'élève est censé.e savoir comment créer un répertoire (commandes md
ou mkdir
, cd
, etc.) et son équivalent
graphique (créer / ouvrir un nouveau dossier etc.), lister son
contenu (commande dir
ou ls
), savoir utiliser
un éditeur de texte pour créer un programme et sauvegarder un programme
source sous un répertoire donné. On doit aussi connaître les commandes de
base Unix (Linux
ou MacOS) et Windows
(cat
, type
, more
etc.)
Sous MacOS ou Linux,
Java est généralement déjà fourni. (le vérifier en tapant javac
-version
. On devrait voir javac 1.8.0_121
ou une
version supérieure). Sous Windows,
voir l'annexe: Préparation
du TP sur PC
NB. Créer un nouveau fichier d'extension .java
pour chaque
programme. Utiliser un éditeur de texte courant. Aide à la présentation
syntaxique. Par exemple, Sublime (https://www.sublimetext.com/3).
Ecrire le programme suivant dans un fichier HelloWorld.java
:
class HelloWorld {
static public void main(String args[]){
System.out.println("Hello, World");
}
};
javac HelloWorld.java
java HelloWorld
HelloWorld.class
résultat de la compilation. Commandes ls
ou dir.class
vient du nom de la classe (première ligne).Remarque : Le fichier source .java
ici a le même nom que la
classe contenant la fonction main(),
i.e. l'identificateur qui suit le mot class
dans le
code source. Le nom du fichier .class
généré pour cette
classe est cet identificateur justement.
Exercice: rajouter d'autres lignes pour imprimer "bonjour" en d'autres langues (e.g. "Bonjour, ça va?", "سلام").
Petite remarque ici si vous êtes sous Windows en mode ligne commande :
UTF-8
(menu Enregistrer+Encodage).
En plus cet éditeur rajoute le caractère invisible ByteOrderMark
(BOM \uFEFF
) en début de fichier. Ce que le compilateur
Java n'accepte pas. Utiliser un autre éditeur pour retirer ce
caractère. Copier / coller le source vers un autre éditeur (e.g.
Sublime Text.)????????
pour le
mot en Arabe. chcp
65001
pour changer le code page vers Unicode
UTF-8 et recommencer.◻︎◻︎◻︎◻︎,
changer de police
d'affichage (menu Propriété+Police)..txt
qu'on visualisera à
part ( "java votreClasse > resultat.txt
).Hello2.java
. On va imprimer: Bonjour Untel
.
où le nom Untel est donné au
lancement du programme sur la ligne commande java
.class Hello2 {
static public void main(String args[]){
if (args.length !=0)
System.out.println("Hello " + args[0]);
}
}
Exécuter avec : java Hello2 Fatima
A noter: Le mot Fatima constitue le premier élément args[0]
du tableau args[]
, paramètre de la fonction main.
Le champ length
donne la taille d'un tableau en Java.
scanner
)scanner
.import java.util.*; // Package Java qui contient la classe scanner
class Saisie {
/**
* Lecture d'un entier, version scanner
*/
static public void main(String args[]) {
Scanner clavier = new Scanner(System.in);
System.out.print("Donner entier: ");
int n = clavier.nextInt();
System.out.println (n*2);
}
}
La classe scanner
se trouve dans le package java.util
. Elle permet de déclarer un objet, variable clavier
ici,
sur lequel on peut lire des données. On l'a instancié ici par :
new Scanner(System.in);
à partir du fichier standard d'entrée représenté par l'objet System.in
La méthode nextInt()
permet de lire un entier. Pour lire un
réel, nextFloat()
ou nextDouble()
. Pour les
chaînes, nextLine()
pour lire une ligne ou next()
pour une chaîne, etc. (exercice: vérifier ces méthodes). Il n'y a pas nextChar()
!
Pour en savoir plus, voir (https://docs.oracle.com/javase/7/docs/api/java/util/Scanner.html
).
Note : Avec scanner
on instancie normalement
un objet à partir d'un fichier texte qui contient des données, e.g.
new Scanner(new File("monFichier.data"));
Il faut alors utiliser l'exception FileNotFoundException
(de
la classe File
) pour cette instruction.
import java.util.*; // Package Java qui contient la classe scanner
class Saisie2 {
static public void main(String args[]) {
// Partie Déclaration
Scanner clavier = new Scanner(System.in);
int age;
String nom;
double taille;
// Partie lecture de données
System.out.print("Quelle est votre nom?: ");
nom = clavier.nextLine();
System.out.print("Quelle est votre age?: ");
age = clavier.nextInt();
System.out.print("Quelle est votre taille?: ");
taille = clavier.nextDouble();
// Partie sortie des résultats
System.out.println("Bonjour "+nom);
System.out.print("Vous avez "+age+" ans");
System.out.println(" et vous mesurez "+taille+" mètres");
}
};
Remarque : On pourrait saisir l'âge et la taille sur une même
ligne séparés par espace. la classe scanner
utilise les
caractères tabulation, fin de ligne et espaces comme séparateurs par
défaut. Mais l'utilisateur peut en spécifier d'autres avec la méthode useDelimiter()
.
Voir la référence
ci-dessus pour plus de détails.
Exercice: Créer, compiler et exécuter ce programme.
Version 2: Le même programme. Sortie des résultats avec format.
Au lieu de println()
, on peut utiliser format()
qui a la syntaxe de printf() de
C.
Exercice: Remplacer les trois dernières lignes System.out.print(ln)
par :
System.out.format("Bonjour %s %nVous avez %d ans", nom, age);
System.out.format(" et vous mesurez %f mètres %n", taille);
NB. la méthode System.out.printf()
existe aussi et
est équivalente à System.out.format()
. %n
est
le format pour "nouvelle ligne".
On lit une chaîne avec next()
, et on prend son premier
caractère avec charAt(0)
.
import java.util.Scanner;
class monChar {
static public void main(String args[]) {
char monChar;
Scanner clavier = new Scanner(System.in);
String s = clavier.next();
monChar = s.charAt(0);
System.out.println(monChar);
}
}
On peut condenser et écrire :
monChar = clavier.next().charAt(0);
sans déclarer explicitement la chaîne s.
Conversion d'une température donnée en degré Celsius, vers une température en degré Fahrenait.
a. Sur le même modèle que le
programme précédent, créer un programme Java (fichier Celsius.java
)
class Celsius {
public static void main(String args[]){
...
}
}
qui effectue cette conversion. Utiliser la formule:
f = 9./5 * c + 32
où f est la t° Fahrenait
et c la t° Celsius.
Appeler la classe Celsius
, et le source Celsius.java
.
NB. Pour que la division 9/5 s'effectue en réel, utiliser 9. au lieu 9 dans le source Java.
b. Version 2: Usage de fonction en Java (static, dans la même classe).
Dans le source Celsius.java
. ajouter maintenant la fonction
(on dit aussi méthode):
static double c2f(int c){
double f = 9./5 * c + 32;
return f;
}
(à ajouter après la fonction main()
avant l' }
de fin de classe Celsius) et
remplacer l'instruction initiale
f = 9./5 * c + 32;
par
f = c2f (c) ;
Compiler et exécuter. Discuter.
c. Version
3: Mettre maintenant la fonction c2f()
ci-dessus
dans une nouvelle classe que
l'on appellera Celc
.
class Celc {
static double c2f(int c){
double f = 9./5 * c + 32;
return f;
}
};
(à ajouter après
l' };
de fin de classe Celsius
dans le même fichier source).
et remplacer l'instruction initiale (programme main toujours)
f =
c2f (c) ;
par
f = Celc.c2f (c) ;
Compiler et exécuter. Discuter.
d. Version
4: (Ne pas imiter cet exemple.) Maintenant, enlever le mot static
dans le profile de la fonction c2f()
de la classe Celc
( double c2f(int c)
au lieu de static double c2f (int
c)
)
et remplacer l'instruction initiale (programme main toujours)
f = Celc.c2f (c) ;
par
f = obj.c2f (c) ;
où obj
est une variable à
déclarer auparavant par:
Celc obj = new
Celc();
Compiler et exécuter. Discuter.
A Noter: Dans ce dernier cas, on doit d'abord instancier un objet obj de la classe Celc pour pouvoir appeler (donc lui appliquer) la fonction c2f(), dite méthode d'instance dans ce cas. Mais comme, il n'y a pas de données propres à chaque objet de cette classe Celc, il n'y a pas besoin d'instancier un objet pour utiliser la méthode c2f(). C'est pour cette raison qu'on peut la déclarer static. Comme cela on l'appelle sans instancier d'objets. On dit méthode de classe dans ce cas.
Remarque: Noter aussi qu'on pourrait, dans le premier cas, instancier plusieurs objets obj1, obj2, ... de classe Celc. L'appel objn.c2f (c) serait indifférent de l'objet auquel il s'applique. Ce qui explique pourquoi il y a des fonctions static et justifie la méthode de classe dans la Version-3 ci-dessus.
En principe, une méthode a un nom unique dans une classe. Cependant Java permet à une méthode d'avoir le même nom que d'autres grâce au mécanisme de surcharge (ang. overload). Java utilise leur signature pour distinguer entre les différentes méthodes ayant le même nom dans une classe, c'est à dire la liste des paramètres. Ce sont le nombre et le type des paramètres qui permet de distinguer.
Soit la classe DataArtist
:
class DataArtist {
static void draw(String s) {
System.out.println("Ceci est une chaîne: "+s);
}
static void draw(int i) {
System.out.println("Ceci est un entier: "+i);
}
static void draw(double f) {
System.out.println("Maintenant un double: "+f);
}
static void draw(int i, double f) {
System.out.format("Une entier %d et un double %f %n",i,f);
}
}
Les différents appels suivant correspondent aux bonnes fonctions:
DataArtist.draw ("Picasso"); // 1ère méthode, draw(String)
DataArtist.draw (1); // 2e méthode, draw(Int)
DataArtist.draw (3.1459); // 3e méthode, draw(double)
DataArtist.draw (2, 1.68); // 4e méthode, draw (int, double)
Exercice: Le vérifier.
A noter: Le type retour d'une fonction ne permet pas de distinguer entre
deux fonctions. Par exemple, static int draw(int i)
est la même signature que static void draw(int i)
. Le
vérifier en compilant une classe qui ne contient que ces deux fonctions
(mettre un corps vide {}
).
La surcharge est surtout utile pour définir plusieurs constructeurs pour un objet.
Un aspect particulier de la surcharge et la déclaration d'un nombre
arbitraire de paramètres. Cela se fait par une ellipse (trois points ...
).
Soit l'exemple:
public static void f(char c, int... p) {
System.out.println(c + " " + p.length);
for (int e:p) System.out.println(" " + e);
}
L'ellipse ...
doit apparaître après le dernier paramètre.
Ici, on une premier paramètre char
et ensuite 0, 1 ou
plusieurs entiers dans une variable p
. int...
signifie un nombre quelconque de paramètres entiers. Au fait,
l'ellipse remplace favorablement un paramètre tableau dont la taille est
bornée. C'est comme un tableau mais de taille illimitée (sauf par le
système). D'où l'usage possible de p.length
dans la fonction
pour connaître la taille actuelle du paramètre p
. La
fonction imprime ensuite ses paramètres.
Les appels suivants sont valides :
char c='a';
f(c);
f(c, 1);
f(c, 2,3,4);
int[] monTableau = {5,6,7,8 };
f(c, monTableau);
Exercice : Vérifier l'exemple et chercher d'autres cas à vous.
NB. C'est comme l'opérateur relationnel de Projection. qui admet en paramètre un nom de relation et ensuite une suite de noms d'attributs de projection.
Math
du package lang
.import java.lang.Math;
Cette classe contient, en plus des constantes e
et pi, les méthodes pour le
calcul numériques (fonctions mathématiques classiques). Ce sont des
méthodes toutes static
. Exemple double Math.abs
(double)
, double Math.sqrt (double)
etc.
(http://docs.oracle.com/javase/8/docs/api/java/lang/Math.html
)
Exercice : Vérifier le programme suivant:
import java.lang.Math;
class TestMath {
static public void main(String args[]) {
System.out.println("e = " + Math.E);
System.out.println("pi = " + Math.PI);
int largeur = 3, longueur = 4;
double w = Math.pow(largeur,2) + Math.pow(longueur,2);
double hypotenuse = Math.sqrt(w);
System.out.println("Hypoténuse = " + hypotenuse);
//... il vaut mieux écrire largeur * largeur que pow (largeur,2)... Of course ;-)
}
}
NB. L'instruction import
n'est pas nécessaire ici. Les
classes du package java.lang
sont importées implicitement .
Exercice: Utiliser la fonction static double random()
,
qui retourne un nombre pseudo-aléatoire supérieur ou égal à 0.0 et
inférieur à 1.0, pour imprimer 6 nombres entiers aléatoires compris entre
1 et 49 inclus.
Modifier le programme pour avoir 6 nombres tous différents (c.f. jeu du Loto).
Calendar
du package
util
.Cette classe abstraite contient les méthodes pour manipuler les dates
dans toute ces composantes (à travers les champs YEAR
, MONTH
,
DAY_OF_MONTH
, HOUR
etc.), et faire des calculs
sur les dates comme déterminer le prochain jour ou semaine.
(voir
http://docs.oracle.com/javase/8/docs/api/java/util/Calendar.html
pour les détails de champs et méthodes)
Exemple-1 : L'objet Calendar
et son contenu:
import java.util.*;
class TestCalendar {
static public void main(String args[]) {
Calendar rightNow = Calendar.getInstance();
// Création d'une instance date initialisée par défaut à la date locale.
System.out.println(rightNow);
// le contenu de rightNow pour les curieux!
}
}
Après exécution (le Fri Mar 23 10:34:04 WET 2012
):
java.util.GregorianCalendar[
… informations techniques sur le fuseau horaire,
la zone, l'heure d'été etc. …
firstDayOfWeek=1,
minimalDaysInFirstWeek=1,
ERA=1,
YEAR=2012,
MONTH=2, <-- Mois numérotée à partir de 0
WEEK_OF_YEAR=12,
WEEK_OF_MONTH=4,
DAY_OF_MONTH=23,
DAY_OF_YEAR=83,
DAY_OF_WEEK=6, <-- 6e jour de la semaine (Vendredi)
DAY_OF_WEEK_IN_MONTH=4,
AM_PM=0,
HOUR=10,
HOUR_OF_DAY=10,
MINUTE=34,
SECOND=7,
MILLISECOND=578,
ZONE_OFFSET=0, <-- Décalage horaire 0, GMT.
DST_OFFSET=0
]
Exemple-2 : Les fonctions d'accès aux champs. Les fonctions get(...) sont nombreuses et de la
forme get(quelqueChose)
où le paramètre est un champs Calendar
(constante symbolique
de type entier). Voir la
documentation officielle. API ci-dessus.
class TestCalendar {
static public void main(String args[]) {
Calendar rightNow = Calendar.getInstance();
// tester les get()
int j = rightNow.get (Calendar.DAY_OF_MONTH);
int m = rightNow.get (Calendar.MONTH);
int y = rightNow.get (Calendar.YEAR);
System.out.println("On est le:"+j+ "/" +(m+1)+"/"+y);
}
}
Affiche:
On est le:19/4/2019
On a rajouté 1 pour le mois, car ils sont comptés à partir de 0. (Voir résultat exemple-1)
Exemple-3 : Calcul du jour.
Dans le même programme, rajouter en les complétant les instructions
suivantes pour déterminer le nom du jour de la semaine de façon à
imprimer: "On est le:Vendredi
19/4/2019
".
String jour ="";
switch(rightNow.get(Calendar.DAY_OF_WEEK)){
case 1: jour = "Dimanche"; break;
case 2: jour = "Lundi"; break;
// ... à compléter ...
case 7: jour = "Samedi"; break;
}
System.out.printf("On est le: %s %d/%d/%d%n", jour, j, m+1, y);
Exemple-4 : Utilisation des set(...) pour changer les dates. Même remarque que pour les get(...). Voir l'API ci-dessus.
La fonction set (champ , valeur ) permet de changer le champ (entier) d'une date
Exercice : Reprendre le même programme, et changer de date du mois vers Mai.
rightNow.set(Calendar.MONTH, Calendar.MAY);
et le jour du mis vers le 28.
rightNow.set(Calendar.DAY_OF_MONTH, 28);
pour imprimer la date du jour comme précédemment.
Utiliser la fonction add (champ, valeur) pour calculer la date du lendemain.
rightNow.add (Calendar.DAY_OF_MONTH, 1);
Exercice : Vérifier que le lendemain du 28 Février est 29 Février 2016, année bissextile, et que le lendemain du 28 Février est 1er Mars pour 2019.
Exercices : Faire d'autres exemples... Utiliser le champ Hour_OF_DAY
.
Elle permettent aussi de manier un type primitif (int
,
float
, double
, etc.) commet une classe.
Ce sont les classes Integer
, Float
, Boolean
etc. du package java.lang
. Ce sont des sous-classes de la
classe Number
.
Ces classes détiennent principalement des méthodes pour convertir entre elles des données numériques, surtout vers (ou à partir de) leur forme chaine de caractères.
a) On considèrera le cas de la
classe Integer
, les autres sont semblables.
String
vers
Integer
. Fonction valueOf().
Correspondance entre la chaîne "123"
et l'entier Integer
de valeur 123.Integer I;
I = Integer.valueOf("123");
Remarque: Par constructeur on peut faire la
même conversion avec new Integer (
"123");
.
String
vers
int
. Fonction parseInt().
Correspondance entre "456"
et l'entier int
de valeur 456.int i;
i = Integer.parseInt("456");
Integer
vers int
. Fonction intValue().
Correspondance entre objet Integer
et entier int
. int i; Integer I;
i = I.intValue();
Remarquer que c'est une méthode d'instance ici (fonction d'accès).
int
vers Integer
.
Correspondance inverse de int
vers Integer
.Integer I = new Integer (i); // Par constructeur
Integer
ou
int
vers
chaîne String
. Passage
réciproque de Integer
ou int
vers chaîne String
.Méthode générale valueOf()
de la classe String
s'appliquant (par surcharge) à
tous les types primitifs.
int i : 34;
s = String.valueOf(i); // s devient "34"
Méthode toString()
de la classe
Integer
ici.
String s;
Integer I = 345;
s = I.toString(); // s devient "345"
Cette méthode est intéressante car elle est
héritée de la classe Object et peut donc s'appliquer à tout
objet si elle est redéfinie. On peut l'utiliser à profit pour imprimer un
objet println(objet.toString);
.
Integer
. Résultat int
.int i = I.compareTo(J); // 0 si I = J, négatif si I<J, positif si I>J
On peut aussi utiliser les opérateurs de
comparaison comme I < J
.
b) Le cas des autres classes est analogue. Par exemple:
float f = 12.34f;
Float F = new Float (f); // de float vers Float
String s;
F = Float.valueOf("12.34"); // de String vers Float
f = Float.parseFloat ("12.34"); // de String vers float
f = F.floatValue(); // de Float vers float
s = F.toString(); // de Float vers String
s = String.valueOf(f); // de float vers String
...
Voir par exemple https://docs.oracle.com/javase/8/docs/api/java/lang/Integer.html
remarque importante:
Les références à objets : Une affectation x = y n'est pas toujours le même effet selon que ce soit un objet primitif ou non. Selon que x et y contiennent des valeurs primitives ou sont des références vers des objets.
On va le tester sur des entiers (objets primitifs) et sur un tableau (objet java).
// // Objets vs Valeurs // class Test { static public void main(String[] args) { int x = 1, y; //////// affectation de valeurs ///////// y = x; // deux valeurs égales mais objets differents. System.out.println("Avant (x = 100): x = " + x + " , y = " + y); x = 100; System.out.println("Après (x = 100): x = " + x + " mais y = " + y); // constater que y n'as pas changé int[] u = {4, 5}; // tableau à 2 entiers. int[] v; ////// même chose avec objets (ici tableaux) /////// v = u; System.out.println("Avant (u[0] = 100): u[0] = " + u[0] + " , v[0] = " + v[0]); u[0] = 100; System.out.println("Après (u[0] = 100): u[0] = " + u[0] + " ET v[0] = " + v[0]); // constater que v[0] a changé aussi } }
On obtiendra:
Avant (x = 100): x = 1 , y = 1
Après (x = 100): x = 100 mais y = 1 <-- y n'a pas changé avec x
Avant (u[0] = 100): u[0] = 4 , v[0] = 4
Après (u[0] = 100): u[0] = 100 ET v[0] = 100 <-- v a changé avec u
où on voit que u
et v
désignent le même
objet: une modification de u
est aussi une modification de v
.
Exercice:
Selon la même idée, faire un programme qui teste l'affectation x = y où x et y sont des objet d'une classe C.
Indication: Soit la classe C :
class C {
int x; // un champ entier
public int getX(){return x;} // méthode pour consulter le champ x
public void setX(int p){x = p;} // méthode pour modifier le champ x }
Créer deux instances x et y :
C x = new C(), y = new C();
les initialiser et les afficher :
x.setX(5);
y.setX(6);
System.out.println(x.getX() + " et " + y.getX());
Constater le résultat: 5 et 6
. Deux objets différents.
Faire maintenant :
x = y;
ensuite modifier x et afficher x y :
x.setX(4);
System.out.println(x.getX() + " et " + y.getX());
Constater que y aussi a été
modifié (résultat: 4 et 4
).
On retrouve cette même caractéristique dans le passage des paramètres en Java.
Les objets en Java sont passés en paramètre par valeur. Mais cette valeur peut-être une donnée (objet primitif) ou une référence à un objet.
Tester sur l'exemple suivant:
//
// Passage des paramètres
//
class Test extends Object {
static public void main(String args[]){
int x = 2;
System.out.println("Avant modif, x = " + x);
modifVal(x);
System.out.println("Apres modif, x = " + x);
int [] t = {2, 3};
System.out.println("Avant modif, t[0] = " + t[0]);
modifObj(t);
System.out.println("Apres modif, t[0] = " + t[0]);
}
public static void modifObj(int p[]) {
p[0] = p[0] + 200; // Objet référencé p est modifié
}
public static void modifVal(int x) {
x = x + 200; // paramètre x modifié
}
}
On obtient:
Avant modif, x = 2
Apres modif, x = 2
Avant modif, t[0] = 2
Apres modif, t[0] = 202
NB: Quand on change le paramètre lui-même, c'est à dire la variable p ici, on change la référence mais pas le tableau.
Exercice 8.1: Vérifier
maintenant qu'en modifiant la méthode modifObj
pour changer
p
:
public static void modifObj(int p[]) {
p = new int [] {200, 300, 400}; // p[0] = 200
}
t[0]
ne va pas changer. On aura toujours t[0] =
2
.
Exercice 8.2 : Reprendre la classe C précédente (§7) et tester le passage de paramètre d'un objet de classe C.
Déclarer une fonction:
public static void modifObj(C p) {
p.setX(p.getX() + 200); // Objet référencé p est modifié
}
et l'appeler par modifObj(o);
(en déclarant: C o = new C();
)
Certains exercices seront évalués à la demande et corrigés par l'encadrant du TP..
Installer Java en téléchargeant le JDK à :
http://www.oracle.com/technetwork/java/javase/downloads/
(Choisir JDK et ensuite la version binaire correspondant votre OS)
Pour travailler en mode commande (c:\>
): Démarrer>Exécuter>taper
cmd.
On pourrait souhaiter de créer un répertoire pour y sauvegarder ses
programmes java. Aller vers la racine (ou sur le Bureau
si
ce n'est pas autorisé)
cd c:\
et taper
md votreNom
cd votreNom
Pour taper ses programmes utiliser blocNote simple ou Sublime pour une meilleure assistance syntaxique . Ouvrez d'abord votre répertoire dans une fenêtre Windows.
Les commandes javac
et java
se
trouvent normalement dans le répertoire c:\jdk...\bin
.
Pour éviter de taper le chemin complet
c:\jdk...\bin\javac pgme.java
et taper simplement
javac pgme.java
rajouter le répertoire c:\jdk...\bin
dans la variable
d'environnement Path. Exemple :
Avant : Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem
Après : Path=C:\WINDOWS\system32;C:\WINDOWS;C:\WINDOWS\System32\Wbem;c:\jdk...\bin
Aller dans panneau de configuration, dossier System ensuite l'onglet Avancé. Modifier alors la variable d'environnement Path.