143
Support Java Java java.sun.com/j2se/1.5/docs/api/index.html positionner la variable JAVA_HOME à la racine de Java le path doit contenir tout le chemin jusqu'à java.exe (sous XP panneau de config, système, avancé, variable d'environnement) Brigitte Groléas 1

CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

  • Upload
    others

  • View
    0

  • Download
    0

Embed Size (px)

Citation preview

Page 1: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Java

java.sun.com/j2se/1.5/docs/api/index.htmlpositionner la variable JAVA_HOME à la racine de Java

le path doit contenir tout le chemin jusqu'à java.exe(sous XP panneau de config, système, avancé, variable d'environnement)

Brigitte Groléas 1

Page 2: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

[email protected]

Brigitte Groléas 2

Page 3: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Structure d’une application Java.

1. Historique.Java est un langage orienté objet semi-compilé, développé par Sun. Sa syntaxe est proche de celle du C++. En 1990, une petite équipe dirigée par James Gosling travaille sur la définition d’un langage de programmation dénommé « Oak » (Chêne en anglais) destiné à faciliter l’implémentation de logiciels pour l’électronique grand publique (téléphone, téléviseurs, magnétoscope, cafetières, four à micro-onde, etc...). Ce langage doit être petit, simple, robuste, fiable et indépendant de l’architecture.Au printemps 1994, l’explosion du Web sur l’Internet dynamise l’équipe de James Gosling. Un langage indépendant de l’architecture est idéal pour programmer sur un réseau hétérogène comme Internet. Le projet change de nom et d’orientation. Le langage Java1 est néEn Mai 1995, l’équipe de Gosling présente la version Bêta de HotJava, un navigateur Web, écrit entièrement en Java, destiné à démontrer les possibilités du langage et supportant les applets2 Java. La société Netscape annonce que son navigateur Web 2.0 supportera les applets Java de Sun.Au printemps 1996, Sun rend publique la première version Bêta du JDK (Java Development Kit), un environnement de programmation Java complet et gratuit. Rapidement les principaux éditeurs de logiciels concluent des accords de licence avec Sun pour diffuser Java (Netscape en mai 95, Oracle en Octobre 95, Borland en novembre 95, IBM et Adobe et Symantec en décembre 95, Microsoft et Novell en mars 96).Netscape, conjointement avec Sun développe un autre langage : JavaScript. JavaScript est une version simplifiée de Java permettant l’écriture de scripts directement dans une page HTML. Il est interprété par le navigateur lorsque la page est chargée. Très limité, (langage interprété, pas de possibilité de définir des classes d’objets, ... ), JavaScript est, en fait, un langage auteur, pas un langage de développement.

1 Le choix du nom Java (café en argot américain) tient au fait que l’équipe de James Gosling a du consommer de nombreux cafés pour que le projet voit le jour !2 Une applet Java n’est pas une application Java, mais une classe Java chargée dynamiquement par une application Java déjà en train de tourner, comme par exemple, un navigateur Web ou un visualisateur d’applet (appletviewer du JDK de Sun).

Brigitte Groléas 3

Page 4: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Les applets développées avec la version 1.0.2 du JDK (Java Development Kit) de Sun sont compatibles avec les navigateurs Web « Netscape 3.0 » et « Internet Explorer 3.0 ».En mars 1997, Sun sort la version 1.1 du JDK qui reprend l’intégralité des API du JDK 1.0 avec de nouvelles fonctionnalités concernant la gestion des événements et un élargissement substantiel de la bibliothèque (23 packages au lieu de 8). L’utilisation de ces ajouts dans des applets nécessite l’utilisation des navigateurs Web « Internet Explorer 4.0 » ou « Communicator » de Netscape.

Brigitte Groléas 4

Page 5: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Présentation du langage Java.

Points forts de Java :

simple et orienté objet C’est du C++, sans pointeur, avec des références.

robuste, fiable et sûr Java est fortement typé et impose au programmeur une certaine rigueur de programmation ce qui permet au langage d’effectuer des vérifications de cohérence et d’éviter bon nombre de bugs.

efficace et riche une bibliothèque de fonctionnalités impressionnante

interprété, indépendant de l’architecture et rapide Java est semi-compilé. Le compilateur Java génère du byte-code, qui est interprété par la JVM (Java Virtual Machine). Ce byte-code permet d’obtenir un format indépendant de l’architecture. L’interprétation de ce byte-code est environ 20 fois plus lente que du code natif issue d’un compilateur. En revanche, il est bien plus rapide qu’un langage de scriptage entièrement interprété (comme JavaScript, Perl, le shell d’unix ou Tcl). De plus, il est possible de recompiler le byte-code afin de produire du code natif et d’atteindre des performances identiques à celle du C.

portable Les spécifications du langage sont indépendantes de la plate-forme utilisée tant au niveau des types de base que de l’environnement proposé dans les packages. L’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est écrite en C ANSI POSIX.

Brigitte Groléas 5

Page 6: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

multitâche (multithread) Java permet de créer des applications capables d’effectuer plusieurs actions (thread) en même temps. Le langage permet un multitâche coopératif ou bien préemptif et fournit des outils de synchronisation et de rendez-vous. Un même programme peut à l’aide de trois threads scruter le clavier tout en chargeant une image et en diffusant un son.

réparti Java est conçu pour le développement d’applications réparties. Il permet d’accéder facilement à des données distantes sur le réseaux, et de réaliser des application client/serveur grâce au package java.net.

dynamique et distribué Un programme Java charge les classes qu’il utilise (y compris les classes de base) en cours d’exécution et éventuellement au travers du réseaux. La possibilité de télécharger le code nécessaire à partir d’un serveur doit permettre à terme d’éviter les installations et mise à jour de logiciels et permettre à Java une grande adaptabilité à tout nouvel environnement.

Brigitte Groléas 6

Page 7: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

3. Structure d’une application Java.Un fichier source Java est constitué de la définition d’une seule classe publique et doit obligatoirement porter le même nom que celui de la classe publique qu’il contient, suivi de l’extension « .java ». Il peut contenir la définition d’autres classes, non publiques, qui ne seront pas accessibles depuis l’extérieur du package. (Un package est un regroupement de classes situées dans un même répertoire).La compilation d’un fichier source « .java » produit un fichier « .class » pour chacune des classes contenues dans le fichier source. Par conséquent, chaque classe compilée est stockée dans un fichier séparé. Le nom du fichier compilé est le même que celui de la classe qu’il contient, suivi de l’extension « .class ».L’une des classes publiques contenue dans l’un des fichiers sources doit contenir une fonction membre statique « main() » qui défini le point d’entrée de l’application Java (Programme principal). Par exemple :

public class Essai {public static void main( String argv[] ) {

System.out.print( "coucou\n" );}

}

La compilation d’un fichier source Java s’effectue par la commande « javac » du JDK (Java Development Kit) de Sun avec en argument le nom du fichier à compiler.

javac Essai.java

Une fois compilé, le programme Java peut être exécuté en lançant l’interpréteur « java » du JDK de Sun en précisant en argument le nom de la classe contenant la méthode statique « main() ».

java Essai

Le code est alors exécuté sur la machine virtuelle java (JVM pour Java Virtual Machine).

Brigitte Groléas 7

Page 8: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

4. Programmation modulaire : les packages.Un package désigne un ensemble de classes compilées (fichiers « .class »), situées dans un même répertoire. La position où se situe le fichier compilé « .class » défini le nom du package, (en remplaçant les séparateurs de répertoires par des points).

Répertoire : toto/titi/tataNom du package : toto.titi.tata

Pour des raisons d’économie de place, un package ou une arborescence de package peut être compressé et stocké dans un fichier au format « .jar ».

En Java, toutes les classes font partie d’un package. Le rattachement d’un fichier source Java à un package donné est réalisé par l’instruction « package » suivi du nom du package. Le nom du package doit correspondre à la position du fichier « .class » dans l’arborescence des répertoires. L’instruction package ne peut apparaître que dans la première ligne de code du fichier source.

package toto.titi.tata;

Si l’instruction package est omise, le code fait implicitement partie d’un package anonyme par défaut et le fichier compilé doit résider dans le répertoire courant.

Lorsqu’une classe fait partie d’un package, cette classe peut être référencée par son nom complet, en indiquant le nom du package suivi du nom de la classe séparé par un point. Par exemple, une classe bidule du package « toto.titi.tata » correspondant à un fichier compilé « bidule.class » résidant dans le répertoire toto/titi/tata est univoquement identifié par :

toto.titi.tata.bidule

Brigitte Groléas 8

Page 9: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

L’instruction « import » permet d’importer une classe ou un ensemble de classes situées dans un package.

import toto.titi.tata.essai;import toto.titi.tata.*;

Ces instructions « import » doivent être situées au début du fichier source juste après l’instruction optionnelle « package ».Dès lors, il est possible de référencer les classes importées par leurs noms abrégés plutôt que par leurs noms complets (en omettant le préfixe désignant le package d’où elles proviennent).Il faut noter que l’instruction import ne provoque pas le chargement des classes importées et ne sert exclusivement qu’à alléger la syntaxe d’accès aux classes importées. Toutefois, si deux packages importés contiennent des classes homonymes, il est nécessaire d’employer le version longue du nom (nom complet) pour lever l’ambiguïté.

Dans la version 1.0 ; l’API Java était constituée de classes définies dans les huit packages suivants :

java.applet Classes pour implémenter les applets.java.awt Classes pour les graphiques (GUI) .java.awt.image Classes pour le traitement des Imagesjava.awt.peer Interfaces avec les environnements natifsjava.io Classes pour les entrées/sortiesjava.lang Classes de base du langage.java.net Classespour la communication réseaux.java.util Classes d’utilitaires.

NOTE : Le package « java.lang » est automatiquement importé dans tous les sources Java.

Brigitte Groléas 9

Page 10: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Les types de données Java :Le langage Java utilise une syntaxe proche du C et du C++. Toutefois, la notion de pointeur (au sens langage C du terme) est totalement absente. Certains types de données sont gérés par valeur, d’autres par référence.

1. Types gérés par valeur : types primitifsJava possède un certain nombre de types de données primitifs (qui ne sont pas des objets !) . Ces types de données sont gérés par valeur (i.e. par copie). Lors de l’affectation d’une variable d’un type primitif à une autre, c’est la valeur de l’une qui est copiée dans l’autre. Il en va de même pour le passage de type primitif en argument d’une fonction ; c’est une copie de la valeur qui est transmise et non la variable elle même.

Chaque type primitif correspond à une taille bien précise en mémoire identique sur toutes les plates-formes. :

type valeur par défautchar caractère unicode \u0000boolean valeur booléenne falsebyte entier signé 8 bits 0short entier signé 16 bits 0int entier signé 32 bits 0long entier signé 64 bits 0float flottant 32 bits 0.0double flottant 64 bits 0.0

Chaque type primitif (sauf short et byte qui ne sont que des types de stockage) possède une classe associée définie dans le package « java.lang ». Ces classes sont Boolean, Character, Integer, Long, Float et Double. Elles permettent de définir des constantes et des méthodes utiles. Par exemple, certaines de ces classes déclarent les constantes MIN_VALUE et MAX_VALUE.

Brigitte Groléas 10

Page 11: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

les caractères UnicodeEn Java, les caractères qui composent les chaînes de caractères mais aussi les identificateurs (variables, fonctions, nom de classes, etc.) sont définis en code « Unicode » sur 16 bits, afin d’intégrer les différentes polices internationales. Le Jeu de caractère Unicode est compatible avec le code ASCII et même avec le code ISO8859-1 (Latin-1) pour les 256 premiers code. Il est ainsi possible de définir des noms de fonction ou de classe en utilisant les caractères accentués du français.Les caractères Unicode non représentable sur la plate-forme d’accueil peuvent être exprimés par leur code en hexadécimal sur 4 digits avec la forme suivante :

\uXXXX 

Les identificateurs doivent commencer par une lettre (au sens Unicode) ou un caractère « _ » ou un « $ » et être suivi d’une série de lettres ou de chiffres (toujours au sens Unicode). Attention aux lettres indiscernables, pourtant différentes (N latin ou N grecque !)

Le type booléenLe type booléen est différent et non compatible avec le type entier. Les constantes booléennes sont « true » et « false ».

Les types entiers ( byte, short, int, long )Tous les types entiers de Java sont signés et il n’existe pas de type « non signé ».Les constantes entières s’expriment en base 8, 10, ou 16 de la manière suivante :

100 (base 10)0x64 (base 16)0141 (base 8)100L (sur un long)

Tout ce qui est moins précis que le type « int » (i.e. short ou byte) est toujours converti en un « int » avant une évaluation d’expression ou un passage d’argument.Un entier est implicitement convertible en un entier de précision plus grande ou en un type réel (le contraire est faux). On peut employer un cast explicite pour convertir vers un type numérique moins précis.

Brigitte Groléas 11

Page 12: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Une division par zéro ou un modulo zéro produit une erreur de type « ArithmeticException ».

Les types réels ( float, double )Les constantes en virgule flottante sont de type double sauf si elles sont suffixées par un « f ». On peut également suffixer les constantes de type double par un « d ». On ne peut pas utiliser une constante double pour affecter une variable de type float (sauf si on fait une conversion explicite avec l’opérateur de cast).

Certaines valeurs particulières peuvent être produites lors de calculs (Infini positif, Infini négatif, Zéro négatif et Non-Nombre). Ces valeurs particulières sont définies dans les classes « java.lang.Float » et « java.lang.Double ») sous forme de constantes : POSITIVE_INFINITY, NEGATIVE_INFINITY, NaN (i.e. Not A Number).

La valeur NaN comparée à n’importe quel autre nombre (y compris lui-même) produit toujours un résultat faux. Pour faire des tests sur NaN, il faut utiliser les prédicats « Float.isNaN » ou « Double.isNaN ».

Un test de comparaison entre un zéro positif et un zéro négatif produit bien un résultat vrai, mais lors d’une division pas zéro, suivant qu’il s’agit d’un zéro positif ou négatif, on obtient un infini positif ou négatif.Grâce à ces valeurs particulières, l’arithmétique sur les nombres flottants ne produit jamais d’erreur.

Brigitte Groléas 12

Page 13: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Types gérés par références : Les objetsHormis les types primitifs, les autres types de données de Java sont les objets et les tableaux (qui sont assimilables à des objets ). Ils sont traités par référence et non par valeur. En d’autres termes, c’est l’adresse de l’objet qui est stockée dans une variable ou passée en paramètre aux fonctions et non une copie de l’objet.

Instanciation et destruction des objetsLa déclaration d’une variable destinée à référencer un objet ne suffit pas à créer cet objet. Pour instancier un objet, il faut utiliser explicitement l’opérateur « new ».

ClassName x; //Crée la référencex = new ClassName(); //Crée l’objet et le référence par x

La libération des objets qui ne sont plus utilisés est implicite. Un mécanisme de récupération (Garbage Collector) est mis en œuvre par le système.

Copie et Test d’égalité entre objetsBien entendu, les objets étant manipulés par référence, deux variables différentes peuvent désigner le même objet :

ClassName x = new ClassName();ClassName y = x; //x et y désignent tout deux le même objet !

Si l’on veut copier un objet, on peut utiliser la méthode « clone() »si elle est implémentée par la classe en question (Classes implémentant l’interface « Cloneable » ).

ClassName x = new ClassName();ClassName y = x.clone();

De même, pour tester l’égalité entre deux objets, on ne peut utiliser l’opérateur « == ». En effet, l’opération « == » ne permet que de tester si les deux variables réfèrent le même objet sans chercher à savoir si les deux objets référencés contiennent les mêmes valeurs.

Brigitte Groléas 13

Page 14: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Pour tester l’égalité entre deux objets, il faut employer une méthode spécialement conçue pour comparer ces objets. En java, un certains nombre de classes redéfinissent la méthode « equal() » de la classe « Object ».

Les références sur TableauxLa définition d’une référence sur tableau s’effectue en ajoutant une paire de crochets vide devant ou derrière le nom de la variable.

int tab1[]; ou int [] tab;ClassName tab2[]; ou ClassName [] tab;

Instanciation de tableauxL’instanciation de « l’objet » tableau proprement dit, s’effectue de la même façon que pour les autres objets grâce à l’opérateur « new » suivi du type et d’une paire de cochets incluant la taille du tableau. La destruction du tableau est automatiquement effectuée par le système via le mécanisme du Garbage Collector (GC).

tab1= new int[100];tab2= new ClassName[10];

La création d’un tableau ne crée pas les objets contenus dans le tableau (c’est pour cela qu’il n’y as pas d’appel au constructeur !). Les éléments du tableau sont initialisés avec les valeurs dépendant du type du tableau (la valeur par défaut du type primitif, ou la valeur null pour les tableaux d’objets)Toutefois, il est possible de créer des tableaux par initialisation statique :

int tab[] = { 1, 2, 3, 4, 5};String dico[]= { "hiboux", "choux", "genoux" };

Tableaux multi-dimensionnelsComme les tableaux sont des objets, les tableaux multi-dimensionnels sont naturellement implémentés comme des tableaux de tableaux :

Brigitte Groléas 14

Page 15: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

int tab[][][] = new int[5][4][3];

Lors de l’allocation d’un tableau multi-dimensionnel, il n’est pas obligatoire de stipuler le nombre d’éléments contenus pour chaque dimension (seule la première est obligatoire). Il est même possible d’avoir des tailles différentes pour chacun des sous-tableaux :

int tab[][] = new int[3][]; // 3 références sur des int[]tab[0] = new int[2]; // 1er s/s tableau : 2 casestab[1] = new int[3]; // 2eme s/s tableau : 3 casestab[2] = new int[4]; // 3eme s/s tableau : 4 cases

On peut également initialiser des tableaux multi-dimensionnels à l’aide d’initialiseurs imbriqués :

int tab[][] = { { 1, 2}, { 3, 4, 5 }, { 6, 7, 8, 9 } };

Accès aux éléments et aux dimensions d’un tableauL’accès aux éléments d’un tableau s’effectue en suffixant le nom du tableau d’une paire de crochets contenant une expression de type entier qui sert d’indice pour identifier le numéro de case désirée. La première case est le numéro zéro.La donnée membre « length », en lecture seule, permet de retrouver la taille d’un tableau :

int tab[][]= new tab[10][20];System.out.println( tab.length ); // imprime 10System.out.println( tab[0].length ); // imprime 20

En Java, tous les accès aux tableaux sont contrôlés. Une erreur (exception) de type ArrayIndexOutOfBoundsException est générée en cas de débordement.

Les Chaînes de caractères : StringEn java, les chaînes de caractères sont implémentées par la classe « String » située dans la package « java.lang ». Cependant, les objets de la classe « String » bénéficient de traitements spéciaux de la part du compilateur Java. Par exemple, il génère automatiquement un nouvel objet String lorsqu’il rencontre une chaîne de caractères constante entre guillemets.

Brigitte Groléas 15

Page 16: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

String s = "Bonjour";

Le contenu des objets de la classe String ne peut pas être modifié. En revanche, il existe une classe StringBuffer qui possède des méthodes permettant de modifier le contenu de la chaîne.

String s = "Coucou";StringBuffer buf = new StringBuffer( s );buf.append( " me revoilou" );System.out.println( buf ); // Coucou me revoilou

La classe string dispose de l’opérateur « + » qui permet de concaténer les chaînes de caractères. Si l’un des opérandes d’une opération de concaténation « + » n’est pas de type string, il est automatiquement converti en une chaîne de façon native pour les types primitifs ou via la méthode « toString() » pour les types non-primitifs.

int i = 5;System.out.println( "i = " + i );

Brigitte Groléas 16

Page 17: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Les Opérateurs.La priorité (précédence) des opérateurs indique l'ordre dans lequel Java évalue les opérateurs au sein d'une même expression. Le tableau ci-dessous résume les règles de priorités dans l’évaluation des différents opérateurs.

PREC NOM OPERANDE ASSOCIATIVITE 1 ++, --, +, - numérique D

~ entier D! booleen Dnew, (type) tout type D

2 *, /, % numérique G3 +, - numérique G

+ String G4 >>, <<, >>> entier G5 >, >=, <, <= numérique G

instanceof objet G6 ==, != primitif,référence G7 & entier ou booleen G8 ^ entier ou booleen G9 | entier ou booleen G10 && booleen G11 || booleen G12 ? : booleen,exp,exp D13 =, +=, -=, *=, variable, exp D

/=, %=, <<=, >>=,>>>=, &=, |=, ^=

Le tableau indique la liste des opérateurs, du plus prioritaire (en haut) au moins prioritaire (en bas). Il y a donc 13 niveaux de priorité.

Opérateurs de même Priorité.Les opérateurs de même priorités sont évalués dans l'ordre indique dans le tableau par la flèche d’associativité.

La flèche « --> » indique que les opérateurs sont évalués de la gauche vers la droite. C'est le cas de la majorité des opérateurs.

La flèche « <-- » indique que Les opérateurs sont évalués de la droite vers la gauche. C'est le cas des opérateurs unaires et des opérateurs d'affectations.

Quelques exemples:

Brigitte Groléas 17

Page 18: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

3 + 4 - 7 + 6 - 5 <==> (((3 + 4) - 7) + 6) - 5 3 + 12 * 5 / 3 <==> 3 + ( (12 * 5) / 3 ) x < 2 || x > 5 && x < 7 <==> (x<2) || ((x>5) && (x<7)) x = y = z = 5 <==> x = ( y = (z = 5) ) x = y = z++ * -a <==> x = (y = ((z++) * (-a))) x = y > 7 <==> x = ( y > 7 )

Bien sûr, il est toujours possible de changer l'ordre d’évaluation des opérateurs en parenthésant les expressions de manière à forcer un ordre d’évaluation explicite.

3. Opérateurs Arithmétiques.Les opérateurs arithmétiques sont les suivants:

- Moins unaire -X - Division X / Y - Multiplication X * Y - Modulo X % Y - Addition X + Y - Soustraction X - Y

Les opérateurs arithmétiques peuvent s'employer avec des variables de tous types moyennant quelques restrictions:

Modulo.Le modulo (reste de la division entière) ne peut s'employer que sur des types entiers.

Division.La division est implicitement une division entière lorsque les deux termes de l'expression sont de type entier. Si l'un des deux termes est de type « float » ou « double », la division sera une division réelle.

+ Les Chaînes

L’opérateur « + » permet la concaténation d’objets de type « String ».

Brigitte Groléas 18

Page 19: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

4. Opérateurs binaires.Ces opérateurs permettent de travailler au niveau du bit dans un mot. Ils serviront à tester la présence de bits à « 1 » dans un mot, à forcer des bits à « 0 » ou à « 1 », à isoler une partie d'un mot, à effectuer des décalages. Les opérateurs de manipulations de bits sont les suivants:

- Complément binaire ~X - Et binaire X & Y - Ou exclusif binaire X ^ Y - Ou inclusif binaire X | Y - Décalage à droite X >> Y - Décalage à gauche X << Y

Complément Binaire.Chaque bit résultat est l'inverse du bit source (i.e. chaque bit égal à « 1 » est transformé en « 0 » et inversement). Exemple:

X = 0 0 1 1 0 0 1 1 ------------------------ ~X = 1 1 0 0 1 1 0 0

ET Binaire.Chaque bit résultat vaut « 1 » seulement si les deux bits sources valent « 1 ». « le plus faible gagne » (i.e. la présence d'un « 0 » entraîne un « 0 »). Exemple:

X = 1 1 0 0 1 0 1 1 Y = 1 1 1 1 0 0 0 1 ------------------------ X & Y = 1 1 0 0 0 0 0 1

L’opérateur ET binaire « & » est souvent utilisé pour filtrer un ensemble de bits dans un mot et ne laisser apparaître que les bits désirés. Il est également utilise pour tester la présence d'un ou plusieurs bits à « 1 » au sein d'un mot, ou pour forcer à « 0 » un ou plusieurs bits dans un mot. Exemple: Isoler les 3 derniers bits d'un mot.

X = b7 b6 b5 b4 b3 b2 b1 b0 7 = 0 0 0 0 0 1 1 1

Brigitte Groléas 19

Page 20: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

------------------------- X & 7 = 0 0 0 0 0 b2 b1 b0

Exemple: tester si le bit « b3 » du mot « X » est à « 1 ». X = b7 b6 b5 b4 b3 b2 b1 b0 8 = 0 0 0 0 1 0 0 0 ------------------------- X & 8 = 0 0 0 0 b3 0 0 0

Si le résultat de l'expression « X & 8 » est non nul, alors le bit « b3 » du mot « X » est à « 1 ».

Exemple: Forcer à zéro les trois bits de poids faibles. X = b7 b6 b5 b4 b3 b2 b1 b0 ~7 = 1 1 1 1 1 0 0 0 ------------------------- X & ~7 = b7 b6 b5 b4 b3 0 0 0

OU Inclusif Binaire.Chaque bit résultat vaut « 1 » si l'un au moins des deux bits sources vaut « 1 ». « le plus fort gagne » (i.e. la présence d'un « 1 » entraîne un « 1 »). Exemple:

X = 1 1 0 0 1 0 1 1 Y = 1 1 1 1 0 0 0 1 ------------------------ X | Y = 1 1 1 1 1 0 1 1

L’opérateur « | » est utilisé pour forcer un ou plusieurs bits à « 1 » dans un mot. Exemple: Forcer à « 1 » les trois bits de poids faibles d'un mot.

X = b7 b6 b5 b4 b3 b2 b1 b0 7 = 0 0 0 0 0 1 1 1 ------------------------- X | 7 = b7 b6 b5 b4 b3 1 1 1

OU Exclusif Binaire.Chaque bit résultat vaut « 1 » seulement si les bits sources diffèrent. « retient les différences » (i.e. la présence de bits opposés entraîne un « 1 »).

Brigitte Groléas 20

Page 21: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple: X = 1 1 0 0 1 0 1 1 Y = 1 1 1 1 0 0 0 1 ------------------------ X ^ Y = 0 0 1 1 1 0 1 0

Décalages.Le décalage à gauche de N positions « X << N » a pour effet de renvoyer une valeur correspondant au mot X dont les bits sont décalés vers la gauche de N positions. Les N bits rejetés à gauche sont irrémédiablement perdus, tandis que les N places libres créées à droite, sont remplies par des bits à zéro. Le décalage à droite fonctionne sur le même principe, mais dans l'autre sens. Le décalage à gauche de N positions correspond à la multiplication du mot X par 2 à la puissance N. Inversement, le décalage à droite de N positions correspond à la division entière de X par 2 à la puissance N. Exemple:

5 = 0 0 0 0 0 1 0 1 ------------------------ 5 << 3 = 0 0 1 0 1 0 0 0 = 5 * 8 = 40

5 = 0 0 0 0 0 1 0 1 ------------------------ 5 >> 1 = 0 0 0 0 0 0 1 0 = 5/2 = 2 (division entière)

Les opérateurs « & », « | » et « ^ »peuvent être utilisés sur des booléens pour connecter des expressions de tests. La différence entre « & » et « && » dans un contexte booléen est l’assurance de l’évaluation du deuxième opérande dans le cas du « & » (idem pour le « | »).

L’opérateur « >>> » décale à droite de façon logique (des zéros entrent à gauche).

Brigitte Groléas 21

Page 22: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

5. Opérateurs d'Affectation, d'inc/décrémentation.

Affectation simple.L’opérateur d'affectation permet d'associer une variable à une valeur.

X = Y

La valeur et le type d'une expression d'affectation sont ceux du dernier objet affecté. Dans l'exemple :

int i; int j; float a; a = j = 5 + ( i = 2 );

l'expression « a = j = 5 + ( i = 2 ) » est de type « float » et vaut « 7.0 ».

Affectation Composée.Les opérateurs d'affectations composées sont une combinaison de l’opérateur d'assignement simple avec des opérateurs arithmétiques ou de manipulations de bits. C'est en fait une forme condensée de l’écriture :

X = X <opérateur> Y

qui se transforme en : X <opérateur>= Y

Les opérateurs d'affectation composée sont les suivants: X += Y <==> X = X + Y X -= Y <==> X = X - Y X *= Y <==> X = X * Y X /= Y <==> X = X / Y X %= Y <==> X = X % Y X &= Y <==> X = X & Y X |= Y <==> X = X | Y X ^= Y <== X = X ^ Y X <<= Y <==> X = X << Y X >>= Y <==> X = X >> Y

Brigitte Groléas 22

Page 23: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Bien sûr, certaines affectations composées ne pourront s'effectuer que sur des types entiers (voir pour cela les opérateurs arithmétiques et ceux de manipulations de bits).

Opérateurs d'Inc/Décrémentation.Les opérateurs d’incrémentation et de décrémentation sont les suivants:

- pré-incrémentation ++X - post-incrémentation X++ - pré-décrémentation --X - post-décrémentation X--

Les 2 expressions « ++X » et « X++ » ont pour effet d'augmenter la valeur de X de 1. La différence réside dans la valeur renvoyée par l'expression. Dans le cas de « ++X » c'est la nouvelle valeur de X qui est renvoyée, tandis que dans le cas de « X++ » c'est l'ancienne valeur de X qui est renvoyée. L'expression « X = Y++; » revient à faire:

Tmp = Y; Y = Y + 1; X = Tmp;

Tandis que l'expression « X = ++Y; » revient à faire: Y = Y + 1; X = Y;

Les opérateurs d’incrémentation et de décrémentation seront utilisés dans des boucles. Mais ils seront utiles lors de la manipulation de pointeurs afin de parcourir séquentiellement des tableaux d'objets.

6. Opérateurs Relationnels et Logiques.

Opérateurs Relationnels.Les opérateurs relationnels sont les suivants :

- inférieur strict X < Y - inférieur ou égal X <= Y - supérieur strict X > Y - supérieur ou égal X >= Y - égalité X == Y - inégalité X != Y

Brigitte Groléas 23

Page 24: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Opérateurs Logiques.Les opérateurs logiques sont les suivants:

- Complément logique !X - ET logique X && Y - OU logique X || Y

Complément Logique.Si l'expression « X » est vraie, alors l'expression « !X » est fausse et inversement. exemple : ces expressions sont équivalentes.

!( X == Y ) <===> X != Y !( X || Y ) <===> !X && !Y

ET Logique.Le résultat de l'expression « X && Y » est vrai seulement si les 2 expressions « X » et « Y » sont vraies toutes les deux. L'expression « X » est évaluée en premier. Si l'expression « X » s’avère fausse, il y a rupture de l’évaluation, le résultat de l'expression « X && Y » est faux, mais l'expression « Y » n'est pas évaluée.

OU Logique.Le résultat de l'expression « X || Y » est vrai si l'une au moins des 2 expressions « X » ou « Y » est vraie. L'expression « X » est évaluée en premier. Si l'expression « X » s’avère vraie, il y a rupture de l’évaluation, le résultat de l'expression « X || Y » est vrai, mais l'expression « Y » n'est pas évaluée. Par exemple, dans l'expression :

a > b || a < f(a)

Si l'expression a > b est vraie, la fonction f() ne sera jamais appelée.

7. Opérateur Conditionnel.C'est le seul opérateur ternaire en Java. Il s'exprime sous la forme:

Brigitte Groléas 24

Page 25: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

<condition> ? <expression1> : <expression2>

Si la condition est vraie, l'expression rend le résultat de l’évaluation de « <expression1> » , sinon elle rend le résultat de l’évaluation de « <expression2> ». Exemple : pour faire

if( a < b ) a = a + b; else a = a - b;

On peut écrire : a = ( a < b ) ? a + b : a - b;

ou encore : a += ( a < b ) ? b : -b;

8. Conversion de Type.En général, Java tente de prendre les dispositions nécessaires pour rendre compatible les expressions au niveau des types. Il effectue des conversions de types implicites afin d’évaluer au mieux l'expression proposée. Cependant, dans certains cas, il peut être nécessaire de forcer la décision du compilateur. La forme d'une conversion de type (cast en anglais, moulage en français !) est :

(type)expression

« type » représente le nouveau type dans lequel l'expression sera convertie. Il doit être indiqué entre parenthèses. La conversion de type sera également utilisée pour forcer un type cohérent lors d'un passage de paramètre à une fonction.

9. Opérateur de Concaténation.L’opérateur « , » permet de concaténer deux ou plusieurs expressions pour ne faire qu'une seule expression. Les expressions sont évaluées successivement de la gauche vers la droite et le résultat est la valeur de la dernière expression évaluée. Exemple, dans l’expression :

Brigitte Groléas 25

Page 26: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

X = ( a = 4, f(x), 3 + a );

X vaut 7.

10. instanceof

L’opérateur « instanceof » retourne vrai si l’objet est une instance de la classe.

Brigitte Groléas 26

Page 27: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Structures de contrôle.

1. Les Sélections: if/else switch/case.

L'instruction if.L'instruction « if » permet l’exécution conditionnelle d'une instruction ou d'un bloc d'instructions. Elle s'exprime de la façon suivante:

if( condition ) { instructions à exécuter si la condition est vraie (i.e. différente de zéro) }

Lorsqu'il n'y a qu'une instruction à exécuter, l'ouverture d'un bloc n'est pas nécessaire. Exemple :

if( a == 0 ) { a++; }

Est équivalent à : if( a == 0 ) a++;

En revanche : if( a == 0 ) a++; b++;

Est mal indenté et correspond en fait à : if( a == 0 ) { a++; } b++;

Brigitte Groléas 27

Page 28: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

La Clause else.L’instruction « if » peut comporter une clause « else » pour provoquer l’exécution d'une autre instruction ou d'un autre bloc d'instructions lorsque la condition est fausse. La clause « else » s'exprime derrière l'instruction « if »:

if( condition ) { instructions à faire si vrai } else { instructions à faire si faux }

De la même façon, s'il n'y a qu'une instruction dans la clause « else » , on peut omettre l'ouverture du bloc. Lorsqu'il y a deux « if » emboîtés, la clause « else » se rapporte au dernier « if » ouvert, à moins que l'imbrication des blocs ne force un autre regroupement. Exemple l'instruction :

if( a > 0 ) if( b > 0 ) a = a + b; else a = a - b; else a = -a;

est correct (le premier « if » ne contient qu'une seule instruction qui est le deuxième « if » possédant une clause « else »), et est correctement indenté (le premier « else » se rapporte au dernier « if » rencontre). Si l'on veut supprimer la partie « else a=a-b; », il faut regrouper comme suit :

if( a > 0 ) { if( b > 0 ) a = a + b; } else a = -a;

Le cas « else if ».Cela correspond à la situation suivante :

Brigitte Groléas 28

Page 29: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Si on est dans le 1er cas choses à faire dans le premier cas FINI sinon Si on est dans le 2-ème cas choses à faire dans le deuxième cas FINI sinon Si on est dans le 3-ème cas choses à faire dans le troisième cas FINI sinon (on n'est dans aucun des cas sus-cités) choses à faire sinon FINI fin du sinon_si

Cela s'exprime de la façon suivante : if( condition_1 ) { bloc d'instructions no 1 } else if( condition_2 ) { bloc d'instructions no 2 } ... else { bloc final }

Exemple : Mettre une variable « tranche » indiquant la tranche d'age aux valeurs suivantes :

- tranche = 1 si l'age est inférieur ou égal à 20 ans- tranche = 2 si l'age est compris entre 21 et 30 ans- tranche = 3 si l'age est compris entre 31 et 50 ans- tranche = 4 si l'age est supérieur ou égal à 51 ans

Se traduit par : if( age <= 20 ) tranche = 1; else if( age <= 30 ) tranche = 2; else if( age <= 50 ) tranche = 3; else tranche = 4;

L'instruction switch.Le « switch » est une instruction permettant des aiguillages multiples.

Brigitte Groléas 29

Page 30: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Elle permet de tester si une expression prend une valeur parmi un ensemble de valeurs constantes et effectue les branchements en conséquence. Elle utilise le mot réserve « case » qui sert à localiser les branchements pour chacun des cas dans la suite d'instructions du bloc du « switch ». Elle peut comporter un cas optionnel nommé « default » qui permet de prévoir une action si la valeur ne correspond à aucun des cas (« case ») présents dans le « switch ». La syntaxe est la suivante :

switch( expression ) { case constante_1: instruction_1.1 instruction_1.2 ... case constante_2: instruction_2.1 instruction_2.2 ... case constante_n: instruction_n.1 ... default: instruction_n+1.1 }

L’évaluation d'un switch est la suivante:

(1) Evaluer l'expression entre les parenthèses du « switch » (2) Comparer la valeur de l'expression à la constante_1. S'il y a égalité se brancher

au niveau de l'instruction_1.1 et exécuter en séquence toutes les instructions qui suivent.

(3) Sinon, comparer la valeur de l'expression à la constante_2. S'il y a égalité se brancher au niveau de l'instruction_2.1 et exécuter en séquence toutes les instructions qui suivent.

(4) Sinon, continuer de même pour tous les cas du « switch » (5) Sinon, la valeur ne correspond à aucun des cas cités, se brancher au niveau de

l'instruction_n+1.1 et exécuter en séquence toutes les instructions qui suivent. Il est important de noter qu'à partir du moment ou un branchement est effectué, TOUTES les instructions qui suivent sont exécutées.

Brigitte Groléas 30

Page 31: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple: switch( c ) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': System.out.println( "voyelle\n" ); default: System.out.println( "consonne\n" ); }

Affichera à l’écran si la variable « c » est une consonne :

consonne

Mais affichera à l’écran, si la variable « c » est une voyelle :

voyelle consonne

Pour éviter qu'un cas ne « déborde » sur les autres, on peut utiliser l'instruction « break » qui a pour effet de faire sortir du « switch ». Exemple:

switch( c ) { case 'a': case 'e': case 'i': case 'o': case 'u': case 'y': System.out.println( "voyelle\n" );

break; default: System.out.println( "consonne\n" ); }

Brigitte Groléas 31

Page 32: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Les Itérations: while do/while for.

L'instruction while.L'instruction « while » permet de répéter l’exécution d'une instruction ou d'un bloc d'instructions tant qu'une condition est vraie. Elle s'exprime de la façon suivante :

while( condition ) { instructions à exécuter tant que la condition est vraie (i.e. différente de zéro) }

Lorsqu'il n'y a qu'une instruction à exécuter, l'ouverture d'un bloc n'est pas nécessaire. Le test de continuation de l'instruction « while » est en-tête du bloc, par conséquent si la condition est fausse d’entrée de jeu, la boucle n'est pas effectuée. Exemple:

while( a % 2 == 0 ) a = a / 2;

Si « a » est impair dès le départ, on n'entre pas dans le « while » et « a » n'est pas divisé par deux. Un « while » peut ne contenir aucune instruction exécutable (i.e. le corps de la boucle est vide), dans ce cas il doit quand même se terminer par un point-virgule « ; ».

L'instruction do/while.L'instruction « do/while » s'exprime en deux parties :

do { instructions } while( condition );

Il est syntaxiquement important de ne pas oublier le point-virgule après le « while » final. C'est la présence du point-virgule qui permet de différencier un « while » d'un « do\while ». Lorsqu'il n'y a qu'une instruction à exécuter, l'ouverture d'un bloc n'est pas nécessaire. Le test de continuation de l'instruction « do/while » est à la fin du bloc, par conséquent si la condition est fausse d’entrée de jeux, la boucle est quand même effectuée une fois. Exemple:

Brigitte Groléas 32

Page 33: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

do { a = a * 3; } while( a % 2 != 0 );

Si « a » est pair dès le départ, il est quand même multiplie par 3.

L'instruction for.La boucle « for » est une instruction comprenant obligatoirement trois parties séparées par des point virgules « ; ».

for( [intialisation] ; [condition] ; [incrementation] ) { instructions }

(1) La partie « initialisation » est exécutée avant d'entrer dans la boucle. C'est une expression contenant généralement l'initialisation de la variable de boucle.

(2) La partie « condition » est évaluée à chaque tour de boucle. C'est une expression qui contient le test de continuation de boucle. Si l’évaluation de cette expression donne VRAI, le boucle est exécutée une fois de plus.

(3) La partie « incrementation » est exécutée après l’exécution des instructions du bloc « for » et avant de « remonter » au test de la partie « condition ».

Certaines de ces parties peuvent être vides, mais les points virgules sont toujours nécessaires. Il est possible de concaténer plusieurs expressions dans n'importe lequel des trois champs d'un « for » grâce à l’opérateur « , ». A l’instar du « while », le corps de la boucle « for » peut être vide. Dans ce cas, le « for » doit quand même se terminer par un point virgule. La boucle « for » peut être exprimée sous la forme d'une boucle « while » de la façon suivante :

initialisation while( condition ) { instructions incrementation }

Brigitte Groléas 33

Page 34: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Les ruptures : continue break.En Java, deux instructions permettent de modifier le déroulement d'une boucle « while », « do/while », ou « for »:

L'instruction CONTINUE: Cette instruction permet de « remonter » à la partie « condition » dans la boucle courante. Elle empêche donc l’exécution des instructions qui la suivent. Elle sera généralement utilisée conjointement avec une instruction « if » ou « switch » imbrique dans la boucle.

L'instruction BREAK Cette instruction permet de sortir d'une boucle (ou d'un « switch ») avant la fin de la boucle (ou du « switch ») courante. Elle permettra de stopper l’exécution de la boucle dans un cas particulier. Elle sera généralement utilisée conjointement à une instruction « if » imbriquée dans la boucle.

returnPermet de sortir d’une méthode pour retourner à la méthode appelante.

Brigitte Groléas 34

Page 35: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Classes et Objets

1. Notion de classes

Qu’est ce qu’un objet ?La programmation orientée objet est une technique qui vise à calquer la manière intuitive dont nous percevons et conceptualisons le monde réel qui nous entoure.La complexité de ce monde réel nous conduit rapidement à définir, classifier, organiser et hiérarchiser les différents objets qui le compose. Cela nous permet de synthétiser nos connaissances à différents niveaux d'abstraction afin de dégager des modèles conceptuels et des schémas de fonctionnement pour chaque objet de notre univers.Un objet est donc une entité de notre environnement avec lequel nous sommes amenés à interagir. Cela peut être, par exemple, un atome, une cellule, un neurone, un poil de barbe, une voiture, un immeuble, un animal, une tortue, une fourmi. Chacun des objets de cette liste (au demeurant fort hétéroclite), possède un certain nombre de caractéristiques et de propriétés qui décrivent la composition et les fonctionnalités de l'objet.Tous les objets de même nature peuvent être qualifiés par un même ensemble de caractéristiques et de propriétés. La définition des caractéristiques et des propriétés d'une même catégorie d'objets s'appelle une Classe. Un Objet particulier d'une Classe s'appelle une Instance de cette Classe.Prenons en exemple une application non triviale : le cas d'un système d'exploitation. Il devra gérer différentes entités, différentes Classes d'objets telles que des Processus, des Fichiers, des Périphériques, des Utilisateurs, etc...Chacune de ces classes, possède des caractéristiques (aspect static, faits, description des objets) et des propriétés (aspect dynamique, règles, méthodes d'action).En résumé :

Objet = entité de l'environnement d'une application. = élément particulier d'une classe. = instance (occurrence) d'une classe.

Classe = un genre, une catégorie d'entités semblables. = une famille d'objets de même format. = caractéristiques + propriétés = description + savoir faire = format des données + méthodes d'actions = est comme-ci et comme-ca + sait faire ceci et cela.

Brigitte Groléas 35

Page 36: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Avantage de cette démarche.L'idée fondamentale de la conception orientée Objet est vieille comme le monde (le monde informatique, bien entendu !). Elle est inhérente à la nécessité de décomposer une application volumineuse en différentes entités distinctes (ou concepts, classes, modules).Cette technicité permet de cacher les détails d'implémentation d'un concept particulier (= objet, module) et de se focaliser sur les propriétés de ce concept du point de vue de l'extérieur (l'interface).

Du point de vue interne, le concept (l'objet) est décrit formellement (en détail) tant au niveau de sa constitution (choix de représentation interne) que de ses méthodes d'action (algorithme permettant de manipuler l'objet).

Du point de vue externe, le concept (l'objet) forme un tout indissociable. C'est une 'boite Noire' inaccessible, dont les détails d'implémentation nous sont cachés et qui interagit avec l'extérieur via une certaine Interface.

Cette approche permet de séparer la représentation d'une Abstraction de son utilisation. En voici les principaux avantages :

Enrichissement des possibilités du langage par la définition de nouveaux objets définis par l'utilisateur et indistingables de ceux traités nativement par le langage (ouverture).

Création facile de nombreux objets par simple application du format défini par la classe (instanciation).

Structuration modulaire de l'application grâce aux différents concepts dégagés (analyse).

Réutilisation des objets dans différents applicatifs (constitution de librairies d'objets généraux).

Autonomie des objets dans les choix d'implémentation interne, interchangeabilité des choix d'implémentation sous réserve de préserver l'interface (optimisation, portage).

Responsabilité de l'objet dans les actes commis sur lui-même (maintenance, debuggage).

Fabrication de nouveau type d'objets par dérivation d'objet de base. Constitution d'objets de plus en plus complexe par extension d'objets déjà définis (héritage).

Brigitte Groléas 36

Page 37: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Moyens mis en Œuvre.La conception orientée objet, est un style de programmation permettant de concevoir et maintenir des applications de plus en plus larges et complexes.Le programmeur peut se définir un environnement hiérarchisé, modulaire et facilement extensible en regroupant ensemble des entités (connaissances + fonctionnalités) liées à un même concept.Les langages orientés objets permettent de supprimer la distinction habituelle entre les données (définissant un objet) et les procédures appliquées à cet objet (méthode).Ils permettent d'encapsuler les objets et leur savoir faire au sein d'une même structure syntaxique (la Classe) et d'atteindre ainsi un pouvoir d'expression et un niveau d'abstraction élevé.Ils sont particulièrement adaptés dans des domaines aussi variés que la simulation ou le prototypage, le développement d'applications lourdes ou complexes, l'élaboration d'outils dans un atelier logiciel, la définition d'objets formels, le développement d'interfaces utilisateurs ouvertes, la représentation des connaissances en Intelligence Artificielle, etc...

Les langages orientés objets implémentent trois principes fondamentaux :

L'encapsulation: Créer des Objets pour déléguer et Protéger.C'est la possibilité de regrouper dans une même structure syntaxique (la classe), le format des données qui définissent l'objet et les fonctions destinées à manipuler ces données. C'est également la possibilité de cacher l'intérieur de l'objet vis à vis de l'extérieur et de ne laisser visible que l'interface d'accès. Cela permet de protéger l'objet des interactions avec l'extérieur.

L'héritage: Dériver pour Organiser et Hiérarchiser ses Concepts.Il permet de construire de nouvelles classes (classes filles) dérivant d'une classe existante (classe mère). La classe dérivée (fille) hérite automatiquement des données et du savoir faire de la classe mère. Elle peut, bien sûr, ajouter de nouvelles données et de nouvelles fonctionnalités qui lui sont propres. Un ensemble de classes obtenues par des dérivations successives forme une hiérarchie de classes.

Le Polymorphisme: Unifier. Un même point de vue sur différentes choses.Plusieurs objets de nature différente peuvent avoir des fonctionnalités similaires (bien qu'implémentées différemment au sein de chaque objet). Le polymorphisme (i.e. qui possède plusieurs formes), permet de donner un même nom à chacune de ces actions. La bonne action sera sélectionnée contextuellement en fonction de la classe d'objets à laquelle elle s'applique.

Brigitte Groléas 37

Page 38: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Les classes en Java.Un programme Java est exclusivement constitué de classes. Il n’y a pas de notion de fonctions globales, ni de variables globales comme en C++.

Définition de classe

class Date {int jour;int mois;int année;

public void init( int j, int m, int a ) {jour = j;mois = m;année = a;

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

Cette classe Date contient 3 composantes données (données membres ou variables d’instance) et 2 composantes fonctions (fonctions membres ou méthodes d’instance). Le nom de la classe (i.e. Date) représente le type de l’objet que vient de définir l’utilisateur.

Instanciation d’objetsPour créer un objet de type Date (instancier un objet Date), il faut procéder en deux temps ;

Déclarer une variable référence de type Date. Cette variable se comporte comme un pointeur en langage C3. En effet, la variable référence est capable de référencer n’importe quelle date, mais pour l’instant, elle ne réfère encore aucun objet de type Date. Sa valeur est null (qui correspond au pointeur NULL du C).

Créer un Objet de type Date grâce à l’opérateur new, et affecter l’objet ainsi alloué dynamiquement à la variable référence pour qu’elle pointe sur ce nouvel objet de type Date.

3 Les variables références de Java ne se comportent pas du tout comme les références du C++. En C++, une référence est « collée » à un objet lors de sa création et ne peut plus s’en décoller jusqu'à sa mort. En java, la variable référence est créée indépendamment de l’objet qu’elle servira à référencer ultérieurement et peut changer d’objet référencé au cours du déroulement du programme. Une variable référence Java est donc un espèce de pointeur et rien d’autre !

Brigitte Groléas 38

Page 39: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Date d; // définition d’une variable référence Dated = new Date(); // instanciation d’un objet Date

// et affectation à la référence « d »

Bien entendu, ces deux opérations étant très complémentaires, il est possible de les combiner dans une même expression (en effectuant une affectation en passant au moment de la déclaration de la référence).

Date d = new Date();

Accès aux composantesL’accès aux composantes de l’objet est réalisé par l’opérateur « . », que ce soit pour les composantes données, ou pour les composantes fonctions.

public class Programme {public static void main( String argv[] ) {

Date d1 = new Date();Date d2 = new Date();

d1.jour = 10;d1.mois = 12;d1.année = 1998;

d2.init( 31, 12, 1999 );d1.affiche(); // affiche : « 10/12/1998 »d2.affiche(); // affiche : « 31/12/1999 »

}}

L’expression « d1.affiche() » à pour effet de lancer la fonction « affiche() » de la date « d1 », tout comme l’expression « d1.jour » s’adresse au champ « jour » de la date « d1 ». Les composantes fonctions font partie de l’objet au même titre que les composantes données. On parle alors de méthodes d’instance et de variables d’instance pour indiquer que ces composantes appartiennent à l’objet (instance).Ces méthodes d’instance ne peuvent être invoquées qu’ au travers d’un objet receveur du type adéquat. Ainsi l’extrait de code suivant, défini deux dates, les initialise, et les affiche.

class programme {public static void main( String argv[] ) {

Date d1 = new Date();Date d2 = new Date();

Brigitte Groléas 39

Page 40: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

d1.init( 10, 12, 1998 );d2.init( 31, 12, 1999 );d1.affiche();d2.affiche();

}}

Espace de nommage et polymorphisme.Les fonctions membre « affiche() » et « init() » sont locales à la classe Date. Leur portée est limitée à la classe. D’autres fonctions « affiche() » peuvent être définies dans d’autres classes sans qu’il y ait de conflit dans l’espace de nommage. Cette possibilité de multiple définitions de fonctions homonymes dans des contextes différents s’appelle le polymorphisme.Les fonctions membres d’instance sont forcément invoquées au travers d’un objet. On dit que la fonction (méthode) est appliquée à un objet particulier (un contexte particulier). Cet objet est, en quelque sorte, en position de receveur et reçoit le message (l’ordre) fonctionnel. L’expression « d1.affiche() » doit être comprise comme « d1 affiche toi ». C’est une transmission par « passage de messages ». Le langage Java sélectionne la méthode (la fonction) et l’applique dans le contexte de l’objet receveur du message.

Brigitte Groléas 40

Page 41: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Notion d’instance.L’expression « Date d1 = new Date(); » défini (instancie) un objet date référencé par « d1 » qui contient 3 composantes données et 2 composantes fonctionnelles. Après initialisation, les objets « d1 » et « d2 » peuvent être représentés en mémoire de la manière suivante :

Contexte d1 :d1 composante données (variables d’instances)   :

jour = 10 mois = 12 année = 1998

d1 composantes fonctions (méthodes d’instances)   :

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}

public void affiche() {System.out.println( jour + "/" + mois + "/" + année );

}

Contexte d2 :d2 composante données (variables d’instances)   :

jour = 31 mois = 12 année = 1999

d2 composantes fonctions (méthodes d’instances)   :

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}

public void affiche() {System.out.println( jour + "/" + mois + "/" + année );

}

Ainsi, d’un certain point de vue, chaque objet possède sa propre fonction d’affichage (c’est pour cette raison que l’on parle de méthodes d’instance !). La fonction d’affichage appliquée dans le contexte de « d1 », évaluera le jour, le mois et l’année de l’objet référencé par « d1 » et affichera « 10/10/1998 », tandis que cette même fonction appliquée dans le contexte de « d2 », évaluera le jour, le mois et l’année de l’objet référencé par « d2 » et affichera « 31/12/1999 ». Bien entendu, pour des raisons d’optimisation de place, le code de ces fonctions est, en réalité, partagé par les différents objets issus d’une même classe.

Brigitte Groléas 41

Page 42: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

En fait, l’objet receveur est « passé » à la fonction de façon cachée et implicite.

L’objet courant : Mot clef « this ».L’objet receveur d’une fonction membre est consultable grâce au mot clef this qui est une référence sur l’objet receveur.

class Date {int jour, mois, année;public void foobar() {

this.jour = 0; // Ces 2 lignes sontjour = 0; // equivalentes

}}

La référence this peut, par exemple, être utilisée pour accéder aux composantes données dans une fonction membre lorsque les noms de ces composantes sont masqués par des variables locales homonymes dans la fonction.

class Date {int jour, mois, année;public void init( int jour, int mois, int année ) {

this.jour = jour; // champ jour = paramètre jourthis.mois = mois;this.année = année;

}}

Brigitte Groléas 42

Page 43: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

3. Protection : Classes et Encapsulation.En Java, il existe des spécificateurs d’accès qui permettent de préciser l’accessibilité de chaque composante.

class Date {private int jour;private int mois;private int année;public void init( int j, int m, int a ) {

jour = j; mois = m; année = a;}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

L’attribut private permet de déclarer des composantes privées à la classe. Ces composantes privées (jour, mois, année) ne pourront être utilisées que par les fonctions membres de la classe Date (toutes autres fonctions situées à l’extérieur de la classe Date n’aura pas accès à ces composantes. Cela permet de « cacher » les composantes privées au monde extérieur. La classe peut être vue comme une espèce de « Club privé » : Les composantes privées sont des membres secrets du club ; seul les membres appartenant au club peuvent les voir et y ont accès. En revanche, les composantes publiques sont ouvertes vers l’extérieur et peuvent être accédées par n’importe qui. Elles sont les « portes d’accès » au Club privé. Evidemment, au moins une des composantes d’une classe doit ne pas être privée Si toutes les composantes étaient privées, la classe serait refermée sur elle-même, donc totalement inaccessible, ce qui ne présente pas un grand intérêt !

class Programme {public static void main( String argv[] ) {

Date d1 = new Date();

d1.jour = 15; // INTERDIT : jour est privated1.init( 10, 12, 1998 );// PERMIS : init est public

}}

Brigitte Groléas 43

Page 44: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Private ou Public ?En général, les composantes données seront déclarées privées afin de protéger le contenu de l’objet du monde extérieur et les composantes fonctions seront déclarées publiques pour permettre un accès contrôlé à l’objet. Les fonctions membres publiques joueront donc un rôle d’interface, en permettant un accès sous leur contrôle et leur responsabilité aux différents autres composantes privées de la classe. Elles peuvent être vues comme des sentinelles qui contrôlent et filtrent l’accès au Club privé. Ce sont, en fait, les primitives d’accès à l’objet (points d’entrées), la partie visible de l’objet vis à vis de l’extérieur.

Modificateurs d’accèsJava dispose de 4 modificateurs d’accès pour préciser le degré de protection des composantes situées dans un objet :

private   : c’est la protection la plus restrictive. Seules les fonctions situées dans la classe peuvent accéder aux composantes déclarées privées.

Aucun   : Par défaut, lorsque l’on n’emploie aucun spécificateur d’accès, la composante est accessible par les fonctions situées dans la classe, ainsi que par les fonctions des autres classes si elles sont situées dans le même package.

protected   : La composante est, bien sûr, accessible par les fonctions de la classe et par les fonctions des autres classes situées dans le même package, mais aussi par les fonctions des classes dérivées même lorsqu’elles sont situées dans d’autres packages. (Nous y reviendrons dans le chapitre concernant l’héritage et la dérivation.

public   : La composante est accessible par toutes les fonctions sans aucune restriction.

Brigitte Groléas 44

Page 45: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

4. Cacher ou ne pas Cacher ?

Intérêt des composantes privées.L’intérêt de protéger les différentes composantes de données d’une classe est clairement évident : tout accès à l’une de ces composantes privées ne peut s’effectuer qu’au travers d’une fonction membre de la classe. La classe dispose donc d’une certaine autonomie, d’une certaine responsabilité sur les agissements effectués sur ses composantes internes. En effet, si l’une des composantes privées d’une classe recouvre, tout à coup, une valeur aberrante, la responsabilité incombe forcément à l’une des fonctions membres de cette même classe (toutes les modifications de données privées d’un objet sont sous le contrôle exclusif et absolu des fonctions de l’objet lui-même). Cette démarche induit une plus grande sécurité, une plus grande robustesse des applications et facilite énormément la maintenance et le debugage.

Notion d’interface fonctionnelle.La partie publique de l’objet est, en quelque sorte, la partie visible de l’iceberg et la partie privée est cachée à l’utilisateur de la classe qui n’a plus à se soucier des détails et choix d’implémentation interne de l’objet. Vu de l’extérieur, l’objet s’utilise via son interface fonctionnelle qui pratiquement est réalisée grâce aux fonctions membre publiques de l’objet.

d1 PARTIE Cachée (Opaque)   :

jour = 10 mois = 12 année = 1998

d1 PARTIE visible (Interface)   :

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}

public void affiche() {System.out.println( jour + "/" + mois + "/" + année );

}

Brigitte Groléas 45

Page 46: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Toutefois, le revers de la médaille est le suivant : la partie privée de l’objet étant inaccessible de l’extérieur, tout besoin d’accès à une privée de l’objet doit forcement s’effectuer au travers de l’interface fonctionnelle (c’est justement ce que l’on veut !!). Dans certaines situations, cela va conduire le programmeur de la classe à créer une multitude de fonctions minuscules (ce qui peut apparaître aberrant d’un point de vue optimisation du code).Ainsi, si l’on veut extraire le jour, le mois ou l’année d’une date, ces opérations devront passer par des fonctions de l’interface dont l’objectif sera simplement de retourner la valeur du champ considéré.

class Date {private int jour, mois, année;

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}public int getJour() { return jour; }public int getMois() { return mois; }public int getAnnée() { return année; }

}

Développement en ligne : méthodes finales, privates ou statiquesPour des raisons d’efficacité, le programmeur Java pourrait être tenté de laisser les composantes jour, mois et année en accès publique. Il perdrait alors tout le bénéfice de l’encapsulation des classes !Il existe une autre solution. En Java, le modificateur final appliqué à une fonction membre permet d’indiquer au compilateur que cette fonction ne peut pas être redéfinie par une sous-classe dérivée désireuse de changer son comportement. La méthode est, en quelque sorte, « algorithmiquement constante ». Il s’agit de la version finale de cette méthode. Dès lors, le compilateur Java est capable d’optimisations automatiques. Plutôt que d’attendre le runtime pour déterminer le type réel de l’objet sur lequel s’applique la fonction afin d’être capable de choisir la bonne implémentation de cette méthode (qui peut être redéfinie dans différentes classes dérivées), il peut, dès la compilation, choisir cette implémentation (puisqu’elle est finale, la fonction ne risque pas d’être redéfinie ultérieurement !). Dans le cas de fonctions suffisamment simples (courtes), le compilateur remplacera l’invocation de la fonction directement par le corps de la fonction. Ce mécanisme est

Brigitte Groléas 46

Page 47: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

connu sous le nom de « développement en ligne »4. Toutes les fonctions membres finales sont candidates au développement en ligne.

class Date {private int jour, mois, année;

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}public final int getJour() { return jour; }public final int getMois() { return mois; }public final int getAnnée() { return année; }

}

Les méthodes statiques (méthodes de classes) et les méthodes privées ne peuvent pas être redéfinies dans des classes dérivées. Elles sont, par conséquent également candidates au développement en ligne.Si le développement en ligne est utilisé par le compilateur, les deux instructions suivantes sont équivalentes :

int i;

i = d1.getJour(); // génétation du code en lignei = d1.jour; // qui correspond en fait à cela.

Bien que les deux instructions soient équivalentes, l’emploi de la méthode « getJour() » est bien préférable car il ne permet l’accès au champ « jour » qu’en lecture seule, et conserve le bénéfice de l’abstraction des données laissant le choix au programmeur de la classe de changer la représentation interne des objets de type Date le cas échéant.

4 La même notion existe en C++ et est explicitement obtenue par l’utilisation de la directive « inline ».

Brigitte Groléas 47

Page 48: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Classes finalesIl est possible de d’appliquer l’attribut final à une classe entière. Une classe finale ne peut plus être dérivée, toutes ses méthodes sont donc implicitement finales. Certains contrôles de type sont plus rapides si on utilise des classes finales car ils peuvent être effectués au moment de la compilation. Si le compilateur Java a une référence sur une classe finale, il sait que l’objet référencé est exactement de ce type et comme toute la hiérarchie de cette classe est connue, le compilateur peut savoir sans ambiguïté si tel ou tel type d’utilisation est valide ou pas. Dans le cas d’une classe non finale, certains contrôles ne peuvent être effectués qu’à l’exécution.

final class Date {// ...

}

Une classe ou une méthode finale impose de sérieuses restrictions sur l’utilisation de la classe. Pour déclarer une méthode finale, il faut être sur de vouloir figer son implémentation, ce qui restreint la flexibilité de la classe vis à vis des programmeurs qui voudraient utiliser cette classe pour des dérivations. Une classe finale ne peut plus être étendue par qui que ce soit, ce qui peut limiter son utilité. Lorsque l’on déclare quelque chose de final, il faut être sûr de vouloir imposer ces restrictions.

Brigitte Groléas 48

Page 49: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

5. Initialisations et Constructeurs.

Valeurs par défaut implicite.L’initialisation des composantes données d’un objet nouvellement créé ne doit pas être laissée au hasard. Si le programmeur ne prévoit rien, Java initialise chaque composante à une valeur par défaut qui dépend de son type. C’est la valeur 0 ou 0.0 pour les types primitifs numériques (byte, short, int, long, float, double), la valeur false pour le type primitif « boolean », la valeur \u0000 pour le type primitif « char » et la valeur null pour les « références ».

class Programme {public static void main( String argv[] ) {

Date d1 = new Date();

d1.affiche(); // AFFICHE : 0/0/0}

}

Valeurs par défaut explicites.Il est possible de prévoir des valeurs par défaut dans les composantes données d’une classe, qui seront attribuées automatiquement à chaque objet nouvellement créé5.

class Date {private int jour = 1, mois = 1, année = 1900;

public void init( int j, int m, int a ) {jour = j; mois = m; année = a;

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

Notion de constructeursPuisque nous avons vu que les données membres d’une classe ont tout intérêt à être privées, l’initialisation d’un objet à des valeurs particulières oblige à passer par 5 En C++, l’attribution de valeur par défaut aux composantes données d’une classe n’est pas permise  ; il faut utiliser les valeurs par défaut des fonctions appliquées au cas des fonctions constructeurs.

Brigitte Groléas 49

Page 50: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

l’interface fonctionnelle. C’est précisément le rôle de la fonction publique « init() » de notre classe Date. Ainsi, pour initialiser une date, il suffit d’invoquer cette fonction, qui par ailleurs, pourrait prendre en charge des vérifications de cohérence (par exemple refuser l ‘initialisation d’une date erronée).L’initialisation d’un objet lors de sa création étant une procédure souvent indispensable pour qu’un objet soit « viable », Java propose un mécanisme générique et systématique d’initialisation qui permet au concepteur d’une classe de se poser ce problème une bonne fois pour toutes. Cette méthode d’initialisation banalisée est réalisée par une fonction membre spécifique nommée le « constructeur ».

Déclaration des constructeurs.La déclaration d’un constructeur se fait de la même manière que n’importe quelle autre fonction membre, hormis le fait que les constructeurs n’ont pas de type (i.e. il ne faut pas déclarer de type retourné, même pas « void » !). Par définition, le nom de la fonction membre constructeur doit être le même que celui de sa classe.

class Date {private int jour = 1, mois = 1, année = 1900;

public Date( int j, int m, int a ) {jour = j; mois = m; année = a;

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

Brigitte Groléas 50

Page 51: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Invocation implicite des constructeurs.Le constructeur est appelé automatiquement et systématiquement dès qu’il y a instanciation d’un nouvel objet. Le code du constructeur est exécuté après les initialisations par défaut Comme toutes fonctions membres, ils peuvent avoir zéro ou plusieurs arguments. Les paramètres, si il y en a, sont renseignés entre parenthèses juste après le nom du type lorsque l’objet est créé avec new.

class Programme {public static void main( String argv[] ) {

Date d1 = new Date( 10, 12, 1999 );

d1.affiche(); // AFFICHE : 10/12/1999}

}

Constructeur par défaut.Par défaut, toute classe possède un constructeur vide sans argument qui ne fait rien. Ce constructeur n’est implicitement défini par le langage que si aucun constructeur n’est défini explicitement par le programmeur. Ainsi, dans l’exemple qui précède, il n’est plus possible de créer des dates non initialisées. Cela peut permettre au concepteur d’une classe de forcer l’utilisateur à initialiser l’objet lors de sa création6.

class Programme {public static void main( String argv[] ) {

Date d1 = new Date( 10, 12, 1999 ); // OKDate d2 = new Date(); // ERREUR

}}

6 Contrairement à C++, l’absence de constructeur sans argument ne gène pas la création de tableaux d’objets puisqu’en Java la création d’un tableau d’objet ne crée pas les objets contenus dans le tableau mais seulement les références initialisés a null.

Brigitte Groléas 51

Page 52: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Surcharge des constructeurs.Grâce au mécanisme de surcharge des fonctions, il est, bien sûr, possible de définir plusieurs constructeurs dans une même classe dès lors qu’ils sont différentiables par leurs arguments7.

class Date {private int jour, mois, année;

public Date() { // AVEC LA DATE DU JOURjava.util.Date now = new java.util.Date();

jour = now.getDay();mois = now.getMonth();année = now.getYear();

}public Date( int j ) { // MOIS ET ANNEE COURANTE

java.util.Date now = new java.util.Date();

jour = j;mois = now.getMonth();année = now.getYear();

}public Date( int j, int m ) { // ANNEE COURANTE

java.util.Date now = new java.util.Date();

jour = j;mois = m;année = now.getYear();

}public Date( int j, int m, int a ){ // AVEC UN TRIPLET D’INT

jour = j; mois = m; année = a;}public Date( Date d ) { // AVEC UNE AUTRE DATE

jour = d.jour; mois = d.mois; année = d.annee;}public Date( String s ) { // A PARTIR D’UNE CHAINE

int sep1 = s.indexOf( '/' );int sep2 = s.indexOf( '/', sep1+1 );jour = Integer.parseInt( s.substring( 0, sep1 ) );mois = Integer.parseInt( s.substring( sep1+1, sep2) );année = Integer.parseInt( s.substring( sep2+1 ) );

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

7 Contrairement à C++, on peut définir un constructeur recevant en paramètre un objet du même type que sa classe, puisqu’en Java, le passage d’objets en paramètre s’effectue par référence.

Brigitte Groléas 52

Page 53: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Invocation explicite d’un constructeur : this().Il est possible d’invoquer un constructeur depuis un autre constructeur de la même classe en employant le mot-clef this suivi de la liste d’arguments que l’on désire passer au constructeur appelé. Cette utilisation de « this(...) » ne peut apparaître qu’en tant que première instruction du constructeur appelant (cette restriction est liée à l’invocation automatique du constructeur de la super-classe). Cela permet de simplifier le code précédent :

class Date {private int jour, mois, année;

public Date() { // AVEC LA DATE DU JOURjava.util.Date now = new java.util.Date();

jour = now.getDay();mois = now.getMonth();année = now.getYear();

}public Date( int j ) { // MOIS ET ANNEE COURANTE

this(); jour = j;}public Date( int j, int m ) { // ANNEE COURANTE

this(); jour = j; mois = m;}public Date( int j, int m, int a ){ // AVEC UN TRIPLET D’INT

jour = j; mois = m; année = a;}public Date( Date d ) { // AVEC UNE AUTRE DATE

this( d.jour, d.mois, d.annee );}public Date( String s ) { // A PARTIR D’UNE CHAINE

int sep1 = s.indexOf( '/' );int sep2 = s.indexOf( '/', sep1+1 );jour = Integer.parseInt( s.substring( 0, sep1 ) );mois = Integer.parseInt( s.substring( sep1+1, sep2) );année = Integer.parseInt( s.substring( sep2+1 ) );

}public void affiche() {

System.out.println( jour + "/" + mois + "/" + année );}

}

Brigitte Groléas 53

Page 54: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Accessibilité des constructeursLe constructeur est, par défaut, public si la classe est publique et non publique (accès limité au package) si la classe n’est pas publique. On peut, explicitement modifier l’accessibilité d’un constructeur avec les attributs publics, protected ou private8. Un constructeur non public permet de restreindre son utilisation (et la création d’objet par son biais ou la dérivation de la classe à cause du chaînage des appels des constructeurs).

Destructeur implicite : le garbage collector.Le rôle du constructeur est de contribuer à la création correct d’un nouvel objet. Lorsque l’objet doit mourir, il se peut qu’il y ait des tâches particulières à effectuer. C’est le rôle du destructeur. En Java, contrairement à C++, la destruction physique des objets est à la charge du système. Un garbage collector tourne en permanence en tâche de fond (c’est une thread démon) pour récupérer l’espace mémoire des objets qui ne sont plus utilisés. Un objet n’est plus utilisé lorsqu’il n’y a plus aucune référence qui pointe sur lui.

Forcer la récupération d’un objet avant la sortie du scope.Il est possible d’anticiper l’action du garbage collector en supprimant explicitement la référence à un objet avant que la variable référence ne disparaisse d’elle même en sortant du bloc dans lequel elle est déclarée :

void methode() {int tab[] = new int[10000];// code utilsant tabtab = null; // on a plus besoin de tab//.code encore long

}

Destructeur explicite : finalize().Le garbage collector se charge de récupérer les ressources mémoire utilisées par l’objet. Mais si l’objet utilise d’autres types de ressources ( socket réseau, descripteur de fichier, ... ), le programmeur doit les libérer lui-même. C’est la raison d’être de la méthode « finalize() » qui est appelée avant la libération de l’objet.8 Un constructeur privé est, a priori, un peu insensé puisqu’il n’est accessible que par les fonctions membres de la classe sujet. Or une fonction membre ne peut être invoquée qu’au travers d’un objet qui ne peut être créé que par le constructeur qui ... En fait, ce cas peu courant peut être mis à profit pour fabriquer une classe «  singleton » qui n’autorise l’instanciation que d’un seul objet. Le constructeur n’étant pas accessible de l’extérieur, la classe peut en contrôler l’accès et pour créer le 1er objet, on doit utiliser une fonction publique statique (méthode de classe) car elle peut être lancée indépendamment de tout objet.

Brigitte Groléas 54

Page 55: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

class Truc {protected void finalize() {

// action à faire quand l’objet meurtsuper.finalize() ; // appel de finalize de

// la super classe.}

}

Quelques détails sur le fonctionnement de « finalize() » :

La méthode « finalize() » doit toujours invoquer la méthode « finalize() » de la super classe.

La méthode « finalize() » est invoquée avant la disparition effective de l’objet. L’interprète Java peut s’arrêter sans avoir libéré tous les objets. Il n’y a pas

certitude que la méthode « finalize() » soit appelée. Java ne donne aucune garantie sur le moment et l’ordre dans lequel les objets seront

libérés et donc l’ordre dans lequel les méthodes « finalize() »seront appelées. L’objet n’est pas détruit immédiatement après l’invocation de la méthode

« finalize() » car celle-ci peut éventuellement ressusciter l’objet et rétablissant une référence dessus. L’objet ne sera récupéré qu’au prochain passage du garbage collector.

Si la méthode « finalize() » génère une exception, elle est ignorée par le système.

Brigitte Groléas 55

Page 56: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

6. Globales et Constantes : static et final.La notion de fonctions et de variables globales n’existe pas au sens propre en Java. Toutefois, il est possible de définir des variables, des constantes et des fonctions globales encapsulées dans une classe donnée. Cela s’effectue grâce au spécificateur « static ». Une composante statique est une composante définie au niveau d’une classe et partagée par toutes les instances (objets) de cette classe.

Variable statiques : variables de classe.Les variables statiques (ou variables de classe)9 sont des variables globales encapsulées dans une classe. Elle existe avant et indépendamment de la création des instances de cette classe et sont partagées par toutes les instances de cette classe.

class Truc {static int var;

}

L’accès aux variables statiques se fait de façon transparente (simplement par leur nom) depuis les méthodes situées dans la classe de la même manière que l’accès aux autres composantes données. Si la variable de classe est publique, elle peut être accédée depuis l’extérieur de la classe par la syntaxe « NomDeClasse.variable »

class Truc {public static int var = 0;

public int foo() {return var;

}class Programme {

public static void main( String args[] ) {Truc.var++; // var passe à 1

}}

Initialisation des variables statiques.Les variables statiques non explicitement initialisées ont une valeur par défaut qui dépend de leur type (false, u0000, 0, ou null). Les variables statiques peuvent être initialisées lors de leur déclaration. Dans des cas plus complexes, on peut utiliser un 9 appelées aussi variables de classe car elles existent par rapport à la classe, par opposition aux variables d’instance qui existent à l’intérieur de chaque instance.

Brigitte Groléas 56

Page 57: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

bloc d’initialisation static qui sera exécuté une seule fois lors du chargement de la classe.

class Truc {static int var; // valeur par défaut 0static int var2 = 12; // initialisation tstatic private int tab[] = new int[100];static {

// code d’initialisation du tableau tabfor( int i = 0; i < tab.length; ++i ) {

tab[i] = i * 2;}

}}

Méthodes statiques : méthodes de classe.Comme les variables statiques, les méthodes statiques (ou méthode de classe) correspondent à des globales définies au niveau de la classe. L’accès aux méthodes statiques se fait de façon transparente (simplement par leur nom) depuis les méthodes situées dans la classe. Si la méthode de classe est publique, elle peut être accédée depuis l’extérieur de la classe par la syntaxe « NomDeClasse.methode() »

class Truc {public static void foo() {

// code de foo}void bar(){

foo();}

}class Programme {

public static void main( String args[] ) {Truc.foo(); // lance foo()

}}

Brigitte Groléas 57

Page 58: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Une méthode de classe ne peut pas accéder aux composantes d’instance car elle n’a pas de référence this sur l’objet courant.

class Truc {static int var; // variable de classeint var2; // variable d’instancevoid foo() { // méthode d’instance

// code de la méthode foo}static void bar() { // méthode de classe

// code de laméthode barstatic void foobar() {

var++; // OKvar2++ // ERREUR !!!!!foo(); // ERREUR !!!!!bar(); // OKthis // ERREUR !!!!

}

Les méthodes de classe ne sont pas héritées par dérivation, et sont donc candidates à l’optimisation du compilateur par le développement en ligne du code.

Constantes nommées : final et statique.Les variables déclarées avec le modificateur « static final » sont en fait des constantes. L’usage veut que, comme en C, les constantes soit nommées en majuscule. Le compilateur reconnaît les constantes et précalcule les valeurs dans le cas d’expressions constantes calculées.

class Truc {static final int CONST = 15;static final int CONST2 = CONST >> 2; // précalule 7

}

L’accès aux constantes nommées se fait de façon transparente (simplement par leur nom) depuis les méthodes situées dans la classe. Si une constante est publique, elle peut être accédée depuis l’extérieur de la classe par la syntaxe « NomDeClasse.constante »

class Truc {public static final int CONST = 10;

public int foo() {return CONST;

}}class Programme {

public static void main( String args[] ) {int var = Truc.CONST; // var passe à 10

}}

Brigitte Groléas 58

Page 59: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple récapitulatif :Supposons que l’on définisse une classe élément contenant un champ « name » pour qualifier le nom d’un élément et un champ « ident » pour définir une clé unique permettant d’identifier chaque élément de façon univoque. Il pourrait être judicieux de faire calculer automatiquement la valeur de la clé d’identification lors de la création de tout nouvel élément par le constructeur. Il faut évidemment « se souvenir » de la valeur courante de la dernière clé attribuée. Cette information est commune à tous les éléments et va donc être implémentée par une variable statique « nextIdent ». Cela donne :

public class Element {private String name; // nom de l’élémentprivate int ident; // numéro d’identification

// géré automatiquementprivate static int nextIdent = 0; // valeur du prochain // numéro à attribuerpublic static final int FIRST_ID = 0; // constante

Element( String s ) { // constructeurname = s;ident = nextIdent++;

}public String getName() { // méthode d’instance

return name;}public int getIdent() { // méthode d’instance

return ident;}public static int nbre_item() { // méthode de classe

return nextIdent;}

}

Brigitte Groléas 59

Page 60: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

7. Dérivation , héritage

Classe de base, Classe dérivée : Vers l'héritage.Dans la vie courante, il est souvent nécessaire de subdiviser une classe un peu trop générale en plusieurs sous-classes. Par exemple, le genre animal se décompose en mammifères, reptiles, insectes, etc... Les mammifères peuvent se redécomposer en humains, chiens, chats, etc... Les chiens peuvent à leur tour être classés par race, et en définitive le chien « milou » est un animal mammifère chien d'une certaine race.Il arrive souvent d'avoir à prendre en compte ce mécanisme de sous classification dès qu'une classe représente une forme de spécialisation d'une autre classe plus générale. Ainsi, par exemple, les neurones sont des cellules vivantes particulières, les chiens sont des mammifères particuliers, les étudiants sont des individus particuliers etc ... La classe spécialisée est appelée la sous-classe ou classe dérivée, et la classe générale se nomme super classe ou classe de base :Prenons comme exemple la classe Individu ci-dessous :

class Individu {private String nom;private String prenom;private Date naissance;

public Individu( String n, String p, Date d ) {nom = n; prenom = p; naissance = d;

}public void aff_nom(){ // affiche le nom

System.out.println( "nom:" + nom );}public void aff_prenom(){ // affiche le prénom

System.out.println( "prenom:" + prenom );}public void aff_date(){ // affiche la date de naissance

naissance.affiche();}public void affiche(){ // affiche tout l’objet

System.out.println( "nom:" + nom );System.out.println( "prenom:" + prenom );naissance.affiche();

}}

Supposons que nous voulions construire une classe d'objet pour qualifier la population étudiante. Il est naturel de se référer au modèle « Individu » que l'on a déjà défini, un étudiant étant un Individu particulier.

Brigitte Groléas 60

Page 61: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

class Etudiant {private Individu etat_civil;private int numéro; // numéro d'étudiant private int etude; // niveau d’études

Etudiant( String n, String p, date d, int n, int e ) {etat_civil = new Individu( n, p, d ); numero = n;

etude = e;}public void aff_nom() { // affiche le nom

etat_civil.aff_nom();}public void aff_prenom() { // affiche le prénom

etat_civil.aff_prenom();}public void aff_date() { // affiche la date de naissance

etat_civil.aff_date();}public void aff_numero() { // affiche le numéro d'étudiant

System.out.println( "numero:" + numero );}public void aff_etude() { // affiche le niveau d'étude

System.out.println( "niveau:" + etude );}public void affiche() { // affiche tout l’objet

etat_civil.affiche();System.out.println( "numero:" + numero );System.out.println( "niveau:" + etude );

}}

Il est normal d'avoir à définir le constructeur et les nouvelles méthodes propre à la classe étudiant, c'est à dire « etudiant() », « aff_numero() », « aff_etude() » et « affiche() ».Mais il est fastidieux de devoir redéfinir les méthodes concernant l'individu dans la classe « etudiant » (c'est à dire les méthodes « aff_nom() », « aff_prenom() » et « aff_date() » ). D'autant plus que le code de ces trois fonctions se limite à appeler la fonction adéquate de la classe individu au travers du champ « etat_civil ». De plus, ce même procédé devra être répété si nous désirons construire, par exemple, une nouvelle classe Etudiant_etranger basée sur la classe Etudiant.L'idée va être "d'importer" dans une nouvelle classe, les données, mais aussi, le savoir faire d'une autre classe. C'est cette notion d'héritage que nous allons maintenant détailler.

Brigitte Groléas 61

Page 62: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

La dérivation et l'héritage simple.Le langage Java nous offre les moyens syntaxiques de prendre en compte cette méthode de subdivision des classes. C'est la notion de dérivation, et son corollaire l'héritage. Une classe dérivée est une particularisation d'une classe de base. Elle partage avec la classe de base dont elle est issue un grand nombre de caractéristiques et de propriétés. Il est assez naturel de ne pas avoir à redéfinir les différentes caractéristiques et propriétés communes à ces deux classes et faire en sorte que, par défaut, la classe dérivée hérite des caractéristiques et des propriétés de la classe de base. Selon ce principe, la classe « Etudiant » va importer l'ensemble du concept « Individu », données et méthodes. Ainsi, les méthodes « aff_nom() », « aff_prenom() », et « aff_date() » n'auront pas besoin d'être redéfinies puisqu'elles sont déjà définies dans la classe de base qui est importée. Cela donne :

class Etudiant extends Individu {int numero; // numéro d'étudiant int etude; // niveau des études suivies

Etudiant( String n, String p, date d, int num, int etu ) {// code du constructeur

}public void aff_numero() { // affiche le numéro d'étudiant

System.out.println( "numero:" + numero );}public void aff_etude() { // affiche le niveau d'étude

System.out.println( "niveau:" + etude );}public void affiche() { // affiche tout l’objet

// code de affiche}

}

La première ligne « class Etudiant extends Individu » défini la classe Etudiant comme classe dérivée de la classe Individu. Cette notation signifie que l’intégralité de la classe Individu est intégrée directement à l'intérieur de la classe Etudiant. On peut considérer que la classe Etudiant contient toutes les composantes des Individus (qui sont "héritées") en plus de sa partie propre (les nouvelles composantes ajoutées dans la classe Etudiant). Toutefois, les composantes privées de la classe Individu, bien qu’héritées, ne sont pas pour autant accessibles dans la classe Etudiant.

De plus, si certaines composantes (données ou méthodes) font l'objet de redéfinition dans la partie propre de la classe Etudiant, elles masquent les composantes homonymes de l’Individu. Ainsi, comme la classe Etudiant redéfini une méthode propre « affiche() », c'est bien sûr celle-ci qui sera sélectionnée pour afficher un Etudiant. A

Brigitte Groléas 62

Page 63: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

contrario, la méthode « aff_nom() » n'étant pas définie dans la classe dérivée c'est celle de la classe de base qui sera sélectionnée.Détaillons ces mécanismes sur un exemple plus simple, dans lequel tout est publique :

class Base {public int i; // trois données public int j;public int k;public void foo() { ... } // trois méthodes public void bar() { ... }public void foobar() { ... }

}

class Derivee extends Base { // Six composantes importées public int a; // trois données public int b;public int i;public void toto() { ... } // trois méthodes public void titi() { ... }public void foobar() { ... }public void test() {

a = 10; // champ "a" propre à Derivée b = 20; // champ "b" propre à Derivée i = 30; // champ "i" propre à Derivée j = 40; // champ "j" de la classe Base k = 50; // champ "k" de la classe Base toto(); // méthode "toto" propre à Derivée titi(); // méthode "titi" propre à Derivée foobar(); // méthode "foobar" propre à Derivée foo(); // méthode "foo" de la classe Base bar(); // méthode "bar" de la classe Base

} }

Les composantes inaccessibles par masquage, en raison de l'homonymie peuvent être « démasquées » grâce au mot clef « super » qui désigne la super classe .

public void test() {super.i = 30; // champ "i" de la classe de Base super.foobar(); // méthode "foobar" de Base

}

Pour référer la méthode « affiche() » de la classe Individu dans la méthode « affiche() » de la classe Etudiant, il faut procéder comme suit :

class Etudiant extends Individu {int numero; // numéro d'étudiant int etude; // niveau des études suivies

Brigitte Groléas 63

Page 64: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

public void affiche() { // affiche tout l’objetsuper.affiche(); // appel l’affiche() d’IndividuSystem.out.println( "numero:" + numero );System.out.println( "niveau:" + etude );

}}

Le mécanisme engendré par Java est simple. L'accès à une composante à travers un objet de la classe dérivée est tout d'abord recherché dans la partie propre de l'objet. En cas de d'échec, la recherche est poursuivie dans la classe de base et ainsi de suite jusqu'à la classe « Object », mère de toutes les classes.

Constructeurs et DestructeursL'instanciation d'un objet d'une classe dérivée implique la création et l'initialisation des données de la partie "propre" de l'objet, mais également de la partie héritée de la classe de base. Les champs de données de la partie héritée étant la plupart du temps privés, il est impossible d'y accéder depuis la classe dérivée. Il est nécessaire d'appeler le constructeur de la classe de base, qui va assurer l'interface.C’est encore grâce au mot clef « super » que l’on effectue le chaînage des constructeurs. Voyons sur un exemple :

class Etudiant extends Individu {int numero; // numéro d'étudiant int etude; // niveau des études suivies

Etudiant( String n, String p, date d, int num, int etu ) {super( n, p, d ); // appel le constructeur d’Individunumero = num;etude = etu;

}}

Les constructeurs de la classe de base doivent être appelés avant la construction des membres « propres » à la classe dérivée. Ainsi, en cas de dérivations successives, tous les constructeurs des « ancêtres » (desquels la classe dérivée est issue) seront appelés en commençant par la classe la plus "ancestrale" jusqu’à la classe de l'objet construit. L’appel à « super(...) » ne peut apparaître qu’en première instruction. Si l'appel à un constructeur de la classe de base n'est pas explicitement réalisé, c'est le constructeur sans argument qui sera implicitement invoqué. S’il n’existe pas, Java génère une erreur.A la libération de l'objet, les destructeurs doivent être explicitement chaînés. Pour cela, la méthode « finalize() » de la classe dérivée se doit d’appeler explicitement la méthode « finalize() » de la super classe par la syntaxe « super.finalize() ».

Brigitte Groléas 64

Page 65: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Dériver ou ne pas dériver : voilà la question.La notion de dérivation intervient dès que la sous-classe peut être considérée comme un cas particulier de la classe générale. Ainsi, par exemple, les chiens sont des cas particuliers de mammifère, eux-mêmes des cas particuliers d'animaux. Les neurones sont des cas particuliers de cellule vivante. Mais un homme n'est pas un cas particulier de cellule vivante, il est composé de cellules vivantes, subtile nuance !Cette notion est valide lorsque l'on peut affirmer que tous les objets de la sous-classe sont des objets de la super classe (la réciproque est fausse, bien sûr). Ainsi tous les neurones sont des cellules, tous les chiens sont des mammifères, tous les mammifères des animaux, mais il n'est pas possible de dire des hommes qu'ils sont des cellules vivantes. Sur les exemples précédemment évoqués, il est logique de dériver la classe Individu pour obtenir le classe Etudiant. En effet, tous les étudiants sont des individus. En revanche, il serait douteux de dériver la classe Date pour obtenir la classe Individu. Les individus ne sont pas une forme spéciale de date bien qu'ils contiennent tous une date de naissance.

L'idée de dérivation est liée à la notion ensembliste. Les étudiants forment un sous-ensemble d'un ensemble plus vaste les individus. Il est clair que les individus ne sont pas un sous-ensemble des dates !L'intérêt de la notion de dérivation, outre l'héritage, repose précisément sur cette notion ensembliste. Java va considérer la classe dérivée comme un cas spécial de la classe de base supposée plus générale et autoriser l'affectation de références sur la classe de base à des objets des classes dérivées. Ainsi, une référence sur Individu, pourra bien évidement pointer sur un individu de « base » mais également sur un individu spécial, un étudiant. Une référence sur individu devient une référence « générique » susceptible de pointer sur tous les « genres » d'individus, étudiants compris. On parle alors de références polymorphes.

Individu ind = new Etudiant();

Bien entendu, au travers de la référence « ind », on ne pourra accéder qu'à la partie Individu des champs de données de l'objet référencé par « ind » même si cet objet est un Etudiant.Contrairement à C++, ce sont les méthodes de l’objet réel qui seront sélectionnées (celles de l’étudiant dans notre cas). En effet, Java recherche la méthode à invoquer au runtime à partir de la nature véritable de l’objet référencé et non pas à partir du type de

Brigitte Groléas 65

Page 66: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

la référence10. C’est l’avantage d’avoir à faire à un langage interprété. Cette recherche « au dernier moment » est appelée liaison dynamique par opposition à la liaison statique qui s’effectue une bonne fois pour toute au moment de la compilation. Puisque les méthodes statiques, privées et finales ne peuvent pas être redéfinies, elles bénéficient d’une liaison statique au moment de la compilation.

Mécanismes de protection dans l'héritage.En plus des phénomènes de masquage dus à l'homonymie des composantes entre la classe dérivée et la classe de base, il faut regarder l’influence des attributs "public:" et "private:" sur l'accessibilité aux champs.L'idée générale de Java est qu'une classe dérivée ne peut pas avoir, ni proposer plus de droits d’accès que n'en prévoit la classe de base. Ainsi, si une classe désire "cacher" certaines de ces composantes en les déclarant privées, la technique de dérivation ne doit pas être le moyen de violer cette volonté de protection de la classe. Par conséquent, les composantes héritées d'une classe Mère auront la même accessibilité dans les méthodes de la classe Fille que celle qu'elles ont à l'extérieur de la classe Mère .Toutes les composantes « propre » de la classe Fille sont, bien entendu, accessibles dans les méthodes de la classe Fille.

class Mere {private int a;public int b;

};class Fille extends Mere {

private int i;public int j;public void foobar() {

a = 10; /* ERREUR */b = 20; /* OK */i = 30; /* OK */j = 40; /* OK */

}}class programme {

public static void main( String args[] ) {Fille f = new Fille();Mere m = new Mere();

f.a = 10; // ERREUR f.b = 20; // OK f.i = 30; // ERREUR f.j = 40; // OK

m.a = 50; // ERREUR

10 C++ peut aussi résoudre dynamiquement la méthode qu’il convient d’appeler en fonction de l’objet véritable. Pour se faire, il faut explicitement déclarer la méthode « virtuelle ».

Brigitte Groléas 66

Page 67: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

m.b = 60; // OK }

}

Les composantes privées d'une classe sont cachées partout (dans les classes dérivées et à l’extérieur) sauf dans la classe elle-même. Les composantes publiques sont visibles partout. Entre ces deux extrêmes, Java propose un compromis dans les relations mère/fille : l'attribut « protected » et l’absence d’attribut (que l’on pourrait nommé friendly par analogie avec le mot clef « friend » du C++). En l’absence de tout attribut, les composantes sont accessibles aux méthodes de la classe et de toutes les classes qui sont définies dans le même package. On peut dire que les composantes sont, par défaut, publiques pour le package dans lequel elles se trouvent et privées pour les autres packages11. L'attribut « protected » permet de définir des composantes de la classe de base qui seront inaccessibles à l'extérieur du package mais accessibles dans les classes dérivées et les classes du même package. D'un certain point de vue, « protected » signifie privé à l'extérieur du package, mais public à l’intérieur du package et par héritage. C'est évidemment au niveau de la classe mère que le problème est traité. Lorsque le concepteur de la classe mère a effectué ses choix de protection, l'utilisateur qui dérive cette classe ne doit avoir aucun moyen d'outrepasser les choix effectués par le concepteur de la classe mère.

package toto;public class Mere {

private int a;protected int b;public int c;

};

package titi;public class Fille extends toto.Mere {

void foobar(){a = 10; // ERREUR b = 20; // OK c = 30; // OK

}}

package tutu;class Programme {

public static void main( String args[] ) {

11 Par rapport au C++, on peut considérer que les composantes non privées d’une classe sont accessibles vis à vis des autres classes du même package comme si les différentes classes d’un même package étaient implicitement mutuellement amies les unes des autres.

Brigitte Groléas 67

Page 68: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

titi.Fille f = new titi.Fille();

f.a = 10; // ERREUR f.b = 20; // ERREUR f.c = 30; // OK

}}

Les différents mécanismes de protection que nous venons d'évoquer sont propagés au cours des dérivations successives. Ainsi, une composante privée de la classe mère, sera inaccessible sur toute une génération de dérivation (fille, petite fille, etc...), A l'opposé, par défaut, une composante "public" ou "protected" d'une classe mère sera accessible sur toute une génération de dérivation publique. Résumé sur la visibilité des composantes   :

Attributs   : public protected rien du tout private

visibilitédes

composantespartout

classe+sous classes

+package

classe +

packageclasse

Résumé sur la visibilité des classes   :

Attributs public rien du tout

visibilité   des

classespartout package

Brigitte Groléas 68

Page 69: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

8. Des classes pour faire des modèles : Abstract.

Notion d’interface fonctionnelle.Les notions de dérivation et d'héritage permettent de construire plus aisément de nouvelles classes en s'inspirant d'un modèle de base (la classe que l'on dérive). Ainsi, plutôt que de partir de rien, la nouvelle classe dérivée hérite d'un certain nombre de fonctionnalités.Pour des raisons d'organisation, de structuration, d'analyse de ses concepts, il peut être agréable de créer des classes dont l'unique ambition soit de servir de modèle pour la dérivation d'autres classes. De telles classes de modélisation ne sont pas créées pour instancier des objets réels, mais plutôt pour mettre en facteur, des notions, des points communs, à plusieurs autres classes qui en hériteront par dérivation. Ce sont ces classes dérivées qui permettront la réalisation d'objets concrets.Cette notion de classes servant de modèle aux autres classes, va être proposée en Java grâce aux classes abstraites. Une classe abstraite est une classe qui exprime un certain nombre de concepts fonctionnels dont certains sont concrets, mais d'autres sont encore abstraits. Les fonctionnalités concrètes seront héritées, et toutes les classes dérivées en bénéficieront. Les fonctionnalités abstraites, qui n'ont pas pu être concrétisées dans la classe abstraite, devront l'être dans les classes dérivées (à moins qu'elles ne soient, elle aussi, abstraites).Une classe abstraite est une classe qui dispose au moins d'une fonctionnalité non encore concrétisée. Elle ne peut pas donner lieu à la création d'objet. Elle n'est utile que pour servir de modèle, de prototype, dans des dérivations. Elle peut, par contre, être utilisée pour la création de références, qui ne pourront, bien entendu, que référer des objets issus de sous classes concrètes.

Brigitte Groléas 69

Page 70: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Syntaxe d’une classe abstraiteUne classe concrète est une classe pour laquelle l'ensemble des fonctionnalités jusqu'alors abstraites ont toutes été concrétisées. Une fonctionnalité concrète est une méthode qui possède un corps (c'est à dire du code). Une fonctionnalité abstraite est une méthode qui n'a pas de corps (pas de code associé). Ce doit être une méthode déclarée abstraite par l’attribut « abstract ». Une classe qui contient au moins une fonction abstraite (directement ou par héritage) est abstraite et doit être déclarée « abstract ».

abstract class Mere {public abstract void foo() ;public abstract void bar() ;public void foobar() {

foo();bar() ;

}}

Dans l'exemple précédent, la classe Mère est abstraite. Elle sert de modèle pour la dérivation de classes filles. Elle ne peut donner lieu à l'instanciation d'objet de type « Mere ».Mais elle permet de définir une interface fonctionnelle en évoquant 3 méthodes et pour chacune d'entre elle, le type d'objet retourné ainsi que les arguments passés. Deux de ces fonctionnalités (« foo » et « bar ») sont abstraites et devront être concrétisées dans les classes filles. La troisième « foobar() » est concrète et possède un corps.L'algorithme (le code) de la méthode « foobar() » peut être défini tout de suite dans la classe abstraite, alors que les 2 méthodes appelées par « foobar() » ne sont pas encore concrétisées. La méthode concrète « foobar() » est héritée dans les classes filles dérivées. La méthode « foobar() » pourra être utilisée au sein d'une classe fille et ce sont les concrétisations de « foo() » et de « bar() » définies dans la fille qui seront effectivement mises en oeuvre (cf. liaison dynamique des méthodes).

Brigitte Groléas 70

Page 71: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple d’une classe abstraite « Forme ».Voyons sur un exemple. Prenons le cas de la classe « Cercle ». Cette classe Cercle, pourrait être dérivée d'une classe abstraite plus générale, la classe « Forme ». Cette classe « forme » permet de regrouper les données et les fonctionnalités communes à toutes formes géométriques. Ainsi, on peut déjà définir la position de la forme, et quelques méthodes d'action comme par exemple, déplacer, afficher, effacer une forme.

abstract class Forme {private int xpos ;private int ypos;

public abstract void efface(); // abstrait public abstract void affiche(); // abstrait public void deplace( int x, int y ) { // concret

efface();xpos = x;ypos = y;affiche();

}}

class Cercle extends Forme {public void efface() { // concret

// code de la méthode efface}public void affiche() { // concret

// code de la méthode affiche}

}

Brigitte Groléas 71

Page 72: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

9. Héritage Multiple : les Interfaces

Héritage Multiple.Nous avons déjà évoqué que la notion de dérivation pouvait être mise en relation avec les notions d'ensemble. Ainsi l'ensemble des animaux peut se subdiviser en mammifères, reptiles, insectes etc... Mais on peut également effectuer des subdivisions selon d'autres critères. Par exemple, carnivores, herbivores, etc...Dans cette situation, il serait agréable de pouvoir prendre en compte qu'un chat est un mammifère carnivore, qu'un crocodile est un reptile carnivore et qu'une vache est un mammifère herbivore. En effet, un crocodile et un chat sont des carnivores et partagent un mode alimentaire, une vache et un chat sont des mammifères et partagent un mode de reproduction.Intuitivement cela donne :

Reptile

Crocodile

animal carnivore léopard

Félin

mammifère chat

vache

herbivore

Cette possibilité pour une classe de dériver de plusieurs classes de base se nomme l'héritage multiple. Le langage Java a décidé de ne pas supporter l’héritage multiple des classes. Ainsi, une classe Java ne peut pas être une sous classe de plusieurs autres classes.

Notion d’interfaceEn revanche, Java propose la notion d’interface. Une interface est une sorte de classe spéciale abstraite, dont toutes les méthodes sont implicitement « public » et « abstract » et dont toutes les composantes données sont implicitement « static » et « final » (c’est à

Brigitte Groléas 72

Les liens expriment les dérivations

Page 73: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

dire des constantes !). Une interface est une pure conception (totalement abstraite), alors qu’une classe est un mélange de conception et d’implémentation. L’interface permet de définir un contrat d’interface fonctionnelle grâce à la déclaration des méthodes abstraites qu’elle contient. Si une classe décide d’implémenter cette interface, elle devra obligatoirement concrétiser toutes les méthodes abstraites de l’interface en respectant la syntaxe imposé par le contrat de l’interface. (nom des méthodes, type de retour et paramètres de ces méthodes).

Définition d’une interface.La définition d’une interface est similaire à celle d’une classe, mais les champs donnés ne sont que des constantes et les méthodes sont forcément abstraites. Cela donne :

interface Bidule {int CONST = 10;void foo( int x );int bar( double d );

}

Utilisation d’une interface : « implements ».Une classe peut utiliser une interface comme base, mais au lieu de dire qu’elle étend l’interface comme c’est le cas pour une super classe, on dit qu’elle implémente l’interface et on utilise le spécificateur « implements ». Cela donne :

class Truc implements Bidule {pubic void foo( int x ) {

// code concret de l’implémentation de la méthode foo()}public int bar( double d ) {

// code concret de l’implémentation de la méthode bar()}

}

L’intérêt réside dans le fait qu’une classe peut implémenter une ou plusieurs interfaces tout en dérivant d’une classe :

class Truc extends Chose implements Bidule, Machin { // ...

}

Brigitte Groléas 73

Page 74: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Références polymorphes Les interfaces peuvent donner lieu à la déclaration de références polymorphes. Ainsi on peut définir une référence sur l’interface Bidule pour pointer un objet de la classe Truc.

class Truc extends Chose implements Bidule, Machin { // concrétisation des methodes de Bidule et Machin...

}class Truc2 extends AutreChose implements Bidule {

// concrétisation des méthodes de Bidule...}Bidule b1 = new Truc();Bidule b2 = new Truc2();b1.foo(); // lance la méthode foo() de Truc.b2.foo(); // lance la méthode foo() de Truc2.

Dérivation d’interfaces.Une interface peut dériver d’une ou plusieurs autres interfaces, ainsi l’héritage multiple est possible pour les interfaces. Par exemple :

Interface Bidule { ...}Interface Machin {... }Interface Pouet extends Bidule, Machin {...}

Brigitte Groléas 74

Page 75: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Traitement d’erreurs: Les exceptions

1. Les Exceptions Java.Les exceptions, en Java constituent un moyen fiable et pratique d’effectuer un contrôle des erreurs rigoureux sans alourdir le code. Java oblige le programmeur à traiter les erreurs qui ont été déclarées par des fonctions standards, considérant que la notion d’erreur fait partie intégrante de la fonction et n’est pas « quelque chose que l’on verra plus tard » !

Principe de fonctionnementUne exception est un signal qui indique qu’une chose d’inhabituelle (par exemple une erreur) s’est produite. Ce signal est véhiculé par un objet (de type Throwable12) qui est lancé et se propage en remontant au travers de l’imbrication des blocs de code et les appels emboîtés de fonctions depuis sa source jusqu'à la méthode « main() ».Si une exception n’est pas capturée par le bloc de code qui l’a générée, l’exception se propage vers le bloc directement entourant. Si aucun bloc de la méthode ne capture l’exception, elle se propage vers la méthode appelante et ainsi de suite. Si l’exception n’est jamais capturée, elle finira sa « remontée » à la méthode « main() » et conduira l’interpréteur Java à s’arrêter en affichant un message d’erreur et une trace de la pile.

Les classes Throwable, Error, Exception et RuntimeException.Une exception est un objet d’une sous-classe de « java.lang.Throwable ». La classe « Throwable » possède deux sous classes standard « Error » et « Exception ». La classe « Exception » possède une sous-classe « RuntimeException » :

Les Exceptions qui sont des sous-classes de « Error » correspondent à des erreurs fatales (erreur d’édition de liens dynamique, plus de mémoire, ... ). En général, elles ne doivent pas être capturées et traitées par le programmeur car elles correspondent à des erreurs non récupérables. Elles provoquent l’arrêt de l’interpréteur Java et

12 To throw signifie lancer en anglais.

Brigitte Groléas 75

Page 76: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

l’affichage d’un message d’erreur. Ce sont des exceptions non contrôlées puisqu’il n’y a pas obligation de les traiter ou de les déclarer.

Les Exceptions qui sont des sous-classes de « Exception » indiquent des erreurs non fatales qu’il convient de considérer en les capturant et en les traitant. Si une méthode est susceptible de générer une exception elle doit obligatoirement, soit capturer et traiter cette exception, soit la déclarer dans son entête par une clause « throws » pour prévenir qu’elle ne la traite pas. Ce sont des exceptions contrôlées puisqu’il y a obligation de les traiter ou de les déclarer.

Les Exceptions qui sont des sous-classes de « RunTimeException » indiquent des erreurs non fatales que le programmeur peut capturer et traiter, mais qui sont considérées comme omniprésentes (parce que trop courantes) et ne nécessitent pas de déclaration dans l’entête des méthodes qui ne les traitent pas. Ce sont des exceptions non contrôlées.

La classe « Throwable » contient les méthodes suivantes qui sont héritées par toutes les sous-classes :

String getMessage(); retourne le message standard associé à l’Exception ou l’Erreur.

void printStackTrace(); void printStackTrace( PrintStream flux )affiche une trace de la pile sur le flux qui montre où a eu lieu l’exception. Par défaut affiche sur « System.out ».

Les Exceptions de la classe « Error ».LinkageError

ClassCircularityErrorClassFormatErrorIncompatibleClassChangeError

AbstractMethodeErrorIllegalAccessErrorInstantiationErrorNoSuchFieldError

NoSuchMethodError

NoClassDefFoundErrorUnsatisfiedLinkErrorVerifyError

ThreadDeathVirtualMachineError

InternalError

Brigitte Groléas 76

Page 77: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

OutOfMemeoryErrorSackOverflowErrorUnknowError

AWTError (java.awt)

Les Exceptions de la classe « RuntimeException ».ArithmeticExceptionArrayStoreExceptionClassCastExceptionIllegalArgumentException

IllegalThreadStateExceptionNumberFormatException

IllegalMonitorStateExceptionIndexOutOfBoundsException

ArrayIndexOutOfBoundsExceptionStringOutOfBoundsException

NegativeArraySizeExceptionNullPointerExceptionSecurityExceptionEmptyStackException (java.util)NoSuchElementEception (java.util)

Les Exceptions de la classe « Exception ».

ClassNotFoundExceptionCloneNotSuportedExceptionIllegalAccessExceptionInstantiationExceptionInterruptedExceptionNoSuchMethodeExceptionAWTException (java.awt)IOException (java.io)

EOFException (java.io)FileNotFoundException (java.io)InterruptedIOException (java.io)UTFDataFormatException (java.io)MalformedURLException (java.net)ProtocolException (java.net)SocketException (java.net)UnknownHostException (java.net)UnknownServiceException (java.net)

Brigitte Groléas 77

Page 78: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exceptions contrôlées : Clause throws.Le langage Java oblige le programmeur à avoir une gestion rigoureuse des exceptions contrôlées afin d’éviter les bogues qui résultent de l’absence de traitement des erreurs. Ainsi, Java exige la déclaration de l’ensemble des exceptions contrôlées qu’une méthode est susceptible de générer. Cette obligation fait en quelque sorte partie du contrat déclaratif de la méthode. Java considère que la déclaration des exceptions contrôlées qu’une méthode peut lever est aussi importante que le type de la valeur qu’elle retourne. Cette déclaration s’effectue à l’aide d’une clause « throws » derrière l’en-tête de la fonction qui prend en argument une liste de types (classes) d’exceptions séparées par des virgules.

public void methode() throws UneException, UneAutreException {// corps de la méthode

}

Le contrat défini par la clause « throws » est appliqué rigoureusement : le compilateur vérifie que les classes d’exceptions déclarées dans la clause « throws » d’une méthode correspondent effectivement aux classes (ou sous-classe) d’exceptions susceptibles d’être générées par cette méthode, que se soit directement (une exception définie par l’utilisateur et lancée explicitement via l’instruction « throw »), ou indirectement en appelant une autre méthode qui déclare générer des exceptions dans sa propre clause « throws ». Ainsi, quand le programmeur défini une méthode qui utilise des méthodes standards déclarant des exceptions contrôlées dans leurs clauses « throws », il ne peut pas les ignorer et doit avoir une stratégie pour les gérer. Trois choix s’offrent à lui :

Capturer l’exception et la traiter. Sa méthode n’a plus à déclarer cette classe d’exceptions dans sa clause « throws » puisqu’elle a été traitée.

Capturer l’exception, ne pas la traiter (ou la traiter partiellement) et générer une nouvelle exception définie par le programmeur (via l’instruction throw). Il doit alors déclarer cette nouvelle classe d’exceptions dans la clause « throws » de sa méthode.

Ignorer l’exception dans le corps de sa méthode. Il doit alors déclarer cette classe d’exception dans la clause « throws » de sa méthode car elle est indirectement susceptible de générer ce type d’exceptions.

La manière de capturer une exception est décrite dans la section suivante. Pour ignorer une exception contrôlée, il faut le stipuler explicitement dans la clause « throws ». Par exemple, écrivons une méthode « lireligne() » qui utilise « readLine() » de la classe « java.io.BufferedReader ». La méthode « readLine() » déclare générer des exceptions de type « java.io.IOException », par conséquent, la méthode « lireligne() » doit

Brigitte Groléas 78

Page 79: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

déclarer, elle aussi, générer des exceptions de même type dans sa clause « throws » (à moins qu’elle ne les capture pour les traiter ) Cela donne :

public static String lire() throws java.io.IOException {BufferedReader clavier;

clavier = new BufferedReader( new InputStreamReader( System.in ) );

return clavier.readLine();}

Les Exceptions qui sont des sous-classe de « Error » ou de « RunTimeException » n’ont pas à être listées dans la clause « throws ». Elles sont considérées comme omniprésentes, pouvant être générées par toutes méthodes et le compilateur ne les vérifie pas.

Capturer des Exceptions : try, catch.Pour capturer des exceptions, il convient d’utiliser la structure de contrôle « try/catch » de la manière suivante :

public void methode() {

// code avant le try

try {// instructions risquant de générer des Exceptions

} catch( UneException e) {// traitement des Exceptions de type UneException

} catch( UneAutreException e) {// traitement des Exceptions de type UneAutreException

}

// code après le try}

Lorsque l’on entre dans le bloc « try » , chaque instruction qui le compose va tenter d’être exécutée.

Si ces instructions ne génèrent aucune exception, le déroulement se poursuit normalement en exécutant le code après le « try ».

Si l’une des instructions du bloc « try » génère une exception, l’exécution du code situé dans le « try » est interrompue et les clauses « catch » attachées au « try » sont scrutées dans l’ordre afin de déterminer si l’une d’entre-elles peut capturer l’exception.

Brigitte Groléas 79

Page 80: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Si aucune clause « catch » ne satisfait l’exception, l’exception est propagée à l’extérieur à la recherche d’une structure « try » enveloppante au travers de l’imbrication des appels de fonction.

Si l’une des clause « catch » satisfait l’exception, les instructions de la clause « catch » concernée sont exécutées et le déroulement se poursuit en exécutant le code après le « try ».

La clause « catch » est argumentée avec une déclaration d’objet d’une sous-classe de la classe Exception. Cette déclaration sert à deux choses.

Le type permet de définir la classe d’Exceptions qui est capturée. N’importe quelle exception de cette classe ou de l’une de ses sous-classes sera capturée. Comme les clauses « catch » sont scrutées dans l’ordre, une clause « catch » qui capture une classe d’exception avant une clause qui capture une sous-classe de cette classe est une erreur.

L’objet de type Exception permet de récupérer des informations concernant l’exception elle-même (l’instance), comme par exemple le message d’erreur associé pour l’utiliser localement dans le bloc « catch ».

Par exemple, comme la division entière est susceptible de générer une Exception de type « ArithmeticException » lorsque le diviseur est égal à zéro, on peut capturer ce type d’exception dans une méthode effectuant une division entière. Cela donne :

public static void methode(int x, int y) {try {

int resultat = x / y;} catch( ArithmetiqueException e ) {

System.out.println( e.getMessage() ) ;return ;

}// code si tout va bien

}

La méthode « getMessage() » permet de récupérer le message d’erreur standard contenu dans l’objet ArithmeticException « e ».

Brigitte Groléas 80

Page 81: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

De toute façon : Clause finallyLa structure « try » peut contenir une dernière clause facultative « finally » :

public void methode() {

// code avant le try

try {// instructions risquant de lever des Exceptions

} ...

} finally {code à effecuer quoi qu’il en soit

}

// code après le try}

Si la clause « finally » est présente, son code est exécuté après le traitement de bloc « try » quelque soit la façon dont le traitement s’est achevé, que se soit normalement, par une exception, ou par une instruction de rupture de séquence comme return, break ou continue. Par conséquent, il n’y a aucun moyen de quitter une structure « try » sans exécuter les instructions de sa clause « finally ».

Si l’on quitte le bloc « try » normalement, le déroulement se poursuit par l’exécution des instructions du bloc « finally » avant d’exécuter le code après le « try ».

Si l’on quitte le bloc « try » à cause d’une rupture return, break, ou continue, le déroulement se poursuit par l’exécution des instructions du bloc « finally » avant d’effectuer l’action correspondant à la rupture. Si le bloc « finally » contient lui-même une rupture, c’est la rupture du bloc « finally » qui gagne.

Si l’on quitte le bloc « try » à cause d’une exception, et que l’exception est capturée par une clause « catch », les instructions du bloc « catch » concerné sont effectuées, puis le déroulement se poursuit par l’exécution des instructions du bloc « finally » (même si le bloc catch contient une rupture ou génère une autre exception).

Si l’on quitte le bloc « try » à cause d’une exception qui ne peut être capturée par aucune clause « catch », le déroulement se poursuit par l’exécution des instructions du bloc « finally » puis l’exception se propage comme d’habitude.

Une clause « finally » peut apparaître dans une structure de contrôle « try » sans qu’il y ait aucun « catch ».

Brigitte Groléas 81

Page 82: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Exceptions utilisateur

Créer des Exceptions.Les exceptions sont des objets instance d’une classe dérivée de la classe « Throwable ». Par conséquent, pour définir de nouvelles exceptions, il faut définir des classes dérivées de la classe « Throwable » ou de l’une de ses sous-classes. Par convention, les nouveaux types d’exception définis par le programmeur dérivent de la classe « Exception » (sous classe de « Throwable ») afin d’être des exceptions contrôlées.La classe « Exception » contient un champ String (hérité de « Throwable »qui sert à décrire le message associé à l’erreur. Ce champ peut être consulté par la méthode « getMessage() » et être défini à l’aide du constructeur de la classe.

Exception( String message ); fixe le message d’une nouvelle exception.

String getMessage(); retourne le message associé à l’Exception.

Une nouvelle classe d’exceptions définie par le programmeur peut contenir des champs supplémentaires, si l’on désire que l’exception soit porteuse d’attributs destinés à préciser des renseignements sur la nature ou la raison de l’exception (par exemple un code d’erreur). Ces champs étant véhiculés dans l’objet exception, ils pourront être accédés (via des méthodes publiques) par les instructions d’une clause « catch » capturant l’exception. Cela permet d’établir une communication entre la source de l’exception et son traitement.Par exemple, pour définir une classe « PileException » destinée à prendre en compte les erreurs pile pleine et pile vide d’une classe pile, on peut procéder comme suit :

class PileException extends Exception {private int codeErreur;

public PileException( String mess, int code ) {super( "Erreur Pile : " + mess );codeErreur = code;

}public final int getErrorCode() {

return codeErreur;}

}

En général, il faut créer de nouveaux types d’exceptions quand le programmeur veut distinguer un type d’erreur plutôt qu’un autre. Il peut alors, capturer le type correct au lieu de capturer un type plus générique qui l’obligera à examiner le contenu de l’objet

Brigitte Groléas 82

Page 83: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

exception pour déterminer s’il faut réellement traiter cette erreur ou si la capture concerne une erreur sans intérêt qui a été interceptée par accident.

Lancer des Exceptions : Instruction throw.Pour lancer une exception, il suffit de créer une instance de la classe exception désirée (par un new) et lancer cette exception par l’instruction « throw » qui prend en argument un objet de type Exception. Bien entendu, la méthode qui lance une exception doit la déclarer dans sa clause « throws ». Voici l’utilisation des exceptions de la classe « PileException » définie dans le paragraphe précédent dans le cadre du développement d’une classe Pile d’entiers :

public class pile {private int pile[];private int sommet = 0;public static final int ERR_VIDE = -1;public static final int ERR_PLEINE = -2;

Pile( int taille) { pile = new int[taille]);

}void empile( int val ) throws PileException {

if( sommet >= pile.lenght ) {throw new PileException( "Pleine", ERR_PLEINE);

}pile[sommet++] = val ;

}void int depile() throws PileException {

if( sommet < 1) {throw new PileException( "Vide", ERR_VIDE );

}return pile[--sommet];

}}

Brigitte Groléas 83

Page 84: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Programmation Multitâches : Threads

Une thread est une tâche indépendante qui s’exécute parallèlement à d’autres. L’interpréteur Java exécute toutes les threads d’une application à tour de rôle, en tenant compte de leurs priorités respectives.

1. Etendre la classe Thread. Pour définir une thread, il faut se baser sur la classe « java.lang.Thread » qui contient un certain nombre de méthodes pour créer, lancer et manipuler les threads.

Définition d’une sous classe de Thread.Pour définir un objet de type thread, il faut commencer par étendre la classe prédéfinie « java.lang.Thread » . Cette classe (qui implémente l’interface runnable) possède une implémentation vide de la méthode « run() » qu’il convient de redéfinir pour fixer le code exécutable de la thread.

class Tache extends Thread {public void run() {

// code exécutable de la thread}

}

Instanciation et lancement d’une sous classe de Thread.La méthode « start() » de la classe « java.lang.Thread » permet de démarrer une nouvelle thread.

public class Programme {public static void main( String argv[] ) {

Tache p1, p2;

p1 = new Tache(); // création tache n° 1p2 = new Tache(); // création tache n° 2p1.start(); // demarrage tache n° 1p2.start(); // demarrage tache n° 2

}}

Brigitte Groléas 84

Page 85: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple : Une classe PingPong sous classe de Thread.Définition d’une classe « PingPong » permettant d’instancier des threads affichant un message à l’écran à une certaine fréquence :

class PingPong extends Thread {String word; // mot à afficherint delay; // durée de la pause (en microsecondes)

PingPong( String s, int t ) {word = s;delay = t;

}public void run() {

try {for( ;; ) {

System.out.print( word + " " );sleep( delay );

}} catch( InterruptedException e ) {

return;}

}}

Création de deux threads, l’une affichant « ping » 30 fois par seconde et l’autre affichant « PONG » 10 fois par seconde :

public class Programme {public static void main( String argv[] ) {

PingPong p1, p2;

p1 = new PingPong( "ping", 33 ); // 1/30 de secondep2 = new PingPong( "PONG", 100 ); // 1/10 de seconde

p1.start();p2.start();

}}

Cela donne quelque chose comme :

ping PONG ping ping PONG ping ping ping PONG ping ping PONG ping ping ping PONG ping ping ping PONG ping ping PONG ....

Brigitte Groléas 85

Page 86: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

2. Implémenter l’interface Runnable.Pour définir un objet de type thread, au lieu d’étendre la classe prédéfinie « Thread », on peut implémenter l’interface « java.lang.Runnable ». Comme Java ne permet pas l’héritage multiple, cela devient indispensable quand la classe que l’on veut définir doit logiquement hériter d’une autre classe que « Thread ».

Définition d’une thread en implémentant l’interface Runnable.L’interface « Runnable » possède une seule méthode abstraite « run() » prévue pour définir le code exécutable de la thread.

class Tache implements Runnable {public void run() {

// code de la thread}

}

Instanciation et lancement d’une thread via runnable.Un objet « Runnable » peut être exécuté dans une thread en l’associant à une thread après son instanciation. En effet, si un objet « Thread » est construit avec un objet « Runnable », l’implémentation de la méthode « run() » de l’objet Thread invoquera la méthode « run() » de l’objet « Runnable ». Cela donne :

public class Programme {public static void main( String argv[] ) {

Tache p1, p2;Thread t1, t2 ;

p1 = new Tache(); // création tache n° 1p2 = new Tache(); // création tache n° 2t1 = new Thread( p1 ); // association des tachest2 = new Thread( p2 ); // aux Threadsp1.start(); // demarrage thread n° 1p2.start(); // demarrage thread n° 2

}}

Exemple de la classe « PingPong » implémentant « Runnable ».

Brigitte Groléas 86

Page 87: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

class PingPong implements Runnable {String word; // mot à afficherint delay; // durée de la pause (en microsecondes)

PingPong( String s, int t ) {word = s;delay = t;

}public void run() {

try {for( ;; ) {

System.out.print( word + " " );Thread.sleep( delay );

}} catch( InterruptedException e ) {

return;}

}}

public class Programme {public static void main( String argv[] ) {

PingPong p1, p2;Thread t1, t2;

p1 = new PingPong( "ping", 33 ); // 1/30 de secondep2 = new PingPong( "pong", 100 ); // 1/10 de seconde

t1 = new Thread( p1 ); // associer les runnablest2 = new Thread( p2 ); // aux threadst1.start(); // et lancer les threadst2.start();

}}

Brigitte Groléas 87

Page 88: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

3. Cycle de vie d’une Thread.Une Thread peut être dans cinq états différents :

Etat Nouveau.La Thread vient d’être créée. La mémoire est allouée et les données privées sont initialisées. La méthode « start() » permet de démarrer la thread pour la placer dans la file d’attente des threads exécutables en fonction de sa priorité. La priorité d’une thread est initialement la même que celle de la thread qui l’a créée. Cette priorité peut être changée en utilisant la méthode « setPriority() ».

Etat Exécutable.L’état exécutable correspond aux threads qui sont prêtes à être exécutées et qui attendent le contrôle du processeur. C’est une file d’attente où chaque thread exécutable est placée en fonction de sa priorité.

Etat Courant.La Thread courante est celle qui possède le contrôle du processeur (i.e. celle qui s’exécute en ce moment). Elle peut céder le contrôle par la méthode « yield() » qui la place dans l’état exécutable, ou se bloquer par les méthodes « sleep() », « wait() » ou « suspend() » jusqu'à ce qu’un événement lui dise de reprendre son service et de se

Brigitte Groléas 88

Nouveau

Exécutable Courant

Bloqué

Mort

start()

Page 89: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

remettre dans la file d’attente des threads exécutables. La méthode statique « Thread.currentThread() » retourne l’objet thread en cours d’exécution (i.e. la thread courante).

Etat Bloqué.Une thread passe à l’état bloqué par l’une des méthodes « sleep », « suspend » ou « wait ».Une thread bloquée attend un événement qui lui demande de réintégrer la file d’attente des threads exécutables. La nature de cet événement dépend de la nature du blocage :

une thread qui dort (sleep) attend le temps imparti (time-out). Une thread suspendue (suspend) attend qu’une autre thread lui demande

explicitement de reprendre son activité par le biais de la méthode « resume() » ou l’expiration d’un time-out.

Une thread en attente (wait) attend d’être avertie d’un changement de condition par une autre thread via la méthode « notify() » ou bien l’expiration d’un time-out.

Etat Mort.Une thread morte est une thread qui a fini son exécution, soit en ayant terminé son travail (fin de la méthode « run() »), soit en étant stoppée par une autre thread par la méthode « stop() ».

Brigitte Groléas 89

Page 90: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

4. Ordonnancement des Threads.Le mécanisme d’ordonnancement des threads de Java n’est pas spécifié de façon très précise et dépend, pour l’instant, de l’implémentation du support d’exécution Java.

Multitâche préemptif.Normalement, l’ordonnancement par défaut des threads est préemptif (i.e. les threads qui possèdent la priorité la plus élevée se partagent plus ou moins équitablement le temps CPU). L’interprète Java peut suspendre la thread de plus haute priorité pour faire exécuter une autre thread de même priorité, ce qui signifie que toutes les threads avec la priorité la plus élevée s’exécuteront finalement (le sens donné au mot « finalement » n’est pas très précis !). Les threads de priorité inférieure s’exécutent seulement (ou surtout ?!?) quand les threads de priorité supérieure sont bloquées.

Agir sur l’ordonnancement de la thread courante.Plusieurs méthodes permettent d’agir sur l’ordonnancement de la thread courante. Il est possible de consulter et de modifier la priorité d’une thread, de l’endormir pour un certain laps de temps, ou de quitter volontairement le contrôle du processeur.

int getPriority(); retourne la priorité d’une thread.

void setPriority( int prio ) throws IllegalArgumentException ;Change le priorité d’une thread. L’intervalle de valeurs est compris entre Thread.MIN_PRIORITY et Thread.MAX_PRIORITY. La priorité « standard » est Thread.NORM_PRIORITY. La thread courante peut changer sa priorité à n’importe quel moment. Si elle diminue sa priorité, le système peut choisir de faire exécuter une autre thread si la thread courante n’est plus parmi celles ayant la priorité la plus haute.

static void sleep( long milli ) throws InterruptedException; static void sleep( long milli, int nano ) throws InterruptedException;Met la thread en cours d’exécution en sommeil pour au moins le nombre de millisecondes (et nanosecondes) donné. Il n’y a aucune garantie que la thread se réveille dans exactement le temps spécifié. Un autre ordonnancement de thread peut interférer ainsi que la précision de l’horloge système.

static void yield(); Abandonne la thread en cours d’exécution et cède le contrôle à une autre thread choisie parmi la file d’attente des threads exécutables. La nouvelle thread choisie peut être celle qui a cédé le contrôle si elle possède la priorité la plus élevée !

Brigitte Groléas 90

Page 91: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Multitâche coopératif.L’utilisation de la méthode « yield() » permet de faire du multitâche coopératif. Chaque thread décide de passer le contrôle à une autre thread au moment qui lui semble opportun. Voici un exemple :

class PingPong extends Thread {String word; // mot à afficher

PingPong( String s ) {word = s;

}public void run() {

for( int i = 0; i < 10; ++i ) {System.out.print( word + " " );yield();

}}

}public class Programme {

public static void main( String argv[] ) {PingPong p1 = new PingPong( "ping" );PingPong p2 = new PingPong( "PONG" );p1.start();p2.start();

}}

produira une sortie qui ressemble à :

ping PONG ping PONG ping PONG ping PONG ping PONG ping PONG ping PONG ping PONG ping PONG ping PONG

Le résultat précédent n’est qu’un exemple approximatif de trace d’exécution. Le résultat effectif peut varier d’une plate-forme à l’autre. La seule certitude est que l’emploi de la méthode « yield() » donne aux autres threads une chance plus équitable d’obtenir des cycles CPU.

Suspendre les ThreadsLes méthodes « suspend() » et « resume() » permettent d’interrompre et de reprendre l’exécution d’une thread. Lorsqu’une thread est suspendue, elle quitte le contrôle du processeur, libère les ressources (verrous acquis sur des méthodes synchronisées) et passe dans l’état bloqué.

static void suspend(); Arrête temporairement une thread et la place dans l’état bloqué. Une thread peut se suspendre elle-même et quitter ainsi le contrôle du processeur au profit d’une autre

Brigitte Groléas 91

Page 92: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

thread. Elle peut également être suspendue par l’intermédiaire d’une autre thread. Il n’est pas dangereux de suspendre une thread déjà suspendue.

static void resume(); Permet de reprendre l’exécution d’une thread suspendue. Cette méthode ne peut être exécutée que par une autre thread (puisque la thread cible est suspendue !). Il n’est pas dangereux de tenter de relancer une thread qui n’aurait pas été suspendue.

5. Synchronisation : éviter les télescopages.Les threads de Java partagent le même espace mémoire. Ainsi plusieurs threads peuvent accéder simultanément à un même objet. Il est nécessaire de mettre en œuvre des outils de synchronisation pour éviter qu’une thread ne consulte une valeur pendant qu’une autre thread est en train de la modifier. C’est au programmeur de décider quelles sont les méthodes ou les instructions qui n’ont pas le droit de s’exécuter en parallèle. Le principe consiste à poser un verrou sur l’objet. La pose d’un verrou est effectuée automatiquement par Java dès lors que l’on utilise une méthode de l’objet qui est déclarée « synchronized ». Lorsque l’objet est verrouillé par une thread, aucune autre thread ne peut accéder à cet objet au travers d’une méthode « synchronized » tant que la première thread n’a pas relâché le verrou. Attention, il est bien sur possible d’accéder à l’objet via des méthodes non synchronisées ou directement à ses composantes données (variable d’instance ou de classe) si celles-ci ne sont pas déclarées « private ».

Brigitte Groléas 92

Page 93: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Méthodes d’instance synchronisées.Voyons, par exemple, le cas d’une file d’attente d’objets composée de deux méthodes « ajoute() » et « retire() » qui permettent respectivement d’ajouter un nouvel élément à la queue de la file et de retirer le premier élément de la file :

class Element {Object obj;Element suivant = null;public Element( Object o ) {

obj = o;}

}

public class File {private Element tete = null; // premier de la fileprivate Element fin = null; // dernier de la file 

public synchronized void ajoute( Object obj ) {Element elt = new Element( obj );

if( tete == null ) { // si la file est videtete = elt; // elt est le premier

}else { // sinon

fin.suivant = elt; // elt après le dernier}fin = elt; // elt est le dernier

}public synchronized Object retire() {

Element elt = tete; // prendre le premierif( tete != null ) { // si file n’est pas vide

tete = tete.suivant; // retirer le premierreturn elt.obj; // et le retourner

}return null; // cas file vide

}}

Comme les deux méthodes sont synchronisées, lorsqu’une thread ajoute un élément sur une instance donnée, elle interdit l’ajout et retrait d’éléments sur cet objet par tout autre thread tant qu’elle n’a pas terminé son travail. Ainsi, plusieurs threads peuvent librement et en toute quiétude ajouter et retirer des éléments sur une même et seule file d’attente partagée. Les accès aux méthodes synchronisées sont donc en exclusion mutuelle. Les variables d’instances « tête » et « fin » sont, bien entendu, déclarées « private » pour garantir que l’accès à ces données ne peut s’effectuer qu’au travers des méthodes synchronisées « ajoute » et « retire ». L’accès aux champs de la classe « élément » ne nécessitent pas de mécanisme de synchronisation particulier puisque toutes les références aux éléments d’une file sont crées par des méthodes synchronisées

Brigitte Groléas 93

Page 94: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

de la classe file. (puisqu’ils ne sont pas connus, ils ne sont donc pas manipulables depuis l’extérieur).

Méthodes de classe synchronisées.Les méthodes de classe (méthodes statiques) peuvent également être déclarées « synchronized ». Dans ce cas, une thread invoquant une méthode de classe, provoque la pose d’un verrou au niveau de la classe. Une autre thread ne peut pas lancer une méthode statique synchronized sur la même classe tant que le verrou est actif. Le verrou de classe n’a d’effet que sur les méthodes de classe et n’empêche aucunement l’accès aux méthodes d’instance synchronisées de cette classe (et réciproquement !).

Héritage des méthodes synchronisées.Si une classe fille étend une classe mère qui possède des méthodes synchronisées, les méthodes héritées sont, bien entendu, synchronisées. Si la classe fille redéfini une méthode synchronisée, la nouvelle méthode peut être synchronisée ou pas. Toutefois, si la redéfinition de la méthode n’est pas synchronisée, la méthode de la super classe reste, bien sûr, synchronisée si elle est invoquée par la syntaxe « super.methode() ». L’objet est alors verrouillé à l’entrée de la méthode de la super classe et déverrouillé quand la méthode de la super classe retourne.

Instructions synchronisées.La structure de contrôle « synchronized » permet de poser un verrou sur un objet quelconque le temps d’exécuter un bloc d’instruction. La structure de contrôle « synchronized » se compose de deux parties : un objet à verrouiller, et un bloc d’instructions à exécuter. La syntaxe est de la forme :

synchronized( objet ) {instructions

}

Dans l’expression parenthésée, objet représente l’objet à verrouiller. Quand le verrou est obtenu, les instructions du bloc sont exécutées exactement comme s’il s’agissait d’une méthode synchronisée. Cela peut permettre d’effectuer de façon synchronisée une méthode non synchronisée d’une classe qui n’a pas été prévue pour fonctionner dans un environnement multi-thread (on peut aussi dériver l’objet et redéfinir les méthodes que l’on souhaite synchroniser).

Brigitte Groléas 94

Page 95: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

L’objet verrouillé ne doit pas forcement être utilisé dans le corps de la structure de contrôle « synchronized ». Il est ainsi possible d’utiliser un objet « fictif » dont le seul rôle est de servir de verrou (comme un sémaphore) pour une série d’autres objets.

Interblocages.Un des problèmes classiques de synchronisation est l’interblocage (deadlock). Une situation simple d’interblocage arrive lorsque 2 taches se bloquent mutuellement chacune attendant que l’autre lève son verrou pour continuer ! Voyons l’exemple suivant :

class X {public static synchronized void foo {) {

Y.bar();}

}class Y {

public static synchronized void bar() {X.foo();

}}

En effet, si une tâche T1 lance X.foo() et obtient le verrou sur X mais pas encore celui sur Y et simultanément une tâche T2 lance Y.bar() et obtient le verrou sur Y, alors T1 est bloqué en attente sur Y qui ne peut être libérée que par T2 qui est bloquée en attente sur X qui ne peut être libérée que par T1 qui est bloquée en .... Il n’y a pas de mécanisme visant à empêcher les interblocages. C’est au programmeur d’éviter ces situations. D’une manière générale, pour éviter un interblocage, il suffit qu’une tâche cherche à acquérir

soit toutes les ressources dont elle a besoin soit aucune pour ne pas risquer de bloquer alors qu’on ne sera pas servi soi-mêmeCela consiste à rendre atomique l’acquisition des ressources par une section critique contrôlée par un seul verrou.

Accès non synchronisés : variables volatiles.La mise en œuvre des accès synchronisés est la manière propre de procéder pour résoudre les conflits d’accès. Toutefois, si dans certaines situations, une variable n’est pas protégée par des accès synchronisés alors qu’elle subit de multiples accès concurrents de plusieurs threads, on peut la déclarer « volatile » pour prévenir le compilateur que contrairement aux apparences cette variable risque d’être modifiée par d’autres threads. En effet, dans l’extrait de code suivant :

Brigitte Groléas 95

Page 96: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

public void run() {Variable = 5;for( ;; ) {

System.out.println( Variable );Thread.sleep( 1000 ); // dormir 1 seconde

}}

le compilateur peut supposer que la variable est invariante dans la boucle et optimiser en utilisant la constante 5 chaque fois qu’il invoque « println ». Déclarer Variable comme étant volatile empêche le compilateur de faire de telle supposition.

6. Les Rendez-vous.Le couple de méthodes « wait() » et « notify() » implémente un moyen de communication entre threads. La méthode « wait() » permet à une thread d’attendre l’arrivée d’un événement qui sera signalé par une autre thread grâce à la méthode « notify() ». Les méthodes « wait() » et « notify() » sont définies dans la classe « Object » et donc héritées par toutes les classes. Elles s’appliquent sur des objets. Ainsi, lorsqu’une thread attend un événement, elle attend qu’on la prévienne (qu’on la notifie) de l’occurrence de cet événement sur le même objet que celui sur lequel elle attend.

Principe de fonctionnement de « wait() » et « notify() »L’utilisation de « wait() » et « notify() » doit obligatoirement s’effectuer dans des méthodes synchronisées (ou instructions synchronisées) sur un même objet. En effet, si les séquences n’étaient pas synchronisées, le contenu de l’objet ne serait pas stable et donc la valeur de l’événement attendu serait indéterminée !

synchronized void attendreEvenement() {while( ! Evenement ) {

wait();// traitement à faire lorsque l’événement s’est réalisé

}}

L’exécution de la méthode « wait() » place la thread dans un Etat Bloqué tout en relâchant le verrou sur l’objet, permettant de libérer d’autre thread en attente sur ce

Brigitte Groléas 96

Page 97: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

verrou. Le test de la condition sur l’événement est effectué dans une boucle while car la notification implique le réveil de la thread bloquée mais n’implique pas nécessairement la réalisation de l’événement (plusieurs threads peuvent notifier sur un même objet pour des raisons diverses et variées).De l’autre coté, la méthode « notify » est invoquée par des méthodes qui modifient des données sur lesquelles d’autres threads sont susceptibles d’être bloquées en attente (waiting).

synchronized void signalerEvenement() {// Traitement Produisant l’événementnotify();

}

Brigitte Groléas 97

Page 98: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Exemple d’utilisation de « wait() » et « notify() »Reprenons l’exemple d’une file d’attente d’objets, en faisant en sorte que les threads consommatrices d’objets attendent l’arrivée d’objets dans la liste si celle-ci est vide.

class Element {Object obj;Element suivant = null;public Element( Object o ) {

obj = o;}

}

public class File {private Element tete = null; // premier de la fileprivate Element fin = null; // dernier de la file 

public synchronized void ajoute( Object obj ) {Element elt = new Element( obj );

if( tete == null ) { // si la file est videtete = elt; // elt est le premier

}else { // sinon

fin.suivant = elt; // elt après le dernier}fin = elt; // elt est le derniernotify();

}public synchronized Object retire() {

try {while( head == null ) {

wait();}

} catch( interruptExceprion e ) {return null;

}Element elt = tete; // prendre le premiertete = tete.suivant; // retirer le premierreturn elt.obj; // et le retourner

}}

Quand un élément est ajouté à la fin de la file, les threads qui attendent sont notifiées. Au lieu de retourner null lorsque la file est vide, la méthode « retire() » attend qu’une autre thread insère un élément. De cette façon, de nombreuses threads peuvent ajouter des éléments tandis que de nombreuses autres sont en train d’en retirer.

Brigitte Groléas 98

Page 99: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Détails des méthodes « wait() » et « notify() »Les méthodes « wait() », « notify() » et « notifyAll() » sont des méthodes de la classe Object. Elles opèrent sur la thread courante. Elles ne peuvent être invoquées qu’au travers d’un code synchronisé ayant acquis un verrou sur l’objet sur lequel elles sont appliquées. Toute tentative d’invoquer ces méthodes en dehors du code synchronisé qui a acquis le verrou sur l’objet provoquera la levée d’une exception « IllegalMonitorStateException ».

public final void wait( long milli ) throws InterruptedException; public final void wait( long milli, int nano ) throws InterruptedException;public final void wait() throws InterruptedException;Met la thread en cours d’exécution en attente jusqu'à ce qu’elle soit notifiée ou que le nombre de millisecondes (et nanosecondes) donné soit écoulé. Si le nombre de millisecondes vaut zéro, « wait( 0 ) » n’expirera pas et attendra jusqu'à ce qu’il y ait notification. « wait() » sans argument est équivalent à wait( 0 );

public final void notify(); public final void notifyAll();Notifie exactement une thread en attente. Si plusieurs threads sont en attente sur le même objet, « notify() » réveille celle qui a attendu le plus longtemps (ce n’est pas forcement celle qui est concernée par l’événement que l’on a voulu notifier). Si l’on est pas certain de la thread qui doit être réveillée, il faut utiliser la méthode « notifyAll() » qui se charge de réveiller toutes les threads en attente sur un objet..

Terminer l’exécution d’une Thread : la méthode « stop() ».Une thread fini normalement sont exécution et passe dans l’état Mort, lorsque sa méthode « run() » se termine. Toutefois, il est possible d’arrêter explicitement une thread en utilisant la méthode « stop() » appliquée à cette thread. La méthode « stop() » génère une erreur de type « ThreadDeath » sur l’objet thread sur lequel elle est appliquée. Comme « ThreadDeath » est une sous-classe de « Error » (et non une sous-classe de « Exception »), il n’est, en général, pas judicieux de capturer « ThreadDeath » (sauf pour faire une opération de nettoyage particulier qu’une clause finally ne pourrait gérer). Si d’aventure « ThreadDeath » est capturée dans la thread il est souhaitable de relancer l’erreur (par un throw ThreadDeath) pour que la thread meurt effectivement ! Lorsque « TreadDeath » n’est pas capturé, Java tue simplement la thread sans afficher aucun message d’erreur.

Brigitte Groléas 99

Page 100: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

Il est possible de générer une exception utilisateur à l’intention d’une thread en utilisant la forme « stop( Trowable e ) ». Cela peut être utilisé pour envoyer un message à une thread qui se chargera de capturer l’exception et de réagir en conséquence. Par exemple, cela peut permettre de réinitialiser une thread « à chaud » en cas de changement de données plutôt que de la tuer et d’en relancer une autre.

public final void stop(); public final void stop( Throwable e );La méthode « stop() » provoque l’arrêt de la thread en levant une erreur de type « ThreadDeath ». La méthode « stop( Throwable e ) » permet de lever une exception quelconque sur la thread cible.

Rendez-vous terminal : la méthode « join() ».Une thread peut attendre qu’une autre se termine en appliquant la méthode « join() » sur la thread dont on veut attendre la mort. Supposons qu’une thread effectue un certain calcul dans sa méthode « run() », il est alors possible d’attendre la terminaison de cette thread afin de récupérer le résultat du calcul :

class Tache extends Thread {private double Resultat;public void run() {

Resultat = calcul();}public double resulat() {

return Resultat;}private double calcul() {

// calculer quelque chose}

}class Programme {

public static void main( String argv[] ) {Tache t1 = new Tache();t1.start() ;// faire des choses pendant ce temps làtry {

t1.join();Sytem.out.println( "resultat=" + t1.resultat() );

} catch( InterruptedException e ) {Sytem.out.println( "tâche interrompue !" );

}}

}

Quand une thread meurt, son objet ne disparaît pas, et l’on peut ainsi accéder à son contenu.

Brigitte Groléas 100

Page 101: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

public final void join( long milli ) throws InterruptedException; public final void join( long milli, int nano ) throws InterruptedException;public final void join() throws InterruptedException;Attend que la thread finisse ou que le nombre de millisecondes (et nanosecondes) donné soit écoulé. Si le nombre de millisecondes vaut zéro, « join( 0 ) » n’expirera pas et attendra jusqu'à ce que la thread se termine. « join() » sans argument est équivalent à « join( 0 ) »;

Brigitte Groléas 101

Page 102: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

7. Les threads demons et groupes de threads

Les Threads démons et les Threads utilisateursChaque application démarre avec une thread utilisateur qui exécute la fonction main. Si la fonction main génère d’autres threads, celles-ci sont, par défaut, également des threads utilisateurs. L’application s’arrête lorsque toutes les threads utilisateurs sont terminées.Les threads démons sont des threads de faible priorité qui tournent en « tache de fond » en attendant des événements (garbage collector, rafraichissement d’écran, etc...). Contrairement aux Threads utilisateurs, les threads démons sont automatiquement tuées par le run-time Java lorsque l’application se termine (i.e. quand la dernière thread utilisateur se termine). Par défaut, une nouvelle thread hérite du statut (utilisateur ou démon) de la thread parente. Après l’instanciation d’une thread (new) et avant son démarrage (start), on peut modifier le statut d’une thread par la méthode :

public final void setDeamon( Boolean b ) throws IllegalThreadStateException; public final Boolean isDeamon();La méthode « setDeamon() » doit être utilisée avant le démarrage (start) de la thread sinon l’exception « IllegalThreadStateException » est lancée. Bien évidemment la méthode « isDeamon() » peut être utilisée à tout moment.

Groupe de threadsA sa création, une thread appartient forcément à un groupe de threads, objet de la classe « ThreadGroup ». Par défaut, une nouvelle thread appartient au même groupe que la thread parente et au départ la thread « main » appartient au groupe « main », qui est créé automatiquement par le noyau Java.Un groupe de threads peut être contenu dans un autre groupe de threads, ce qui introduit une notion de hiérarchie arborescente. L’intérêt des groupes de threads est de pouvoir exécuter des actions globales portant sur l’ensemble du groupe et des groupes descendants au lieu de devoir spécifier ces actions individuellement sur chaque thread. Le deuxième intérêt concerne la sécurité. En effet, une thread d’un groupe ne peut agir que sur les threads de son propre groupe ou des groupes descendants.

Brigitte Groléas 102

Page 103: CHAPITRE 13kernels.free.fr/divers/support/insta/java/java.doc · Web viewL’environnement de programmation est lui aussi portable : le compilateur est écrit en Java et la JVM est

Support Java

public ThreadGroup( ThreadGroup parent, String name ); public ThreadGroup( String name );Crée un nouveau groupe de Threads, avec le nom name (obligatoire), sous groupe de parent. Si parent est omis, le parent implicite correspond au ThreadGroup de la Thread courante.

public final String getName(); public final ThreadGroup getParent();public final boolean parentOf( ThreadGroup grp );Les 2 premières méthodes retournent le nom et le ThreadGroup parent. La troisième retourne true si le groupe est un parent de grp ou est grp lui-même.

public final void setDeamon( boolean b ); public final boolean isDeamon();Un groupe peut avoir le statut démon. Dans ce cas, il est automatiquement détruit quand il devient vide. Ce statut n’influence aucunement le statut des threads contenues dans le groupe qui peuvent tout à fait être démons ou pas.

public final synchronized void setMaxPriority( int prio ); public final int getMaxPriority();Permet de fixer une limite supérieure sur la priorité des threads contenu dans le groupe. Après avoir fixé une priorité maximum, toute tentative de donner à une thread une priorité supérieure au maximum du groupe est silencieusement tronquée à ce maximum. Cela n’affecte pas les threads déjà créées avec une priorité plus grande.

public final void checkAccess(); Lance une Exception « SecurityException » si la thread courante n’a pas le droit de modifier ce groupe ; ne fait rien sinon.

public synchronized int activeCount(); public synchronized int activeGroupCount();Retourne une estimation des threads ou des sous-groupes contenus dans ce groupe.

public int enumerate( Thread tab[], boolean recursif ); public int enumerate( ThreadGroup tab[], boolean recursif );public int enumerate( Thread tab[] );public int enumerate( ThreadGroup tab[] );Remplit le tableau tab avec les Threads (ou les ThreadGroup ) contenues dans ce groupe jusqu'à concurrence de la taille du tableau. Retourne le nombre d’éléments contenus dans le tableau. Si récursif est a true, « enumerate » parcourt récursivement tous les sous-groupes. Si récursif est omis, il vaut implicitement true.

public final synchronized void stop(); public final synchronized void suspend();public final synchronized void resume();Permet d’effectuer ces actions globalement sur toutes le threads de ce groupe et de tous ses sous-groupes.

Brigitte Groléas 103