Académique Documents
Professionnel Documents
Culture Documents
Vuibert Informatique
Java : de lesprit la mthode Distribution dapplications sur Internet 2e dition Michel BONJOUR, Gilles FALQUET, Jacques GUYOT et Andr LE GRAND
Conception de la couverture : Jean Widmer Contact : informatique@vuibert.fr Les programmes et exemples figurant dans ce livre ont pour but d'illustrer les sujets traits. Il n'est donn aucune garantie quant leur utilisation dans le cadre d'une activit professionnelle ou commerciale.
Toute reprsentation ou reproduction intgrale ou partielle, faite sans le consentement de l'auteur, ou de ses ayants droit, ou ayants cause, est illicite (loi du 11 mars 1957, alina 1er de l'article 40). Cette reprsentation ou reproduction, par quelque procd que ce soit, constituerait une contrefaon sanctionne par les articles 425 et suivants du Code pnal. La loi du 11 mars 1957 n'autorise, aux termes des alinas 2 et 3 de l'article 41, que les copies ou reproductions strictement rserves l'usage priv du copiste et non destines une utilisation collective d'une part, et d'autre part, que les analyses et les courtes citations dans un but d'exemple et d'illustration.
viii
3.4 3.5
ix
Importation des packages et des classes........................................98 Dclaration de types .....................................................................100 Dclaration dune classe ...............................................................100 Dclaration dune interface ..........................................................101 Dclaration de membres ..............................................................102 Dclaration dune mthode et dun constructeur .......................102 Cration dobjets ..........................................................................103 Exceptions.....................................................................................105 Processus et synchronisation ........................................................107
xi
15.4 Ajouter des menus aux fentres ...................................................204 15.5 Un gestionnaire dalertes..............................................................206 15.6 Invitation explorer .....................................................................208
xii
19.15 Srialisation et persistance des objets ..........................................261 19.16 Invitation explorer .....................................................................263
xiii
24.4 Introspection.................................................................................350
xiv
Glossaire ........................................................................ 483 Rfrences .................................................................... 491 Liste des applets ............................................................ 493 Liste des applications .................................................... 495 Liste des tableaux .......................................................... 497 Index ............................................................................ 501 Le CD-ROM du livre ........................................................ 513
Remerciements
Nous tenons remercier ici : Ian Prince, lorigine de notre intrt pour les hypertextes et les systmes distribus. Nos collgues de travail pour les changes sur Java autour dun caf. Les participants notre premier cours Java pour leur patience, leur intrt et leurs remarques constructives. Les tudiants qui ont travaill avec nous dans nos projets autour de Java et des bases de donnes. Nos familles et nos amis qui ont support notre Javamania.
xvi
fdfdfdfdfdfdf
Gilles Falquet, docteur s sciences mention informatique, est actuellement matre denseignement et de recherche lUniversit de Genve. Il mne des travaux de recherche sur les modles et technologies des bases de donnes et hypertextes. Jacques Guyot, docteur s sciences mention informatique, est charg de cours lUniversit de Genve et responsable de linformatique du dpartement des finances de Montres Rolex S.A. Il sintresse lintgration des traitements et des donnes dans le cadre du Web. Andr Le Grand, docteur en informatique de lUniversit de Montpellier II, est actuellement matre-assistant lUniversit de Genve et lInstitut de Hautes tudes en Administration Publique (Lausanne). Ses travaux portent sur les mthodes de conception orientes objet et lingnierie des systmes dinformation.
avril 95
xvii
17 sep 95 dc 95 jan 96 fv 96 Naissance de No Prsentation de LAZY la 4me confrence WWW Boston Test de JavaScript Ajout de la syntaxe de Java au BNF Club Dmarrage du JavaCorner cuiwww.unige.ch/java mars 96 Participation au cours du 3me cycle romand : le Web et ses outils Portage de LAZY sur le WebServer dOracle avril 96 mai 96 Outils hypermdia sur le dictionnaire Oracle Dbut du projet FNRS (Fond national de la recherche suisse) pour ltude de la gnration dhypertextes partir des bases de donnes Organisation dun cours sur Java juin 96 Etude des spcifications de JDBC 1.0 Compilateur de LAZY en Java Gnrateur et gnration dune documentation hypertextuelle pour Java dans le BNF Club 1997 1998 Cours et Evanglisation Java ! Implantation dune uvre dart en Java avec lartiste Herv Grauman, pour lOffice fdral de statistique en Suisse (www.collectivepainting.ch) Utilisation de Java et JDBC dans lenseignement et la recherche (structures de donnes, interfaces de systmes dinformation) mai 98 oct 98 Ecriture dune applet pour dessiner les diagrammes syntaxiques pour une spcification BNF Ecriture dun gnrateur doutils syntaxiques en pur Java
Introduction
Internet, FTP, TCP/IP, E-Mail, autoroutes de linformation et les derniers en date WWW, HTML, HTTP, XML, IIOP, CORBA, Java sont autant dacronymes remplissant les discussions et les revues dinformatique. Utiles ou simples gadgets ? Technologies sres ou de transition ? Quels nouveaux domaines mergent? Comment linformatique est-elle modifie? Autant dinterrogations qui sont souleves. Rpondre lensemble dentre elles ncessitera certainement plusieurs annes, demandera ce que la socit shabille de ces nouveaux atours, smerveille, seffraie et finalement intgre ces nouvelles technologies productrices de nouvelles valeurs. notre avis, les informaticiens doivent prendre conscience de ces enjeux sociaux et dvelopper une thique de lutilisation de ces nouvelles technologies1. Technologie sans conscience... Notre propos restera plus prosaque et moins polmique : comment utiliser efficacement Java, ce langage de programmation? Notre premire partie, consacre lesprit Java, situe le langage dans son contexte et dcrit la transition avant Java - aprs Java . Nous y introduisons galement les concepts essentiels pour la programmation distribue sur Internet ou pour lanimation, par exemple. La seconde partie dcrit la forme de Java, il sagit ici de dcrire la syntaxe de Java et la smantique associe. Le langage Java tant relativement simple, les rgles de grammaire sont peu nombreuses. La troisime partie sattache examiner le fond de Java. Nous tudierons un ensemble de problmatiques telles que : comment dessiner, animer ou communiquer, et proposerons des solutions programmes en Java. Le lecteur trouvera travers celles-ci de nombreux exemples de la syntaxe Java et pourra ainsi la matriser par la pratique. De plus, il abordera par ces problmatiques lutilisation
1. Le lecteur trouvera la page 491 des rfrences que nous trouvons intressantes.
xx
Introduction
des classes standard de Java et lapplication des diffrents concepts propres la programmation oriente objet. La quatrime partie du livre est ddie la mthode. Matrisant la syntaxe, la smantique et les classes standard de Java, le programmeur doit alors faire face la complexit de ses propres crations. Il doit effectuer des choix de conception pour ses objets qui ne seront pas sans importance quant leur rutilisation, leur gnricit, leur testabilit, etc. Cette partie comporte galement une description des mthodes de scurit de Java et de linterface de programmation dapplications bases de donnes JDBC (Java DataBase Connectivity) propose par Sun, Cette partie sachve sur llaboration dapplications distribues avec RMI et CORBA. En annexe on trouvera : la grammaire Java en BNF, une comparaison Java C++, une description du langage HTML et une prsentation de JavaScript.
xxi
Smalltalk, C++, etc. Ces environnements ont pour premier objectif de faciliter la recherche dobjets et de mthodes aidant la rsolution dun problme. Comme nous le constaterons dans la suite de ce livre, la syntaxe et les concepts de Java sont relativement simples. Par contre, la richesse de ses packages demande un investissement certain. On ne peut devenir un bon dveloppeur Java sans les connatre, ils sont incontournables; Java, par un effet de rebond, aprs avoir t Applet est devenu Servlet : la problmatique initiale tait dans le contexte statique du Web, de pouvoir excuter du code sur un poste client. La mobilit du code Java soutenue par le slogan Write once, run everywhere (cris-le une fois, excute-le partout) tait indispensable pour gommer la varit des postes clients connects sur le Web. Mais il existe une varit identique du cot des serveurs: les mmes arguments dconomie de rcriture ont sduit les dveloppeurs dapplications sur serveur. Du coup, Java a quitt son image de gadget pour animer les pages Web; Java sest enfoui au cur du silicium, dans des processeurs spcialiss, dans des cartes puces, dans une bague (JavaRing). Cette cristallisation de la machine virtuelle Java sest accompagne de lcriture dun systme dexploitation, le Java OS, et de la publication dune norme dinterconnexion de composants (JINI). Cette incrustation de la technique au cur dobjet quotidien est nos yeux le rel enjeu de Java et des techniques de la programmation distribue utilisant du code mobile. En effet, mme si vous possdez un ordinateur, vous possdez galement une quantit dautres objets attendant un ajout dintelligence et une connexion au reste du monde. Lincorporation dans le quotidien des processeurs Java et limage de celle des moteurs lectriques si bien intgrs dans les objets que lon a oubli leur existence; Java, travers lEntreprise Java Beans (EJB), devient le cadre conceptuel pour la production dapplications partir de composants. Ici, se dvoile lultime Graal de linformatique. Non seulement, il est possible dutiliser le code Java universellement, mais en plus il serait possible de le rutiliser. Avec les Beans, il est possible de dvelopper des petits composants comme des boutons ou des champs de saisie qui sont assembls dans une interface graphique; les messages mis sont connects aux actions propres lapplication. Cela constitue le degr zro de la rutilisation. Lintrt de la rutilisation crot avec la taille des composants. Avec EJB, il sagit de crer des gros composants. Si pour crer un magasin virtuel, on trouve les composants: gestion des
xxii
Introduction
clients, gestion des fournisseurs, gestion des commandes, gestion des expditions, gestion des paiements par carte, gestion des catalogues alors on peux effectivement assembler et paramtrer les rgles de gestion propres son entreprise. Le projet San Fransisco dIBM est un prototype de ce que peut devenir cette orientation. EJB sera sans doute le modle adopt dans larchitecture CORBA par les socits actives dans le domaine des connecticiels. Mais crire une nouvelle version dun livre nest pas seulement constater que lon a choisi un bon sujet. Cest pour Java 2 : rviser la syntaxe du langage (classe interne, nouveaux usages des modificateurs, etc.); adapter les exemples aux nouvelles API; utiliser la notation UML (Unified Modeling Language) pour les graphes de classes; dcrire le nouveau modle dvnements par dlgation ; dcrire lusage des classes collections (nouvelles classes de java.util) pour crer des structures de donnes; dcrire lutilisation des fichiers archives (jars); introduire les nouveaux composants dinterface SWING; dcrire les composants logiciels JavaBeans; dcrire les mcanismes dintrospection, de srialisation, etc.; ajouter un exemple complet dinteraction avec une base de donnes en utilisant JDBC; ajouter la cration dapplication rpartie avec RMI (Remote Method Invocation); introduire lutilisation de Java dans une architecture CORBA. Nous avons conserv pour ces ajouts le style concis et conceptuel de la premire version. Nous avons limin les annexes sur lAPI. En effet, lexplosion du nombre de packages, de classes et de mthodes de Java 2 rendait impossible limpression papier de tels index. La documentation comprime de Java 2 tient dans seize millions de caractres, notre livre dans peine un: il vous faut donc considrer ce livre comme une synthse des connaissances ncessaires et utiles et vous rfrer constamment la documentation pour les dtails.
xxiii
Conventions utilises dans cet ouvrage Le texte est en police Sabon. Un mot important est crit ainsi. Dans le texte, un mot-cl, une classe ou une mthode de Java est crit ainsi. Le code Java est en police Courrier :
// ceci est un commentaire dans une ligne de code.
Partie I
Lesprit Java
Laccs ces diffrents concepts, le sujet, la finalit et linfini, se fait manifestement travers celui de conscience. Voil donc, au regard de toute philosophie qui se dveloppe une mfiance vis--vis de limage informatique de notre esprit, la clef de lirrductible cart! Grard Chazal, Le miroir automate.
Chapitre 1
Avant Java
La partie la plus saillante dInternet est le World Wide Web (WWW ou plus simplement Web). Celui-ci matrialise le mtissage de deux concepts : celui des rseaux de communication interconnects (Internet) et celui dhypertexte. Chacun de ces concepts a une origine et des objectifs qui lui sont propres, tandis que leur union ouvre des perspectives absolument novatrices et impensables voil quelques annes encore (le premier outil Web en mode texte a vu le jour en 1991 au CERN). Nous allons maintenant dfinir quelques concepts afin de prparer la transition vers Java... et de clarifier notre discours.
le dcoupage des flux dinformation initiaux en paquets de taille standardise et leur rassemblage ultrieur. Les rseaux emprunts lors dune communication assurent le transfert des paquets IP. Ceux-ci sont encapsuls (au dpart et en quittant une passerelle IP) par le protocole du rseau qui les transmet ; ils sont ensuite dcapsuls lorsquils quittent ce rseau (en entrant dans une passerelle et en arrivant destination). Le succs de ce protocole est principalement d la relative simplicit de ralisation des passerelles IP. La disponibilit de telles passerelles sur de nombreux types de machines a favoris lutilisation de IP dans des environnements htrognes.
FTP Telnet SMTP SNMP application prsentation session
TCP
transport
IP
Ethernet
...
Arpanet
Tokenring
Interconnexion de rseaux
De plus, des serveurs spcialiss dans le catalogage des documents situs sur diffrents sites FTP ont t dvelopps. De tels serveurs (comme ARCHIE, par exemple) comportent une base de donnes permettant lindexation dun nombre considrable de documents. Telnet (Terminal Protocol) est un protocole daccs un hte en mode terminal . Il permet un utilisateur de se connecter distance des serveurs de calcul, des banques de donnes ou dautres services hbergs par des ordinateurs centraux. NNTP (Network News Transfer Protocol) permet la constitution de groupes de communication (newsgroups) organiss autour de thmes (loisirs, politique, culture, etc.). Une architecture hirarchique de sites miroirs a galement t mise en place afin de limiter le volume dinformations distribuer. SMTP (Simple Mail Transfer Protocol) dfinit quant lui un service de base en matire de courrier lectronique. SNMP (Simple Network Management Protocol) est un protocole charg de la gestion du rseau. Il est gnralement utilis pour la communication avec les systmes lectroniques tels que passerelles, routeurs, multiplexeurs, etc.
organisation, entreprise; dpartement; hte. Des serveurs de noms tablissent un niveau logique au-dessus du niveau physique des adresses, afin de supporter des rorganisations au niveau des rseaux et des machines. Ainsi, cui.unige.ch et cuiwww.unige.ch sont deux adresses logiques dun mme hte du Centre universitaire informatique de luniversit de Genve, dont ladresse IP est 129.194.70.1. Dans le cas du courrier lectronique, le format gnralement utilis est la concatnation dun nom dutilisateur et de ladresse IP dun hte hbergeant un serveur SMTP : johnny@rock.musique.fr pourrait correspondre ladresse de qui vous savez. Il nest pas ncessaire de dmontrer limportance prise en quelques annes par Internet et le Web.
Communications internationales
Rseau - rgion
Hypertextes
1.2 Hypertextes
Lide initiale de liens associatifs entre des donnes et des documents dorigines diverses est attribue Douglas Engelbart, dans les annes 50. Alors directeur de lARC (Augmentation Research Center of Stanford Research Institute), D. Engelbart avait pour but de crer des logiciels capables de supporter le travail coopratif et de faciliter la communication entre les utilisateurs. On notera au passage que ce mme programme de recherche tudiait galement les crans multifentres ou encore lutilisation de la souris pour manipuler des complexes informationnels. Le lien associatif est constitu dune rfrence (la cible) et dune ancre (la source). La rfrence et lancre rsident normalement dans des nuds informationnels (textes, images, voire sons) diffrents. Il est ainsi possible de tisser une vritable toile reprsentant les liens smantiques entre diffrentes informations. Lutilisateur peut alors choisir son chemin dans ce rseau selon ses intrts et ses objectifs, naviguant entre les nuds en suivant les liens (voir figure 1.1). Des outils tels que HyperCard sur Macintosh ou les systmes de documentation et daide en ligne des logiciels Excel, Oracle ou FrameMaker nous ont familiariss avec cette approche navigationnelle o lon doit cliquer pour passer dune explication une autre, suivant les besoins. Plus rcemment, de nombreux CD-ROM ont t raliss selon ce paradigme, utilisant des liens hypertextuels pour prsenter un sujet en proposant de nombreux itinraires de parcours. Le contenu des nuds est dsormais tendu dautres types de donnes tels que : image, graphique, vido, son, etc., faisant voluer le principe de lhypertexte vers celui de lhypermdia.
1.3 Web
Imaginez un instant que vous ayez disposition un hypertexte et que les nuds de celui-ci soient rpartis sur les diffrents htes dInternet, des liens hypertextuels permettant la navigation dun nud lautre, dun hte lautre. Le contenu des nuds serait vari, constitu aussi bien dimages, de textes, danimations ou de sons. Ne rvez plus, vous ne serez pas linventeur de ce systme ! En effet, le Web (World-Wide Web [3]) correspond trait pour trait la description ci-dessus. Restent encore dfinir quelques notions de manire plus prcise. Le Web peut tre vu comme le mtissage de deux toiles (Web en anglais) : une toile physique, constitue des rseaux interconnects formant Internet; une toile smantique, constitue des rseaux dhyperliens.
Langage de programmation Un langage possde une syntaxe et une smantique qui Il faut un compilateur pour Par exemple Java
Smantique
Programme
Le compilateur Java
Ce mtissage entre liens physiques et liens logiques naurait certainement pas suffit lui seul dclencher le vritable ouragan Web que lon connat aujourdhui. Cest sans aucun doute le dveloppement de logiciels de navigation (browsers, butineurs) trs simples utiliser et disponibles (souvent gratuitement) sur les plateformes les plus rpandues (PC, Macintosh, puis Unix) qui a vritablement mis le feu et attir le grand public. Les butineurs les plus rpandus (Mosaic, Navigator, MacWeb, WinWeb, Explorer, HotJava, etc.) se basent tous sur des principes dinterface assez simples que lon peut rsumer ainsi : chaque fentre affiche le contenu dun nud dinformation (texte format, images, etc.); des zones sensibles sont places dans le contenu du nud, signales de manire visuelle (exemple : texte soulign en rouge ou image clignotante); ces zones sensibles sont les ancres de liens hypertextuels (voir point 1.2). Lorsque lutilisateur active une ancre (par un clic de la souris), le nud rfrenc par le lien est tlcharg depuis la machine qui lhberge vers la machine de lutilisateur, cela travers le rseau; le contenu de ce nud est ensuite affich dans la fentre, matrialisant ainsi le nouvel emplacement de lutilisateur dans lespace Web.
Web
Il faut encore prciser que les butineurs ont un rle passif en ce qui concerne la prsentation des informations : les indications de formatage, de dfinition des ancres ou dautres facilits dinteraction sont entirement dtermines dans le nud. Cette particularit a permis le dveloppement de butineurs compatibles entre eux, ne diffrant que par les fonctionnalits supplmentaires quils offrent aux utilisateurs. Certaines de ces fonctionnalits sont destines assister le cybervoyageur dans son priple travers le Web : dition de bookmarks, listes de nuds regroups par lutilisateur selon ses propres thmes dintrt; gestion de lhistorique des nuds visits; gestion dun cache (stockage local dlments frquemment rencontrs : icnes, logos, afin dviter leur tlchargement systmatique). Les points suivants prsentent trois lments importants du Web, savoir : HTML : le langage de description du contenu des nuds dinformation; URL : le format de nommage des nuds; HTTP : le protocole dinteraction entre un client (le butineur) et un serveur (lhte qui hberge le nud dsir).
HTML
HTML (HyperText Markup Language) est un langage de description du contenu et de la structure dun nud dinformation. HTML est lui-mme driv dun ensemble de styles et de descriptions issu dune norme appele SGML (Standard Generalized Markup Language). Pour simplifier notre discours, admettons que le nud dinformation sur lequel nous allons travailler soit un document. Nous pouvons alors dcrire : des lments de structure du document : son titre, ses paragraphes, sousparagraphes, listes numrotes, images; des lments de formatage du contenu : texte en italique, tabulations. HTML permet dexprimer ces diffrentes rgles de structuration et de formatage dune manire indpendante de la machine et du logiciel utiliss pour afficher le document. cet effet, HTML dfinit des dlimiteurs (ou balises) que lon introduit dans le contenu dun document et qui seront dtects et interprts par le logiciel daffichage. Lexemple suivant montre les possibilits de base de HTML :
<TITLE>Jump in the Web</TITLE> <H1>Once Upon a Time ...</H1> Welcome to the world of HTML this is the first paragraph.<P> this is the <B>second</B> and <I>some URL</I><P> <A HREF="http://www.oracle.com"> at Oracle </A><P>
10
La figure 1.1 ci-dessous reproduit notre document tel quil apparat sur un Macintosh, en utilisant le butineur Mosaic. La tche du butineur consiste charger le code HTML du document travers le rseau et en excuter les commandes afin dafficher le document format.
Les dlimiteurs (tags en anglais) sont entours de crochets <> et vont en gnral par paire : <XXX> et </XXX>. Dcouvrons certains dentre eux en tudiant le code HTML correspondant au document ci-dessus : donne un titre au document.
<TITLE>Jump in the Web</TITLE> <H1>Once Upon a Time ...</H1>
donne un en-tte une partie du document (niveaux 1 6). indique la fin dun paragraphe.
Welcome to the world of HTML this is the first paragraph.<P> this is the <B>second</B> and <I>some URL</I><P> <A HREF="http://www.oracle.com"> at Oracle </A><P>
dfinit une rfrence et son ancre. Cest ainsi que lon dclare des liens hypertextes.
Web
<IMG SRC="smile.gif">
11
Nous consacrons lannexe D la dfinition des principaux dlimiteurs de HTML. Lintrt de HTML pour un programmeur Java rside dans le fait quun programme Java peut tre invoqu depuis le contenu dun document HTML. On parle alors dapplet Java (voir chapitre 10, page 123).
URL
Un URL (Uniform Resource Locator) permet de localiser de manire unique une ressource (un nud dinformation) sur Internet. Il identifie la fois : le protocole utiliser pour charger la ressource (file, ftp, http, etc.); la machine hte (adresse IP, ventuellement avec un numro de port); le chemin daccs la ressource (arborescence du systme de fichiers); le nom de la ressource (nom de fichier). Le format complet est le suivant :
protocole://hte.organisation.domaine[:port]/chemin/nom
Ce format respecte les conventions de nommage mentionnes au point 1.1. LURL peut encore tre tendu afin dindiquer le nom dune sous-rfrence interne au nud, laide du suffixe (#sous-rfrence), comme dans lexemple suivant :
http://cuicui.unige.ch:9876/db/java/livre/preface.html#merci
Cela permet une navigation lintrieur dun mme nud, comme par exemple des renvois entre paragraphes dun mme document. Nous verrons quun URL peut galement servir dmarrer une application et lui fournir des paramtres, permettant ainsi dinterroger une base de donnes ou dinteragir avec un systme complexe distance.
HTTP
HTTP (HyperText Transfer Protocol) est un protocole destin aux changes entre un client Web (butineur) et un serveur (appel serveur HTTP ou serveur Web ) hbergeant des nuds dinformation. Le serveur HTTP et lensemble des nuds forment ce que lon appelle communment un site Web . Fonctionnement du serveur Le serveur HTTP rceptionne les requtes des clients (exprimes laide dURL) et leur retourne le contenu des nuds rfrencs. Il sert galement de passerelle (gateway) vers des applications invoques par le client. De plus, il gre les droits daccs certains nuds et rcolte des statistiques sur lutilisation des services (nombre de requtes, provenance des clients ou nuds les plus demands).
12
Loffre en matire de serveurs HTTP est assez importante, des systmes ayant t dvelopps pour les principales plateformes : Unix, Windows, Macintosh. La mise en uvre dun serveur HTTP est relativement simple. Nanmoins, il faut distinguer les deux cas suivants, trs diffrents en matire de scurit, de charge (nombre daccs simultans)... et de cot de licence : installation intranet (locale), accessible uniquement depuis les machines du rseau interne lorganisation ou lentreprise; installation Internet, accessible (potentiellement du moins) depuis nimporte quelle machine connecte Internet. Ainsi, le cot dun serveur HTTP varie fortement selon la configuration, de quelques centaines de francs franais pour un serveur lmentaire sur PC plusieurs centaines de milliers de francs pour une installation Internet sur une machine UNIX multiprocesseurs.
Architecture client-serveur
13
convertisseurs existent pour traduire en HTML des documents issus de Word (format RTF), FrameMaker (format MIF), LaTeX, etc. Dans le cas des images, de nombreux utilitaires permettent de convertir les fichiers issus de logiciels de dessin (CorelDraw, Canvas, Painter, etc.) au format GIF, trs rpandu sur le Web.
Le client nest utilis que pour la prsentation (par exemple avec X11).
2 3
Le client est un serveur de prsentation intgrant le contrle de la logique de laffichage. Les traitements sont rpartis entre le client et le serveur (par exemple les procdures PL/SQL dOracle sexcutant sur le client, dans les forms et dans le SGBD serveur). Le serveur est un pur serveur de donnes (une base de donnes sans procdures stockes). Excel + ODBC* EIS (Executive Information System) + BD locale*.
Donnes
Donnes
14
Type 6 Activit sur le serveur Activit sur le client Donnes Traitements Prsentation Description
Les principaux problmes rencontrs dans la mise en uvre du client-serveur sont : la difficult de rpartition de lactivit entre le serveur et le client; cette rpartition est difficile effectuer a priori, lidal tant quelle soit vue comme une optimisation des performances. Cela nest possible que si le langage de programmation est identique sur le serveur et sur le client (PL/SQL par exemple) ou si lensemble de lapplication est obtenu par gnration (avec NSDK de Nat system, par exemple). Lutilisation doutils tels que PowerBuilder ou SQL-Windows introduisent une rupture de langage entre le serveur et le client qui peut rendre cette tche ardue et/ou coteuse en temps de reprogrammation; le cot de distribution des logiciels (versions) et la complexit de la gestion des configurations; gnralement, seul le code excutable du logiciel est distribuer sur le client (run-time) ainsi que les gestionnaires de rseaux. Cette tche peut devenir un cauchemar qui est fonction de nombreux paramtres : N : nombre de postes clients; A : nombre de versions actives du SGBD; B : nombre de versions actives du gestionnaire dcran; C : nombre de versions actives du systme dexploitation client; D : nombre de protocoles rseaux utiliss. Admettons que la complexit soit gale au produit de ces variables. En dbut de projet, on estime les valeurs A, B, C, D 1. La complexit est donc celle du nombre de postes clients. Mais aprs quelques mois ou annes, A, B, C, D ont gnralement pris des valeurs entre 1 et 4... Do une augmentation de la complexit que nous vous laissons calculer; la faible portabilit; nous navons rencontr aucun gnrateur dapplications ne ncessitant pas de retravailler les documents gnrs, bien quils se dclarent tous multicibles. Il est donc difficile de faire cohabiter des communauts dutilisateurs ne partageant pas les mmes types de postes de travail.
15
Le client-serveur reprsente nos yeux une tape transitoire entre larchitecture terminaux en toile autour dun ordinateur central et celle du client universel et du serveur universel baignant dans lintranet/Internet . Cette tape aura essentiellement permis dinstaller les rseaux dans les entreprises.
Langages volus
Lintroduction du langage FORTRAN dans le domaine scientifique et du COBOL pour les applications de gestion marque larrive des langages volus. Ces langages permettent au programmeur de sexprimer dans des termes plus proches de son propre langage, et non plus laide de codes correspondant aux diverses instructions excutables par la machine utilise. Le COBOL introduit galement la structuration hirarchique des donnes.
Langages structurs
Llargissement du champ dapplication de linformatique conduit dvelopper des programmes de plus en plus grands et de plus en plus complexes grer. La programmation structure introduit un ensemble dinstructions de contrle (si alors sinon, rpter jusqu, etc.) permettant dexprimer un algorithme en les combinant entre elles et surtout dliminer les instructions de saut sauvages (goto), jusqualors omniprsentes. Chaque bloc dinstructions possde dsormais un seul point dentre et un seul point de sortie, ce qui facilite grandement la lecture et la comprhension des programmes. Le typage strict des donnes est galement introduit, permettant de dtecter ds la compilation des erreurs graves pouvant conduire la corruption de la mmoire. Algol, puis Pascal et C ont grandement contribu la diffusion de la programmation structure. La mthode de dveloppement sous-jacente la programmation structure est la dcomposition des problmes en sous-problmes par raffinements successifs, appele aussi approche descendante (top-down).
Langages modulaires
Toujours dans le but de matriser des logiciels dont la taille devient considrable (plusieurs millions de lignes dinstructions), des langages comme Modula puis
16
Ada mettent en avant le concept de programmation modulaire. Un module regroupe des sous-programmes et des donnes qui ont un but commun, que ce soit la gestion dun type de donnes, dun priphrique, dune fonction complexe du systme, etc. Lide de base de cette approche est de construire les programmes par assemblage de modules.
17
lhritage multiple. La simplicit de Java et le large support dont il jouit dj pourrait bien en faire le Pascal de la fin du sicle, cest--dire le langage qui amne la programmation objet non seulement chez les dveloppeurs professionnels mais aussi chez tous ceux qui veulent sinitier la programmation sans ncessairement en faire leur profession.
Chapitre 2
Rvolution an 4 : Java
Java nest plus radicalement nouveau, il sinscrit dans la continuit de lvolution des langages. Par contre, ses capacits concernant la distribution dapplications sur Internet en font un outil rvolutionnaire. En quatre ans, il aura aussi affirm son ambition de remplacer C++.
20
Cette orientation objet nest pas en soi la qualit principale de Java (il existe des centaines de langages objets ayant ces proprits!). Les qualits de Java rsident dans lassainissement effectu par ses concepteurs au niveau de limplantation des concepts du langage. Ces choix dimplantation ont t guids dans Java par des objectifs de scurit, de sret de programmation, de portabilit, de distribution et de performance.
Caractristiques principales
21
les processus en cours) et une liste de ceux qui ne le sont plus. Ces derniers, dsormais inutiles, peuvent donc tre limins de la mmoire par un processus spcialis (le garbage collector ou plus potiquement ramasse-miettes). Afin dviter lmiettement de la mmoire, on peut dplacer des objets dans la mmoire, puisque toutes les rfrences un objet sont connues. Java utilise cet effet des algorithmes performants de nettoyage et de compactage de la mmoire, excuts paralllement au droulement normal du programme. Le prix payer pour cette optimisation de la mmoire est de quelques pour cent sur la performance gnrale du programme (dans les applications critiques, le programmeur peut dsactiver et ractiver le mcanisme volont). Nanmoins, les bnfices sont normes : le programmeur na plus besoin de dsallouer des objets devenus inutilisables; mais surtout le risque derreurs portant sur des objets encore rfrencs mais dj supprims est limin. Ainsi, nous ne devrions plus entendre : Je croyais ne plus avoir besoin de cet objet et je lai supprim, mais javais oubli quil tait rfrenc par cet autre objet, vous comprenez, cest tellement complexe, une erreur est vite arrive et le compilateur na rien dit. Notons enfin que de telles erreurs, responsables dun grand nombre de crash de programmes, sont extrmement difficiles dtecter car elles ne sont pas systmatiquement reproductibles.
22
23
jets. Ds lors, comment traduire la ralit en objets? reste la question primordiale, laquelle nous tenterons par ailleurs de rpondre dans la partie IV.
24
tion). Le programmeur tant dcharg des responsabilits de gestion de la mmoire, il peut mieux se concentrer sur lactivit de lobjet et sur la qualit de sa conception. Linterprtation par une machine virtuelle et le chargement dynamique permettent dviter des phases de compilation et ddition de liens qui peuvent devenir trs lourdes ds que le projet atteint une certaine taille. Le compilateur, avec sa vrification stricte du typage, permet lui aussi de dtecter de nombreuses erreurs de programmation (passage de paramtres, appel de mthodes, etc.). Java possde galement des mcanismes assez subtils en ce qui concerne le rglage de la visibilit et de lhritage entre classes. Ces mcanismes peuvent tre pleinement utiliss pour dvelopper des logiciels complexes et de taille importante, en appliquant les apports mthodologiques du gnie logiciel.
Java est sr
La scurit, dans un environnement compltement distribu comme le rseau Internet, est une priorit absolue. Il est impensable de tester tous les programmes avant de les charger, de certifier toutes les sources et tous les serveurs du rseau. La seule solution est que le poste de travail se protge lui-mme. Lencapsulation de lexcution du code dans une machine virtuelle permet la portabilit par rapport la machine physique, mais elle assure aussi un dcouplage par rapport aux ressources (mmoire, systme de fichiers, canaux de communication) de cette dernire. Lapplication, une fois charge, est enferme dans la machine virtuelle et na donc pas directement accs aux instructions de la machine physique, ni ses ressources. Chacune de ces ressources sera alors vue comme un service de la ma-
Code mobile
25
chine virtuelle. Lutilisateur peut ainsi rgler en tout temps les capacits de sa machine virtuelle (donc des applications charges lintrieur), en fonction du degr de confiance quil a envers le serveur ou la socit qui a produit le programme : pour un jeu sduisant, il peut ne donner au programme que le droit de sexcuter; pour grer son compte dpargne, il peut autoriser le programme mis disposition par sa banque crer un fichier local des transactions. Atteindre ce degr de confiance demande une grande rigueur, la machine virtuelle devant se mfier de tous les programmes qui sont chargs. A cet effet, elle effectue sur chacun dentre eux une srie de tests (voir chapitre 27) afin de prouver un certain nombre de proprits attestant que lexcution des bytes-codes ne peut avoir un comportement cach (virus, etc.). De plus, lespace des noms du code est isol de celui de sa provenance; il est ainsi impossible quun objet se substitue un autre. Enfin, le code est test par rapport aux droits qui lui sont attribus (lire/crire des fichiers locaux, communiquer localement/ lextrieur, etc.). Ces trois qualits robustesse, portabilit et sret sont celles qui vont assurer le succs futur de Java.
26
Prsentation
Prsentation Traitements Prsentation Traitements Prsentation Donnes Traitements Prsentation Donnes Traitements Prsentation
Donnes
Au fond, la typologie nest plus classifiante et le mode de travail sera un mlange de tout, sur le client et sur le serveur.
Si nous rexaminons les difficults rencontres dans la mise en uvre du clientserveur (voir point 1.6), nous constatons que : la rpartition de lactivit ne pose pas de problme : il est possible de transfrer le code Java du serveur vers le client. Le contenu des documents HTML dtermine ce que le client doit excuter; le cot de la distribution diminue fortement : le client charge lapplication lorsquil charge le document, obtenant ainsi la dernire version de celle-ci. Le cot de distribution se rsume au cot de transfert, celui-ci
Code mobile
27
pouvant tre rduit grce lutilisation dun systme de cache dans le butineur et de miroirs diminuant les distances et augmentant les capacits daccs. Seul le butineur doit tre install sur le client; la portabilit est maximale, autant du ct des clients qui ne connaissent pas les dtails dimplantation des serveurs que du ct des serveurs qui ne connaissent pas les configurations matrielles des clients ou leur systme dexploitation. Le trio Java, BD et Web (y compris TCP/IP) remplit toutes les cases de la typologie. Les serveurs et les clients y acquirent des statuts duniversalit qui les rendent indpendants. La logique du couple client-serveur est remplace par celle dun serveur accessible par tous les clients et dun client connectable sur tous les serveurs.
28
pes de contenus, le producteur de document peut choisir parmi les codes disposition celui qui convient en fonction du type de contenu quil veut gnrer ou animer.
Code mobile
29
Hypertextes Web
Les bases de donnes sont la mmoire dInternet; en effet, il est impensable de grer un grand nombre de documents (plusieurs milliers de pages HTML sur un mme serveur) sans recourir une base de donnes. La gestion des liens (URL), des droits daccs, de la mise jour des donnes, la construction des index sont simplifies grce elles. De plus, la base de donnes constitue galement un moteur de recherche et de synthse de documents. Les hypertextes dfinissent linterface de prsentation et de navigation entre des documents qui contiennent des donnes, du code mobile et la logique de lapplication. Ainsi, lhypertexte permet dinscrire dans les liens une logique dapplication. Le parcours des liens peut se substituer lactivation de boutons ou darticles dans un menu. Le code mobile dfinit le comportement des objets. Il fait passer un document de ltat statique ltat dynamique en spcifiant des fragments de comportement. On peut alors imaginer qu la description des donnes sera ajoute une description des fragments de comportement, sassemblant pour tre smantiquement pertinents. Par exemple, si lon souhaite grer ses emprunts la banque, le fragment de code dcrivant une calculatrice de gestion damortissement sera charg et prsent en mme temps que ltat de ses comptes.
1. Ces deux points de vue couvrent ce que lon appelle le network-computing.
30
Les documents affichs seront de moins en moins stocks dans des fichiers. Ils seront le rsultat de la synthse : des donnes stockes dans la base de donnes; des fragments de code mobile associs aux types de donnes ; des droits de lutilisateur par rapport son rle; du contexte de lutilisation; du chemin parcouru dans lhypertexte. ... Restent imaginer des mthodes de conception et de dveloppement qui tiennent compte de cette nouvelle donne.
Chapitre 3
3.1 Outils
Nous allons rapidement passer en revue les diffrentes situations dutilisation de Java, quil sagisse de dveloppement en local ou reli Internet.
32
Dautres outils tels que courrier lectronique, transfert de fichiers, compression/ dcompression, encryptage (PGP), etc., peuvent tre utiles.
O trouver Java
33
Nous verrons au paragraphe 16.3 quil est galement possible dexcuter une applet comme une application.
34
Windows NT; Windows 95-98; MacOS. Vous pouvez le charger avec sa documentation depuis le site suivant :
http://java.sun.com/
Contenu du JDK
Le kit de dveloppement contient : un compilateur : le programme qui va traduire vos fichiers de texte source Java en byte-code; un viewer : le programme qui interprte vos fichiers byte-code; lAPI Java : un ensemble de classes qui vous permettront de dvelopper vos programmes ; une documentation : un ensemble de fichiers HTML qui constitue une aide indispensable la bonne comprhension de lAPI Java. Dautres outils de dveloppement sont galement disponibles : un gnrateur de documentation (Javadoc) : il permet de construire des documents partir des commentaires mis dans les programmes; un dbogueur : un programme pour la mise au point de vos programmes; un gnrateur de code natif : gnrant du code natif pour certaines architectures de machine; un dsassembleur.
35
Le rsultat de cette compilation (pour autant quelle ne produise pas derreur) doit crer dans le mme rpertoire un fichier ayant une extension .class, soit : MaPremiereApplication.class. Finalement, excutez le programme avec la commande :
java MaPremiereApplication
Sous dautres systmes dexploitation (MacOs par exemple), laffichage a lieu dans une fentre (voir figure 3.1) qui correspond au stdout (la sortie standard dUnix).
Une application doit toujours possder une mthode main() dclare comme suit :
public static void main (String args[]) { ... instructions excuter ... }
Nous verrons plus loin la signification exacte des termes qui apparaissent dans cet nonc.
Le rsultat de cette compilation (pour autant quelle ne produise pas derreur) doit crer dans le mme rpertoire un fichier ayant une extension .class, soit MaPremiereApplet.class.
36
Il nous faut maintenant invoquer cette applet depuis un document HTML qui devra se trouver pour le moment dans le mme rpertoire que le fichier MaPremiereApplet.class. Nous proposons dcrire ceci dans un fichier test.html :
<title>Applet Une</title> <h1>Vraiment la première</h1> <hr> <applet code=MaPremiereApplet.class width=200 height=50> </applet> <hr> <a href="MaPremiereApplet.java">Le source.</a> <hr>
Ouvrez votre butineur et demandez charger votre document test.html. Vous devriez obtenir le rsultat suivant (figure 3.2) :
37
5. Si un nud (ou une liste des liens retourns) vous intresse, sauvez son URL dans une liste de rfrence (bookmark). 6. Recommencer avec des mots proches ou contraires (Java AND virus). 7. Si vous dsirez avoir des liens en franais, introduisez au moins un mot en franais (Java AND programmation). 8. Recommencez rgulirement vos recherches, la frquence dpendant de la vitesse dvolution du domaine (semaine, mois, trimestre, etc.).
Figure 3.1 Recherche laide de lindexeur AltaVista, lpoque o il tait sans publicit!
Partie II
Le langage
Telles des chvres en dtresse, sept Mercedes-Benz vertes, les fentres crpes de reps grge, descendent lentement West End Street et prennent snestrement Temple Street vers les vertes venelles semes de htres et de frnes prs desquelles se dresse, svelte et empes en mme temps, lvch dExeter. Prs de lentre des thermes des gens sempressent. Quels secrets reclent ces fentres scelles? G. Perec, Les Revenantes.
4. Les bases 5. Les structures de contrle 6. Une introduction aux objets 7. Les structures 8. Exceptions et processus
Chapitre 4
Les bases
Pour apprendre un langage, deux approches peuvent tre suivies : la premire, des concepts vers la syntaxe et la seconde, de la syntaxe vers les concepts. Nous avons choisi de suivre cette dernire car elle permet de partir de notions dj rencontres dans dautres langages de programmation et de nous amener un stade o il devient possible de construire des exemples intressants laide de notions dj expliques. De plus, en partant des bases, il est possible de faire rapidement tat des diffrences existant avec dautres langages tels que C ou C++ (voir ce propos lannexe A).
4.1 Commentaires
Trois styles de commentaires sont disponibles en Java. Le plus connu est celui qui provient du C, o le commentaire est encadr par /* et */.
/* ceci est un commentaire sur plusieurs lignes ... qui se termine ici */
42
Le second provient de C++ et permet de placer un commentaire sur la mme ligne quune instruction. Dans ce cas, le commentaire commence par //.
int i // voici une variable entire
Enfin, le troisime style consiste encadrer le commentaire avec /** et */. Cette forme est utiliser uniquement dans les dclarations : elle est reconnue par un gnrateur automatique de documentation (JavaDoc). Le tableau 4.1 cidessous illustre ces trois styles de commentaires.
Style
/* commentaire */ // commentaire /** commentaire */
Dfinition Tous les caractres compris entre /* et */ sont ignors. Tous les caractres compris entre les // et le retour de la ligne sont ignors. Tous les caractres compris entre /** et */ sont ignors par le compilateur mais peuvent tre traits par des outils de documentation automatique.
Ce commentaire ne donne aucun renseignement sur le rle de zoom et sur le choix de la valeur 2.
int zoom=2 // valeur par dfaut du zoom au dmarrage
Ce dernier lui est nettement prfrable. Nous allons maintenant examiner comment nommer prcisment les objets de nos programmes.
4.2 Identificateurs
Les identificateurs permettent de nommer les diffrents lments (variables, classes, mthodes, packages, etc.) des programmes Java.
identifier = "dans {a..z, A..Z, $, _}" < " dans {a..z, A..Z,$,_,0..9,unicode character over 00C0}" >
La rgle de nommage ci-dessus indique que le premier caractre doit tre une
Identificateurs
43
lettre minuscule ou une lettre majuscule, ou encore le caractre soulign _ ou le caractre dollar $. Les caractres suivants (ds le second) peuvent tre soit : des caractres a..z ou A..Z; le _ ou le $; des chiffres de 0 9; les caractres Unicode (voir [13]) suprieurs 0X00C0, permettant dintroduire dans les identificateurs des caractres nationaux tels que , , etc. ( lexclusion cependant des caractres de contrle). Exemples didentificateurs valides en Java :
$valeur_system dateDeNaissance ISO9000
long est bien form selon les rgles nonces ci-dessus, mais il appartient la
liste des mots rservs du langage Java (voir tableau 4.2). En effet, en Java comme dans les autres langages de programmation, un certain nombre de mots sont rservs la construction des instructions. Ds lors, un identificateur ne doit pas tre choisi dans cette liste.
abstract case continue extends goto3 int null return synchronized true boolean catch default false if interface package short this try break char do finally implements long private static throw void byte class double float import native protected super throws while byvalue1 const2 else for instanceof new public switch transient
44
Acceptable
nom_de _methode ceci_est_une_variable
Dconseill
$init _type
4.3 Littraux
Les littraux dfinissent explicitement les valeurs sur lesquelles travaillent les programmes Java. Ils sont intimement lis aux types des variables qui les contiennent. Java supporte trois catgories de littraux : les boolens, les nombres (entiers et flottants) et les caractres.
Boolens
Les mots cls false et true dfinissent respectivement les valeurs de vrit faux et vrai. Ils permettent essentiellement dinitialiser des variables boolennes. noter que la valeur dune variable boolenne est toujours associe lun de ces deux littraux et ne peut pas tre assimile un 0 ou un 1 comme dans le cas des langages C ou C++ (voir p. 421).
boolean resultatAtteint = false ; boolean continuer = true ;
1.
Les diagrammes syntaxiques que nous utilisons ont t tablis partir des spcifications du langage publies par Sun. Nous avons prfr conserver les termes anglais originaux pour dsigner les lments syntaxiques.
Littraux
45
Entiers
Lexpression des nombres entiers peut se faire dans trois formats : en dcimal, en octal et en hexadcimal.
Lentier exprim en dcimal ne commence jamais par un zro. Cela est extrmement important pour viter des erreurs.
int nbrDeMois = 12;
Enfin, pour exprimer un entier en hexadcimal, il suffit de le faire prcder dun zro suivi dun X minuscule ou majuscule.
int dixHuit= 0x12;
Les nombres entiers dclars littralement correspondent au type entier int sur 32 bits. On peut forcer un entier prendre le type entier long en le faisant suivre dun L minuscule ou majuscule; il stend alors sur 64 bits.
Flottants
Le littral flottant est utilis pour dfinir des valeurs dcimales. Il comporte une mantisse et ventuellement une partie exposant exprime en puissances de 10. Un nombre flottant doit obligatoirement avoir un point dcimal ou une partie exposant (sinon rien ne le distingue dun nombre entier). Les diagrammes syntaxiques 4.3et 4.4expriment ces diffrentes possibilits.
46
La partie exposant est prfixe par un E minuscule ou majuscule suivi de la valeur de lexposant (voir diagramme 4.5). Exemples de flottants avec partie exposant :
2E0 2E3 2E-3 .2E3 2.5E-3
Les nombres flottants dclars littralement correspondent au type flottant double sur 64 bits. On peut forcer un flottant prendre le type float en lui faisant succder un F minuscule ou majuscule; il stend alors sur 32 bits. On peut galement forcer un flottant prendre le type flottant double prcision en lui faisant succder un D minuscule ou majuscule ; il stend alors sur 64 bits (diagramme 4.6) :
3.14F 3.14159D
Caractres
Le littral dun caractre est un caractre entour de deux apostrophes : Il peut tre choisi dans lensemble des caractres Unicode. Le tableau 4.4 ci-dessous montre les caractres de contrle les plus courants ainsi que leur squence de codification.
Caractre Continuation Abrviation <nouvelle ligne> Squence
\
'x'
'a'
'4'
Littraux
Caractre Nouvelle ligne Tabulation Retour arrire Retour chariot Saut de page Backslash Apostrophe Guillemet Caractre octal Caractre hexadcimal Caractre Unicode Abrviation N HT BS CR FF \ ' " 0377 0xFF 0xFFFF Squence
\n \t \b \r \f \\ \' \" \377 \xFF \uFFFF
47
Chanes de caractres
Les chanes de caractres sont formes dune suite de caractres entoure de guillemets (voir diagramme 4.7); elles sont associes au type String. En Java, le type String constitue une classe part entire et ne doit pas tre confondu avec un vecteur de caractres. Le tableau 4.5 montre diffrents exemples de chanes de caractres et le rsultat de leur impression.
Rsultat de limpression
48
La dclaration dune variable (diagramme 4.8) seffectue en prfixant le nom de la variable par son type (par exemple int pour un entier) :
int i;
La dclaration dun ensemble de variables du mme type seffectue en prfixant le nom des variables par leur type : Le diagramme 4.8montre galement que lon peut ajouter un modificateur (modifier) la dfinition dune variable. Par exemple, le modificateur final prcise que la valeur de la variable ne pourra plus tre change aprs son affectation initiale : cest ainsi que lon dfinit une constante. Nous examinerons plus en dtail ces diffrents modificateurs lorsque nous traiterons des classes (point 7.5, p. 100).
final int NbreDeRoues=4; final float pi=3.14159; int i,j,k;
Dans les exemples ci-dessus, on constate que lon peut affecter une valeur une variable lors de sa dclaration; le diagramme 4.9indique cette possibilit.
Revenons sur la notion de type. Il existe deux catgories de types : les types simples comme les boolens, les entiers, etc., qui sont considrer comme des types primitifs car ils ne sont pas construits partir dautres types;
49
les types composs qui sont construits partir dautres types comme les vecteurs, matrices, classes ou interfaces. Les diagrammes 4.10et 4.11illustrent la dfinition des types en Java.
Boolens
Une variable boolenne pourra contenir lune des valeurs vrai ou faux. Cette variable pourra tre assigne par les littraux true ou false et elle pourra recevoir le rsultat dune expression logique :
boolean voitureArretee=true; voitureArretee = (vitesse < 1);
Entiers
Il existe quatre types dentiers : byte, short, int et long. Chacun diffre par la taille des entiers quil peut reprsenter, exprime en nombre de bits (voir tableau 4.6).
Type
byte short int long
Nbre de bits
8 16 32 64
Exemple
byte NbrEnfant; short VolumeSon; int i,j,k; long detteSecu;
50
La dclaration dune variable entire permet de reprsenter un nombre entier limit par le nombre de bits de sa reprsentation. Cette variable pourra tre assigne par les littraux entiers et recevoir le rsultat dune expression entire.
Flottants
Il existe deux types de flottants : float et double. Chacun diffre par la taille de sa reprsentation exprime en nombre de bits (voir tableau 4.7).
Type
float double
Nbre de bits
32 64
Exemple
float ageMoyen; double pi;
Une variable flottante pourra contenir un nombre flottant limit par le nombre de bits de sa reprsentation. Cette variable pourra tre assigne par les littraux flottants et recevoir le rsultat dune expression flottante.
Caractres
La dclaration dune variable caractre permet de reprsenter une valeur dfinie sur lensemble des caractres Unicode. Cette variable pourra tre assigne par des littraux caractres et recevoir le rsultat dune expression caractre.
char separateur=\t; // le sparateur est un tabulateur
Un caractre est reprsent sur 16 bits en Java. Il sert conserver la valeur dun seul caractre. Les chanes de caractres quant elles sont reprsentes par la classe String (voir le point Chanes de caractres , p. 47).
Vecteurs et matrices
Les vecteurs, galement appels tableaux, sont dclars en postfixant le type ou la variable par [ ] :
int i[ ]; // vecteur dentiers int[ ] j; // autre notation pour le mme type que i char motsCroises[ ][ ]; // une matrice de caractres
On remarquera que les vecteurs ne sont pas contraints par des bornes au moment de leur dclaration. Lallocation de lespace ncessaire au vecteur se fera explicitement au moyen dune mthode new qui sera prsente dans le prochain chapitre (voir p. 61). On peut cependant allouer de lespace au vecteur et linitialiser lors de la dclaration :
int f[ ] = {1, 1, 2, 3*t, 5, 8, u-13, 21}; double[ ][ ] e1 = {{0.0, 1.0}, {-1.0, 0.0}};
51
Dans le programme Test ci-dessus, les variables x et c ne sont visibles que dans leur bloc respectif. Ainsi, dans le bloc de methodeA, il nest pas possible daccder la variable x. La figure 4.1 illustre lespace de visibilit des variables x et c. Examinons maintenant le cas des blocs imbriqus et celui de la redfinition dune variable. Lorsque des blocs sont imbriqus, les variables dfinies un niveau suprieur sont visibles depuis les sous-blocs. Toutefois, si dans un sous-bloc on redfinit une variable visible dans un bloc suprieur, cette nouvelle variable masque la variable suprieure lintrieur du sous-bloc (et de ses propres sousblocs). Voyons cela laide dun exemple :
class Test { // debut de test public static void principal(String args[]) { // debut de principal float echange; int a,b; ... if a < b then { int echange;
52
echange=a;a=b;b=echange }; } // fin de principal public void methodeA () } // fin de principal
Test principal
a, b, echange
bloc du if
echange
Dans le bloc du if, a et b rfrencent les variables du bloc principal, alors que echange rfrence la variable locale echange du bloc (voir figure 4.2). La redfinition des variables est destine des variables temporaires utilises lintrieur dun bloc, comme par exemple lindice dune boucle.
4.6 Oprateurs
Les oprateurs sont regroups par types doprations : numriques, comparaisons, logiques, manipulations de chanes de caractres, manipulations binaires. Leur classification se base sur le nombre doprandes quils ncessitent : 1 (unaire), 2 (binaire) et mme 3 (ternaire).
Prcdence des oprateurs (de la plus grande la plus petite) Les oprateurs de mme niveau sont valus depuis la gauche
. ++ * + << < == & ^ != >> > >>> <= >= [] -/ % () ! ~ instanceof
Oprateurs
Prcdence des oprateurs (de la plus grande la plus petite) Les oprateurs de mme niveau sont valus depuis la gauche
&& || ?: = , op=
53
Les expressions composes sont values de la gauche vers la droite, une table de prcdence (voir tableau 4.8) indiquant la priorit entre les oprations. Prenons comme exemple lexpression suivante :
x=z+w-y/(3*y^2)
Pour cette expression, lordre de lecture (de la gauche vers la droite) est :
= + / ()
lintrieur des parenthses (), nous avons * ^ par ordre de lecture de mme que par ordre dexcution.
Assignation
Loprateur dassignation est le symbole "=". Lassignation affecte lexpression place droite de loprateur lexpression (une variable) place gauche de celui-ci. Il est intressant de constater que, dans Java, lassignation est considre comme un oprateur binaire qui modifie son oprande gauche.
j=2; i=j*3; i=j*3(j=2); // expression dassignation dun litral // expression dassignation dune expression // expression valide combinant les deux formes
Trois autres oprateurs ont des effets de bord : ~, ++ et --. Lutilisation combine de ces oprateurs dans une mme expression risque den rendre la lecture confuse. On essayera donc de dcomposer les expressions afin quelles ne contiennent chacune quun seul oprateur avec effet de bord.
54
Expressions numriques
Les expresssions numriques sont classiques. Cependant quelques raccourcis syntaxiques sont connatre pour allger le code.
Exemple
i=-j; i++; i--;
Oprateur
+ += -= *
Action Addition
Exemple
i=j+k i+=2; //i=i+2
Soustraction
Multiplication
x=2*y
Oprateurs
Oprateur
*= / /= % %=
55
Action Exemple
x*=x; //x=x*x
Modulo
Pour les nombres entiers, les rgles suivantes sont appliques (voir diagramme 4.12, tableaux 4.9 et 4.10) : la division par 0 et le modulo par 0 gnrent une exception lexcution; les oprations dont la reprsentation dpasse la valeur maximum du type de lentier dbordent dans les entiers ngatifs. Pour les nombres flottants, les oprations ont la mme smantique : pour les incrmentations et dcrmentations, on ajoute la valeur 1.0; le % (modulo) appliqu un flottant prend le sens de la division dans les entiers; la division par 0 et le modulo par 0 gnrent la valeur inf; les oprations dont la reprsentation dpasse la valeur maximum du type gnrent la valeur inf tandis que les dbordements vers linfiniment petit gnrent 0. Le programme TestNumber illustre le cas o lon approche du maximum de la reprsentation pour les entiers et les flottants.
class TestNumber{ public static void main (String args[]) { int i=1000, j=1000; float x=1, y=1; for (int k=0; k<100;k++) { i*=10; j/=10; x*=10000; y/=10000; System.out.println("\ni="+i+" j="+j+" x="+x+" y="+y); } } } i=10000 j=100 x=10000 y=0.0001
56
i=100000 i=1000000 i=10000000 i=100000000 i=1000000000 i=1410065408 i=1215752192 i=-727379968 i=1316134912 i=276447232 i=-1530494976 i=1874919424 j=10 j=1 j=0 j=0 j=0 j=0 j=0 j=0 j=0 j=0 j=0 j=0 x=1e+08 x=1e+12 x=1e+16 x=1e+20 x=1e+24 x=1e+28 x=1e+32 x=1e+36 x=Inf x=Inf x=Inf x=Inf
Action Plus petit que Plus grand que Plus petit ou gal Plus grand ou gal Egal Diffrent de
Exemple
x<i; i>100; j<=k; c>=a; i==20; c!=z;
En ce qui concerne la relation dordre sur les nombres flottants, la prudence simpose, car x==y peut tre vrai sans que y<x || y>x soit forcment vrai. Il faut galement rester vigilant avec loprateur == qui peut tre confondu dans un programme avec =. Mais, contrairement ce qui se passe en langage C, cette erreur est dtecte par le compilateur.
Oprateurs relationnels
57
Oprateurs logiques
Les oprateurs logiques traitent des oprandes dont la valeur est boolenne. Les quatre oprateurs de base sont : la ngation (!), le ET (&), le OU (|), le OU exclusif (^). Le tableau 4.12 prsente ces oprateurs et le rsultat de leur application sur des oprandes logiques (p et q). Le diagramme 4.15et le tableau 4.13 dcrivent lensemble complet des oprateurs logiques.
p
v v f f
q
v f v f
!p
f f v v
p&q
v f f f
p|q
v v v f
p^q
f v v f
Pour chaque oprateur logique (sauf pour la ngation), on trouve une forme assigne o la variable affecte est aussi loprande de gauche de loprateur. Ainsi :
p&=(i=10); // est quivalent p=p&(i=10)
On trouve aussi pour le ET et le OU une version avec valuation raccourcie, dont les symboles sont respectivement && et ||. Dans ce cas, lvaluation de lexpression logique est stoppe ds la dtermination certaine de sa valeur de vrit. Ainsi, dans :
p1 && p2 && ... & pn
lvaluation est stoppe ds quune expression pi retourne true. Ce mcanisme permet aussi dviter dvaluer des expressions qui pourraient gnrer une erreur, comme dans lexemple suivant o une division par 0 est vite :
(i!=0) && (x > ( y/i)); // y/i nest pas valu si i gale 0
Dans ce cas, si p est vrai alors lexpression e1 est value, sinon e2 est value. Cette forme, du fait que lassignation est considre comme une expression, peut tre utilise comme une instruction if. Exemple :
p?e1:e2; // est quivalent if (p) e1; else e2;
58
Action Ngation ET OU OU exclusif ET valu OU valu Ngation assigne ET assign OU assign Si alors sinon
Exemple
!p; p & (i<10) p | q p ^ false p && q && r p || q || r p!=p; p&=q p|=q // p= p & q // p= p | q
(i<10)?(j=2):(j=3)
Enfin, ajoutons encore que les oprateurs !, &, |, et ^ sont tendus des oprations de manipulation binaire sur les bits de la reprsentation des oprandes entiers. Ces oprateurs appliquent ainsi la table de vrit chaque bit dun entier, substituant false 0 et true 1.
59
Les oprandes qui ne sont pas des chanes de caractres sont automatiquement convertis. La concatnation de chanes de caractres est dcrite par le diagramme 4.3 et le tableau 4.14. Nous avons dj utilis cet oprateur plusieurs reprises dans des instructions dimpression telles que :
System.out.println("\ni="+i+" j="+j+" x="+x+" y="+y);
Exemple
"conca"+"tnation"; s+=" la fin";
Ces oprateurs ont une version assigne qui permet daffecter directement le rsultat dun dcalage effectu sur une variable celle-ci.
60
Oprateur
<< >> >>> <<= >>= >>>=
Il est intressant de noter les quivalences suivantes (tableau 4.16) entre les oprations de manipulation binaire et les oprations arithmtiques sur les entiers. Pour un nombre entier i, on a :
Oprateur binaire
~i i>>k i<<k i>>>k i>>>k
Oprateur arithmtique
(-i)-1 i/2 i*2 i/2 k k k
Condition
si i>0
si i>0 si i<0
(i<<k)+(2<<(L-k-1)
Conversions de types
61
int i[] = new int [100]; // i un vecteur de 100 entiers int c[][] = new char[10][10]; // c une matrice de 10x10 caractres
Les indices des vecteurs et des matrices commencent 0, ce qui signifie que la valeur maximum dun indice sera dimension du vecteur 1 :
i[0] = 1; i[9] = 10; c[0][0]=a; c[9][9]=z; // // // // la premire position de i est initialise 1 la dernire position de i est initialise 10 premire case de c dernire case de c
Pour un type ayant plusieurs dimensions, seule la premire dentre elles doit obligatoirement tre fixe au moment de lallocation :
int c[][] = new char[10][]; // c une matrice de 10 par ?
Des dimensions diffrentes peuvent trs bien exister dans la mme variable :
c[1] = new char [12]; // deuxime ligne de c = 12 caractres
Dune manire gnrale, lallocation dune variable de dimension n peut tre vue comme une srie de n-1 boucles imbriques effectuant chacune une allocation :
int c[][] = new char[10][10]; // est quivalent : int c[][] = new char[10][]; // allocation de la matrice c (10 lignes) for (int i=0; i< c.length; i++) c[i] = new char [10]; //allocation de chaque ligne de c
Nous reviendrons plus prcisment sur les mcanismes dallocation et sur la gestion de la mmoire en Java au point 6.2.
62
caractre ou utiliser un entier en tant que flottant. Pour effectuer ce genre doprations, il faut faire appel la conversion de types. Il y a deux catgories de conversions : les largissements, qui conservent les valeurs, avec une ventuelle perte de prcision et les rtrcissements, qui peuvent compltement modifier les valeurs. Le rtrcissement se prsente lorsquon convertit vers un type moins tendu que le type de dpart. Par exemple, il est vident que les 64 bits dun long ne pourront pas tenir dans les 8 bits dun byte. Dans ce cas il y a troncature, seuls les 8 bits les moins significatifs sont conservs. Une conversion de rtrcissement doit tre indique explicitement laide de loprateur de casting (<type>).
Llargissement ne ncessite aucune notation particulire. Llargissement dun entier un flottant peut faire perdre de la prcision lorsque la mantisse du type flottant est plus courte que le nombre de bits de lentier. Voici quelques exemples de conversions :
int i; i == (int) ((float) i); // nest pas toujours vrai // Rtrcissement avec troncation ncessaire int a = 911000; byte ba = (byte)a; // rsultat: ba =-104 short sa = (short)a; // rsultat: sa = -6504 // Rtrcissement sans troncation a = 66; char ca = (char)a; // rsultat: ca = 'B' (66 = code Unicode de 'B') ba = (byte)a; // rsultat: ba = 66 // Rtrcissement dun flottant double d = 7.7e+204; int a = (int)d; // rsultat: a = 2147483647 (le plus grand entier) d = 6789.6789; a = (int)d; // rsultat: a = 6789 (arrondi) // Elargissement dun entier a = 2111222333; float f = a; // rsultat: f = 2.11122227e+9 (perte de prcision) double d = a; // rsultat: d = 2.111222333e+9 (pas de perte de prcision)
Conversions de types
63
Le tableau 4.17 ci-dessous numre les conversions autorises (oui), autorises mais pouvant causer une perte de prcision (perte) et celles ncessitant une conversion explicite ().
De \ byte short int long float double char byte oui () () () () () () short oui oui () () () () () int oui ou oui () () () oui long oui oui oui oui () () oui float oui oui perte perte ou () oui double oui oui oui perte oui oui oui char oui () () () () () oui
Chapitre 5
66
Les deux formes suivantes peuvent tre employes : if (e) S1; linstruction S1 est excute si e est vraie :
if (i==1) s=" i est gal 1 ";
if (e) S1 else S2; linstruction S1 est excute si e est vraie. Linstruction S2 est excute si e est fausse:
if (i==1) s=" i est gal 1 "; else s=" i est diffrent de 1 ";
De ces deux formes, nous pouvons driver : if (e) {B1}; le bloc B1 est excut si e est vraie :
if (i==1) { s=" i est gal 1 ";
Excution conditionnelle
i=j; }
67
if (e) {B1} else {B2}; le bloc B1 est excut si e est vraie. Le bloc B2 est excut si e est fausse :
if (i==1) { s=" i est gal 1 "; i=j; } else { s=" i est diffrent de 1 "; i=1515; }
if (e1) S1 else if (e2) S2 ... else Sn; cest une cascade de si_alors. Linstruction Si est excute si ei est vraie et que toutes les expressions testes auparavant sont fausses :
if (i==1) s=" i est gal 1 "; else if (i==2) s=" i est gal 2 "; else if (i==3) s=" i est gal 3 "; else s=" i est diffrent de 1,2 et 3 ";
Cette dernire forme nous amne recommander une certaine prudence dans lutilisation de si_alors en cascade. Ainsi, dans lexemple ci-dessus, la dernire clause else se rapporte au dernier si_alors. Dans de tels cas, lutilisation de {} est ncessaire pour bien marquer le dbut et la fin des instructions, comme le montre cet exemple :
i=0; j=3; if (i==0) if (j==2) s=" i est gal 2 "; else i=j; System.out.println(i);
Que va imprimer le programme ci-dessus : 0 ou 3? Il va imprimer 3, car i==0 et j!=2, donc on excute i=j. Le else se rapporte en effet au if le plus imbriqu.
Au cas o (switch)
Linstruction switch se comporte comme un aiguillage, excutant des instructions diffrentes (clauses case) suivant le rsultat dune expression. Pour cela, elle commence par valuer lexpression qui lui est lie puis elle compare la valeur retourne avec celle de chaque expression lie aux case. Dans le cas o il y a galit, elle commence excuter le code li ce case, puis excute toutes les instructions des cas suivants.
68
Si lon dsire isoler chaque clause case, il faut terminer son code avec un break. Si aucun cas dgalit nest trouv et quune clause default est spcifie, alors on excute cette clause. Du point de vue syntaxique, les symboles case et default sont considrs comme des tiquettes (voir diagramme 5.4). Examinons la forme gnrale de switch sans break :
switch (e) { case c1: S1; case c2: S2; ... case cn: Sn; default: Sd };
Si lexpression e est value la valeur ci, alors les instructions Si, Si+1, ... Sn, Sd sont excutes. Si lexpression e est diffrente de tous les ci, alors on excute lexpression Sd. Examinons la forme gnrale de switch avec break :
switch (e) { case c1: S1 break; case c2: S2 break; ... case cn: Sn break; default: Sd };
Si lexpression e est value la valeur ci, alors linstruction Si est excute. Si lexpression e est diffrente de tous les ci, alors on excute lexpression Sd.
class TestSwitch{ public static void main (String args[]) { int i=3; switch (i) { case 1: System.out.println("I"); break; case 2: System.out.println("II"); break; case 3: System.out.println("III"); break; case 4: System.out.println("IV"); break; case 5: System.out.println("V"); break; default: System.out.println("pas de traduction"); } }}
Il faut encore prciser que le type de lexpression dune clause case doit tre char, byte, short ou int.
Excution itrative
69
70
Pour_faire_ (for)
Une boucle for est dclare laide dune ou plusieurs instructions (S1, B1) et de trois expressions (e1, e2, e3) : la premire (e1) initialise litrateur (aprs lavoir ventuellement dclar); cette expression nest excute quune seule fois; la deuxime (e2) exprime la condition de test (tant quelle est vraie on continue la boucle); elle est vrifie chaque itration; la troisime (e3) modifie litrateur; elle est excute chaque itration, la suite de linstruction (S1). Le diagramme 5.7prcise la syntaxe, dont les deux formes sont : for (e1;e2;e3) S1; excuter e1. Tant que e2 est vrai, excuter linstruction S1 et lexpression e3; for (e1;e2;e3) B1; excuter e1. Tant que e2 est vrai, excuter le bloc B1 et lexpression e3. Les expressions e2 et e3 sont optionnelles. Si elles ne sont pas prcises, le bloc B1 doit alors contenir des instructions pour modifier litrateur et une instruction break pour quitter la boucle. Dune manire gnrale, une boucle for est quivalente la boucle while suivante : e1; while(e2) {S1; e3}.
71
Dans lexemple TestFor, nous avons deux types de boucles : lune croissante, lautre dcroissante. Dans la seconde, on remarque que litrateur est dcrment en dehors de lexpression de modification (e3), qui est vide. Ce mcanisme permet de modifier litrateur de manire complexe depuis lintrieur du bloc dinstructions.
72
5.5 Rupture
Linstruction break, dj rencontre dans linstruction switch (voir le point Au cas o (switch) , p. 67), peut galement tre utilise dans les itrateurs while, do et for : elle ordonne alors de quitter la boucle dans laquelle elle est utilise. Il est mme possible de remonter de plusieurs niveaux en accompagnant linstruction break du libell identifiant le bloc dinstructions quitter.
Dans lexemple TestBreak, le premier break (sans libell) force le programme quitter la boucle locale (j) tandis que le second (break bloc1) le force quitter le bloc complet identifi par le libell bloc1. Dans lexemple TestBreak2 ci-dessous, linstruction daffichage sera ignore car elle se trouve dans le bloc dinstructions identifi par le libell bloc2 (et non dans la boucle elle-mme!) :
class TestBreak2{ public static void main (String args[]) { bloc2:{ for (int i=0;i<10;i++) if (i==2) break bloc2; System.out.println("ne sera pas crit"); } } }
Continuation
73
5.6 Continuation
Linstruction continue est utilise dans les itrateurs while, do et for. Elle provoque linterruption du droulement normal de la boucle, le contrle tant repris aprs la dernire instruction de celle-ci (on recommence donc une nouvelle itration). Comme pour la rupture, il est possible dindiquer un libell : dans ce cas, le contrle est repris dans la boucle dpendant immdiatement de ce libell, comme le montre lexemple TestContinue :
class TestContinue{ public static void main (String args[]) { bloc3: for (int i=0;i<10;i++) for (int j=0; j<10;j++){ // quitte la boucle locale if (j>1) continue; // quitte la boucle for i ... if (i>2) continue bloc3; System.out.println(i+"/"+j); } System.out.println("en dehors des boucles"); } }
Malgr leur apparente ressemblance, les instructions break et continue sont trs diffrentes : dans le cas du break, on quitte rellement la boucle, alors que dans le cas du continue, on saute seulement le bloc dinstructions et on continue quand mme excuter les itrations.
74
75
76
Les nombres qui sont amicaux avec eux-mmes sont appels nombres parfaits . Parmi eux on peut citer : 6 et 28.
Chapitre 6
CLASSES
INSTANCES r1 r3 r2 d1 (OBJETS) d2
Les mthodes de Rectangle dterminent le comportement des objets de ce type. La dclaration dune mthode est compose des lments suivants : le type du rsultat produit, ou void si elle ne produit pas de rsultat; le nom de la mthode; le type et le nom des paramtres, placs entre (); un bloc dinstructions qui constitue le corps de la mthode.
79
On remarquera laccs systmatique aux variables dinstance dont chaque Rectangle est muni et qui refltent son tat (sa largeur et sa hauteur). Linstruction return calcule le rsultat et termine lexcution de la mthode. Le type du rsultat, le nom de la mthode et le nom et le type des paramtres forment ce quon appelle la signature de la mthode. Dans le bloc dinstructions dune mthode, on peut utiliser la pseudovariable this pour dsigner lobjet courant, cest--dire lobjet sur lequel la mthode est en train de travailler.
Constructeurs
Finalement, il ne nous reste plus qu dfinir le constructeur de la classe : une mthode particulire qui indique comment initialiser une instance. La rgle de nommage dun constructeur est simple, il doit porter le mme nom que la classe concerne :
class Rectangle { ... Rectangle(double initL, double initH){ largeur=initL; hauteur=initH; } ... }
Ce constructeur initialise les deux variables dinstance du nouvel objet avec les valeurs des deux paramtres initL et initH. Voici donc le code complet de notre classe Rectangle :
class Rectangle { double largeur, hauteur; Rectangle(double initL, double initH){ largeur=initL; hauteur=initH; } double perimetre() {return 2*(largeur+hauteur);} double surface() {return largeur*hauteur;} double diagonale() { return Math.sqrt(largeur*largeur+hauteur*hauteur);} void doubler() {largeur*=2; hauteur*=2;} }
80
Nous procdons de la mme manire pour la classe Disque (variables dinstance, constructeur, mthodes) et obtenons le code suivant :
class Disque { double diametre; static final double pi=3.14159; Disque(double initD){ diametre=initD; } double perimetre() {return pi*diametre;} double surface() {return (pi*diametre*diametre)/4;} double rayon() {return diametre/2;} void doubler() {diametre*=2;}
Notons encore que si aucun constructeur nest dfini, Java cre un constructeur qui na aucun paramtre et ninitialise aucune variable dinstance.
cre un objet de la classe Disque et invoque le constructeur qui initialise la variable diametre 2.5. On peut assigner un objet une variable : pour cela il faut dclarer une variable du type correspondant. La dclaration de type seffectue comme pour les types de base (int, char), en faisant prcder la variable par le nom de la classe :
Disque d1,d2; d1=new Disque(2); d2=new Disque(4); // dclaration de 2 variables de type Disque // invoque le constructeur et assigne lobjet
Si la mthode possde des paramtres, les expressions donnes lors de linvocation (arguments) sont values et affectes aux paramtres correspondants de la mthode. Si lon veut invoquer une mthode sur linstance courante, on crira :
this.mthode(expression1, ...)
81
Un programme complet
Nous pouvons crire maintenant un petit programme (TestRectDisk1) utilisant les classes Rectangle et Disque (on notera au passage que les noms commenant par une majuscule sont rservs, par convention, aux identifiants des classes, ceux des mthodes commenant par une minuscule).
class TestRectDisk1{ public static void main (String args[]) { Rectangle r1=new Rectangle(2,4); Rectangle r2=new Rectangle(3,4); System.out.println("diagonale de r1: "+r1.diagonale()); System.out.println("primtre de r2: "+r2.perimetre()); r2.doubler(); System.out.println("primtre de r2: "+r2.perimetre()); Disque d1,d2; d1=new Disque(2); d2=new Disque(4); System.out.println("rayon de d1: "+d1.rayon()); System.out.println("primtre de d2: "+d2.perimetre()); d2.doubler(); System.out.println("primtre de d2: "+d2.perimetre()); } }
82
Si une classe possde plusieurs constructeurs, ceux-ci peuvent sinvoquer les uns les autres grce linstruction this(). Par exemple :
Rectangle(double initLH){ this(initLH, initLH);
Destruction dobjets
Il ny a en gnral pas besoin de soccuper de dtruire les objets car la machine virtuelle Java sen charge. Ds quun objet nest plus rfrenc par aucune variable ou aucun autre objet, le gestionnaire de mmoire le dtruit et rcupre lespace mmoire quil occupait. Cependant, dans le cas o lobjet avait, au travers de ses mthodes, ouvert des canaux de communication ou des fichiers, il faut les fermer explicitement. Cest pourquoi le systme invoque la mthode finalize(), si elle existe, juste avant la destruction de lobjet. On peut donc placer dans cette mthode le code ncessaire la restitution des ressources occupes par lobjet.
83
de doubler la largeur et la hauteur de linstance de manire indpendante. Nous obtenons le code suivant :
class Rectangle extends Object{ ... void doubler() { largeur*=2; hauteur*=2;} void doubler(boolean l, boolean h) { if (l) largeur*=2; if (h) hauteur*=2; }
Nous pouvons alors doubler les instances de Rectangle selon nos besoins :
class TestRectDisk2{ public static void main (String args[]) { r2.doubler(); r2.doubler(false,true); } // largeur et hauteur // uniquement la hauteur
On parle dans un tel cas de surcharge des mthodes. Le compilateur examine les types de paramtres et leur nombre au moment de la dclaration de lappel, afin de dterminer la bonne mthode invoquer. Lexemple suivant montre un autre cas de surcharge vu prcdemment :
r2.doubler(); // r2 est un Rectangle d2.doubler(); // d2 est un Disque
Dans ce cas, le compilateur sait (grce la dclaration de type des variables) que pour r2, il doit invoquer la mthode doubler() de la classe Rectangle alors que pour d2, il doit invoquer celle de la classe Disque.
Variables de classe
Une classe peut galement possder ses propres variables de classe (qui ne seront pas cres dans ses instances), lui permettant de grer des informations propos de ses instances, comme par exemple la hauteur moyenne des Rectangles. Les variables de classe sont dclares statiques (static). Elles sont initialises au moment du chargement de la classe. La constante pi, dclare static dans la classe Disque, est un autre exemple de variable de classe. En effet, il nest pas ncessaire (ni mme utile) que chaque instance de Disque possde sa propre copie de la variable pi.
84
en tant prfixes par le nom de lobjet, depuis lextrieur de la classe. Ainsi, linstruction suivante imprimera les dimensions de r2 :
System.out.println("dimension:"+r2.largeur+"/"+r2.hauteur); r2.hauteur=45;
Il est bien entendu possible de cacher les variables dinstance (surtout pour viter quon ne les modifie de lextrieur) grce deux modificateurs, private et protected, que nous tudierons plus en dtail au point 24.2. Les variables de classe, quant elles, sont accessibles depuis lextrieur de la classe en les prfixant du nom de la classe. Le fameux System.out nest autre que la variable de classe out de la classe System et System.out.println() invoque la mthode println() de cet objet.
Mthodes de classe
Les mthodes de classe sont destines agir sur la classe plutt que sur ses instances : elles permettent de manipuler les variables de classe. Nous avons ainsi ajout notre exemple une mthode de classe modifierEchelle() que nous devons dclarer static. Lappel cette mthode se fera en la prfixant par le nom de la classe. Lorsque lon dsire effectuer des initialisations complexes des variables de la classe, on peut lui associer un bloc dinstructions qui sera excut lors du chargement de la classe. Un tel bloc doit avoir la forme suivante (on notera labsence de nom de mthode) :
static { instruction; ...}
85
Dfinition de sous-classes
Admettons que nous voulions crer une classe Carr. Sans le mcanisme dhritage, nous devrions redfinir les mthodes perimetre(), surface(), diagonale(), etc., alors quun carr, cest presque un rectangle. Nous allons donc profiter du fait que Java supporte la notion dhritage (et que nous avons dj dfini une classe Rectangle) pour crer une classe Carr qui tend le comportement de Rectangle, hritant ainsi de ses variables dinstance et de ses mthodes. Nous dirons alors que Carr est une sous-classe de Rectangle et que Rectangle est la super-classe de Carr. Nous dfinissons un constructeur pour la classe Carr, qui va invoquer le constructeur de la classe dont elle hrite (Rectangle). On utilise cet effet le dsignateur super(). Nous ajoutons ensuite une mthode cote() la classe Carr.
class Carre extends Rectangle{ Carre(double initC){ super(initC,initC); } double cote() {return this.hauteur;} } class TestRectDisk4{ public static void main (String args[]) { Carre c1=new Carre(4); System.out.println("dim. c1: "+c1.largeur+"/"+c1.hauteur); System.out.println("surf. c1: "+c1.surface()); System.out.println("cot de c1 "+c1.cote()); }}
86
Excution de TestRectDisk4 :
dim. c1: 4/4 surf. c1: 16 cot de c1 4
Comme r2 est de type Rectangle, et bien quelle dsigne un Carre, son comportement est restreint celui dun Rectangle; on ne peut lui appliquer que les mthodes propres Rectangle.
double s = r2.surface(); // OK double c = r2.cote(); //*** FAUX *** erreur la compilation
Par contre, si une mthode est redfinie dans une sous-classe, cest bien la mthode de la sous-classe qui est appele. Par exemple, sil existe une mthode imprimer() dfinie dans Rectangle, qui imprime la largeur et la hauteur dun rectangle, et une mthode imprime() dans Carre, qui imprime le ct, lexcution de
Rectangle r r = new Rectangle(5, 6); r.imprimer(); r = new Carre(4); r.imprimer();
produira :
largeur: 5 hauteur: 6 cote: 4
Le mcanisme qui, lors de lexcution du programme, choisit la bonne mthode excuter en fonction de la classe de lobjet dsign, sappelle liaison dynamique; nous y reviendrons en dtail au point 22.1, p. 313. Mentionnons aussi que la pseudovariable super sert accder aux mthodes de la super-classe, mme si elles ont t redfinies. Cela est utile lorsquune mthode de la sous-classe veut utiliser la mthode quelle redfinit. Par exemple :
class CarreCouleur extends Carre { String couleur; CarreCouleur(int a, String clr) {... } // constructeur
87
produira :
cote: 3 rouge
Cette rgle peut parfois savrer trop svre et empcher des affectations correctes, comme par exemple :
Rectangle r; Carre c; r = new Carre(5); ... c = r; // r dsigne bien un Carre // *** Refus la compilation
Le compilateur a raison de refuser la dernire instruction car r pourrait trs bien dsigner autre chose quun Carre. Lorsque lon sait quune variable r (ou une expression) de type Rectangle dsigne en fait un Carre, on peut crire :
(Carre) r
afin de changer le type de lexpression en Carre, permettant ainsi dcrire lassignation prvue :
c = (Carre) r;
Le compilateur admet cette instruction, mais Java tant sr, il y aura un contrle au moment de lexcution, afin de vrifier que r dsigne bien un objet de Carre (ou de lune de ses sous-classes). Si ce nest pas le cas, une erreur dexcution se produira.
88
Constructeurs de sous-classes
Lune des rgles de Java impose que tout constructeur appelle directement ou indirectement un constructeur de sa super-classe. Si la premire instruction dun constructeur nest pas super() ou this(), un appel super() est automatiquement ajout avant la premire instruction. Dans ce cas, il faut quun constructeur sans paramtre existe dans la super-classe. Examinons encore un exemple : admettons que lon souhaite tendre le comportement des rectangles celui des paralllpipdes. Nous agissons comme dans le cas prcdent, en tendant la classe Rectangle afin dajouter une variable dinstance pour mmoriser la profondeur dun Parallelepipede et en dclarant le constructeur et les mthodes propres cette nouvelle classe :
class Parallelepipede extends Rectangle{ double profondeur; Parallelepipede(double x, double y, double z){ super(x,y); profondeur=z; } double volume(){return surface()*profondeur;} } class TestRectPar{ public static void main (String args[]) { Parallelepipede p1=new Parallelepipede(2,3,4); System.out.println("prof. p1:"+p1.profondeur); System.out.println("surf. p1:"+p1.surface()); System.out.println("vol. p1:"+p1.volume()); } }
Excution de TestRectPar :
prof. p1:4 surf. p1:6 vol. p1:24
Il y a quelques pages encore, nous ne savions rien de lhritage et voil que nous avons cr une vritable petite famille. En Java, toutes les classes ont pour origine la classe Object. Une classe ne pouvant tendre quune seule classe (appele sa super-classe), nous avons donc une hirarchie stricte que lon peut reprsenter sous forme dun arbre dhritage, dont la racine est la classe Object (voir figure 6.2).
89
Object
Rectangle
Disque
Carre
90
return 2*(largeur+hauteur); } double surface(){ return largeur*hauteur; } ...
} class Disque extends GeometriePlane{ ... double perimetre() { return GeometriePlane.pi*diametre; } double surface() { return (GeometriePlane.pi*diametre*diametre)/4; } ... }
La classe abstraite napporte pas grand-chose de nouveau dans le comportement des objets. Par contre, en observant la structure, nous savons dsormais que toutes les sous-classes dune classe abstraite implantent ses mthodes. Exemple :
class Triangle extends GeometriePlane{...}
Cette dclaration nous assure que des mthodes perimetre() et surface() adaptes aux triangles pourront tre invoques sur des instances de la classe Triangle. Nous avons donc structur notre monde dobjets gomtriques.
Classes anonymes
for (int i=0; i<nbSommets; i++) sommets[i] = new Sommet(); } ... }
91
On voit sur cet exemple que les mthodes de la classe interne peuvent accder aux variables dinstance de leur objet englobant. Lexpression poids/nbSommets signifie : diviser la variable poids du sommet courant par la variable nbSommet du polygone auquel appartient le sommet. Linstruction new Sommet() du constructeur de Polygone cre des objets de Sommet dpendant du Polygone en construction. On peut galement crer des objets de Sommet depuis lextrieur de la classe Polygone, pour autant quon indique de quel Polygone ils dpendent. On utilise pour cela une nouvelle syntaxe de linstruction new :
Polygone po = new Polygone(); Polygone.Sommet spo = po.new Sommet();
Dans ce cas, la classe anonyme est une sous-classe de Sommet et lobjet sommetSpecial se comporte comme un Sommet mais avec une mthode poidsRelatif redfinie. Lorsque nous tudierons la gestion des vnements, nous verrons que les classes anonymes et les classes internes peuvent simplifier lcriture du code.
6.7 Interfaces
Une interface est assez similaire une classe abstraite, puisquelle dclare un ensemble de mthodes abstraites et de constantes. On ne peut donc pas instancier une interface (pas de new()), par contre linterface dfinit un type (on peut dclarer des variables de ce type). Une classe peut indiquer dans sa dfinition quelle implante une ou plusieurs interfaces. Elle sengage alors fournir une dfinition pour toutes les mthodes dfinies dans linterface.
92
Une interface peut hriter dune ou plusieurs autres interfaces, les interfaces formant une hirarchie spare de celle des classes. Revenons la gomtrie et dclarons une hirarchie dinterfaces :
interface Geometrie{ static final double pi=3.14159; } interface Courbe extends Geometrie{ double longueur(); void doubler(); } interface Surface extends Geometrie{ double surface(); }
Redfinissons maintenant les classes Rectangle et Disque en prcisant quelles implantent ces interfaces :
class Rectangle extends GeometriePlane implements Courbe, Surface { ... comme avant } class Disque extends GeometriePlane implements Courbe, Surface{ ... comme avant }
Les hirarchies de classes et dinterfaces ainsi que les liens dimplantation sont illustrs sur la figure 6.3 :
INTERFACES Gomtrie CLASSES Object
Courbe
Surface
GomtriePlane
Dans le programme TestRectDisk7 ci-aprs, nous montrons quil est possible de manipuler les rectangles et les disques comme des courbes ou des surfaces. On parle alors de polymorphisme :
class TestRectDisk7{ public static void main (String args[]) {
Packages
Courbe c[]=new Courbe[10]; Surface s[]=new Surface[10]; Rectangle r[]=new Rectangle[5]; Disque d[]=new Disque[5]; // crer des rectangles for (int i=0;i<5;i++){ r[i]=new Rectangle(i+1,i+1); c[i]=r[i]; s[i]=r[i]; } // crer des disques for (int i=0;i<5;i++){ d[i]=new Disque(i+1); c[i+5]=d[i]; s[i+5]=d[i]; } // manipuler les objets de chaque classe System.out.println("surf. r[2]: "+r[2].surface()); System.out.println("surf. s[2]: "+s[2].surface()); System.out.println("long. r[2]: "+r[2].longueur()); System.out.println("long. c[2]: "+c[2].longueur()); // considrer les objets comme des lments gomtriques // surface de tous les objets double surfTotal=0; for (int i=0;i<10;i++)surfTotal+=s[i].surface(); System.out.println("surfTotal: "+surfTotal); // doubler tous les primtres for (int i=0;i<10;i++)c[i].doubler(); //surface de tous les objets surfTotal=0; for (int i=0;i<10;i++)surfTotal+=s[i].surface(); System.out.println("surfTotal: "+surfTotal); } }
93
Excution de TestRectDisk7 :
surf. r[2]: 9 surf. s[2]: 9 long. r[2]: 12 long. c[2]: 12 surfTotal: 98.1969 surfTotal: 392.787
6.8 Packages
Un package permet de regrouper physiquement des classes concernant un domaine particulier (exemple : accs au rseau), afin de mieux les organiser. Le package dfinit un systme de nommage (nomDePackage.nomDelement);
94
celui-ci devra tre utilis dans tout programme dsirant accder aux lments (classes, constantes, etc.) du package. En rsum, les trois mcanismes proposs par Java pour structurer et organiser le code sont : lhritage, structure des classes; les interfaces, structure des comportements; les packages, structure du dveloppement.
La situation est celle dcrite par la figure 6.4 ci-dessous : les deux variables r1 et r2 font rfrence au mme objet :
r1 largeur : 2 hauteur : 4 r2 Figure 6.4Deux variables rfrenant le mme objet Rectangle
La mthode clone(), hrite dObject, peut tre invoque pour crer une copie dun objet :
Rectangle r3 = r1.clone()
Les deux objets obtenus aprs un tel clonage sont gaux (ils ont les mmes valeurs dans leurs variables dinstance) mais ne sont pas identiques.
r3 == r1 r3.equals(r1) // retourne false // retourne true
La mthode equals() teste lgalit du contenu des objets alors que loprateur == teste lidentit (sagit-il du mme objet?). Nous reviendrons plus en dtail sur ces questions au point 23.4. Comparaison des chanes de caractres Ce que nous venons de prsenter sapplique en particulier aux chanes de caractres (String). Les chanes de caractres tant des objets part entire, il faut utiliser la mthode equals() pour tester lgalit de deux chanes (mmes caractres) et non pas == (mme objets). On peut galement tester lordre lexicographique entre deux chanes avec la mthode compareTo() de la classe String.
95
Chaque classe fournit une mthode pour extraire la valeur simple de lobjet enveloppant :
boolean b2 = bObj.booleanValue(); int p2 = pObj.integerValue();
Nous sommes maintenant en mesure dutiliser la classe Vector pour crer une squence dentiers :
Vector v = new Vector; v.addElement(new Integer(5)); v.addElement(new Integer(2)); v.addElement(new Integer(90));
Chapitre 7
Les structures
Classes, interfaces, packages
Les diffrents lments permettant dorganiser et de structurer un programme Java, savoir les classes, les interfaces et les packages ont t introduits au chapitre prcdent. Nous allons maintenant y revenir afin dexaminer en dtail la syntaxe de leur dclaration.
Limportation peut galement tre utilise pour abrger le nom des interfaces. Sun Microsystems a propos un schma de nommage unique pour les packages, un peu la faon des URL. On trouve dans lidentifiant le nom de domaine assign au site o rside le package, suivi dun chemin dans larborescence des rpertoires menant au package (ou au sous-package). Exemple :
CH.Unige.Cui.java.projet3.pck4.classe
Par convention, le premier composant est crit entirement en majuscules (COM, GOV, FR, etc.), les suivants (commenant par une majuscule) faisant partie du nom de domaine assign au site (dans lordre inverse du format dadresses Internet). Ce schma permet didentifier de manire unique chaque
99
classe et vite toute collision. Ainsi chaque dveloppeur peut crer sa propre classe Rectangle! Il existe trois formes pour spcifier limportation. Le diagramme 7.3runit leurs syntaxes respectives tandis que les exemples ci-dessous illustrent leur utilisation :
Remarques : si plusieurs classes portent le mme nom dans des packages imports, le compilateur gnre une erreur; les classes java.lang.* sont automatiquement importes par dfaut;
100
cest pourquoi nous avons pu faire rfrence dans nos exemples aux classes System, Math, etc. du package java.lang sans lavoir import.
101
Les modificateurs de classe sont : abstract : indique que la classe est abstraite : certaines de ses mthodes nont pas de corps, elles seront implantes dans des sous-classes; final : une classe finale ne peut pas tre tendue par des sous-classes (ceci permet au compilateur deffectuer certaines optimisations dans le code, car il ne peut pas y avoir de surcharge); public : une classe est visible pour les classes des autres packages uniquement si elle est dclare publique. Une classe non publique nest visible que pour les classes dfinies lintrieur de son package. Les combinaisons suivantes de modificateurs sont autorises :
public; abstract; public abstract; final; public final
Les modificateurs dune interface sont : abstract : par dfinition une interface est abstraite; public : une interface est visible pour les classes des autres packages uniquement si elle est dclare publique. Une interface non publique nest visible que pour les classes dfinies lintrieur de son package. Les combinaisons suivantes de modificateurs dinterfaces sont autorises :
public; public abstract
Quand une interface tend une autre interface (super-interface), elle hrite de toutes ses constantes et mthodes. La classe qui implante cette interface doit implanter la fois les mthodes de linterface et celles de sa super-interface.
102
Cration dobjets
103
La dclaration dun constructeur suit le mme principe que celle dune mthode. Il ny a cependant pas de type de rsultat et le nom du constructeur doit tre identique celui de la classe.
Chapitre 8
Exceptions et processus
8.1 Exceptions
Pour traiter de manire structure les situations exceptionnelles, Java offre un mcanisme dexceptions. Une exception est un objet particulier de la classe Exception ou dune de ses sous-classes qui est cr au moment o une situation anormale est dtecte. Une fois cre, lexception est lance (ou leve) laide de linstruction throw, ce qui a pour effet darrter lexcution normale du programme et de propager lexception jusquau premier bloc dinstructions capable de la capter et de la traiter (catch). Le traitement dexceptions introduit une nouvelle structure dinstruction dcrite par le diagramme 8.1 ci-dessous.
En temps normal, linstruction suivant le try est excute. Si une exception survient, on saute directement au catch dont le type du paramtre correspond au type de lexception. Si aucun catch ne convient, lexception est propage aux blocs englobants puis, sils ne la captent pas, la mthode qui a invoqu celle o se trouve le try, et ainsi de suite, ventuellement jusquau systme dexcution Java qui interrompt alors le programme. Dans tous les cas de figure, linstruction suivant le finally est excute avant de quitter le bloc (mme si lexception na pas t capte et doit se propager).
Un processus (voir point suivant) peut se mettre en sommeil pour une certaine dure. Ce sommeil peut tre interrompu pour diverses raisons qui gnrent alors une exception de type InterruptedException :
try {Thread.sleep(2000);} // dort 2 secondes catch(InterruptedException signal) {} // continue simplement
Un problme peut survenir lors dune opration dentre-sortie, crant une exception de type IOException :
try {x=System.in.read(); ... catch (IOException e) { ... }
La tentative daccs un lment hors des limites dun tableau cause galement une exception :
try z = tab[i]; catch (ArrayIndexOutOfBounds ai) { System.out.println(ai.getMessage()); z = -1; }
Lexception est un objet qui peut contenir un texte informatif prcisant la nature du problme. La mthode getMessage() rcupre ce texte.
Processus et synchronisation
107
Il existe dj toute une hirarchie dexceptions dont le sommet est la classe Throwable.
Cration de processus
Pour faire fonctionner un processus, il faut : 1. Crer un objet de la classe Thread (ou de lune de ses sous-classes). 2. Dmarrer lexcution du processus en invoquant la mthode start(). Il y a deux manires de crer des processus en Java : dfinir une sous-classe de Thread qui redfinit la mthode run();
class Pro1 extends Thread { public void run() { // ICI ce que fait le processus // } } ... Pro1 p1 = new Pro1(); p1.start(); // dmarre un processus qui excute p1.run()
crer un objet de Thread avec le constructeur Thread(Runnable obj) auquel on passe un objet qui implante Runnable, cest--dire qui possde une mthode run().
class Pro2 implements Runnable { public void run() { // ICI ce que fait le processus // } ... Pro2 q = new Pro2(); Thread p2 = new Thread(q); p2.start(); // dmarre un processus qui excute q.run()
Synchronisation
Deux processus peuvent vouloir accder aux mmes objets en mme temps, ce qui peut causer des problmes de cohrence. Pensons un processus qui calcule la somme des nombres contenus dans un tableau alors que, simultanment, un autre processus dplace les lments du tableau pour les trier. Pour prvenir ce type de situation, un processus peut sassurer laccs exclusif un objet.
108
Linstruction synchronized() rserve un objet pour la dure de lexcution de linstruction qui suit puis le libre. Si lobjet est dj rserv (par un autre processus), synchronized() met le processus en attente jusqu ce que lobjet soit nouveau libre. lintrieur dun synchronized(o), le processus peut librer temporairement lobjet et se mettre en attente en appelant o.wait(). Il attendra jusqu ce quun autre processus excute un o.notify() puis libre lobjet o. Les mthodes wait() et notify() ne peuvent tre invoques que par un processus qui a rserv lobjet. Une mthode peut tre dclare synchronized, ce qui quivaut englober le corps de la mthode avec synchronized (this) {}. Nous verrons plusieurs exemples de processus dans la partie III et nous expliquerons plus en dtail la synchronisation et la concurrence au chapitre 25.
Partie III
9. LAPI Java 10. Retour sur les applets 11. Dessiner 12. Animer 13. Interagir 14. Composants dinteraction graphique 15. Gestion des conteneurs 16. Protocoles de mise en pages 17. Manipulation dimages et de sons 18. Les composants Swing 19. Entres-sorties et persistance des objets 20. Les accs au rseau (java.net)
Chapitre 9
LAPI Java
Lenvironnement de dveloppement Java est fourni avec une interface de programmation dapplications (API : Application Programming Interface) appele Core API, regroupant un ensemble de classes prdfinies dusage gnral que lon retrouve sur toutes les plates-formes. Cette API dfinit les briques de base utiliser dans tout programme Java afin de lui assurer une portabilit maximale de son code. Le Core package de Java est actuellement constitu dune soixantaine de packages, les 15 de premier niveau figurant dans la table ci-dessous. Chaque package est spcialis dans un domaine particulier. Tous proposent des solutions de nombreux problmes auxquels tout programmeur Java est tt ou tard confront.
Package java.applet Description Fournit les classes ncessaires pour crer une applet et les classes pour que lapplet puisse communiquer dans son contexte dexcution. Fournit toutes les classes pour crer des interfaces avec lutilisateur pour peindre et afficher des images. Contient les interfaces et les classes pour le dveloppement de composants logiciels JavaBeans. Fournit les interfaces et les classes pour la gestion des entres/sorties travers des canaux de donnes, la srialisation et les systmes de gestion de fichiers. Prsent (mais remanie depuis) Java1.0 Prsent Trait 10
java.awt
Prsent en partie
11 17
java.beans java.io
24 19
112
Package java.lang java.math Description Fournit les classes fondamentales pour la conception du langage de programmation Java. Fournit les interfaces et les classes pour effectuer des oprations en entier et dcimal dune prcision arbitraire (aussi longue que dsire). Fournit les classes pour la gestion du rseau et des communications. Fournit les services dinvocation distance des mthodes (Remote Method Invocation). Fournit les interfaces et les classes dans le cadre de la scurit. Fournit les services JDBC (Connection aux bases de donnes). Fournit les interfaces et les classes pour la manipulation des textes, des dates, des nombres et des messages dune manire indpendante des langues naturelles. Contient la gestion de quelques structures de donnes des utilitaires pour la manipulation des dates, un modle dvnement, etc. Dfinit un contrat entre les composants interface-utilisateur et des technologies dassistance lutilisateur (loupe, vocaliseur) Fournit un ensemble de composants lgers (entirement crits en Java, pour la gestion des interfaces, ils sont donc compltement indpendants de la plate-forme et ont un comportement similaire sur toutes les plate-formes). Fournit la correspondance entre l'API CORBA de l'OMG et le langage Java. Elle contient la classe ORB qui est un courtier d'objets (Object Request Broker) directement utilisable.
java.sql java.text
java.util
23 et ailleurs
javax.accessibility javax.swing
18
org.omg.CO RBA
30
Mthode de travail
113
Tout dabord faire un tour relativement complet des packages de base (java.applet, java.awt, java.io, java.lang, java.net, java.util). Ensuite, examiner les principes et les services spcialiss rendus principalement dans le cadre de la programmation distribue : accs aux bases de donnes (java.sql); invocation des mthodes distance (java.rmi); utilisation dun ORB (approche CORBA avec org.omg.CORBA); programmation des interfaces (javax.swing). Nous considrons ces ensembles de classes comme notre bote outils dont il va falloir apprendre se servir. Ainsi, avant de construire de nouveaux outils, il va tre important de bien connatre ceux dont nous disposons dj. Cette partie est consacre lapprentissage des fonctionnalits proposes par lAPI. Nous avons choisi de ne pas traiter les packages un un, mais de travailler autour de diffrents thmes : comment dessiner, crire? comment animer une applet? comment interagir avec la souris, avec le clavier? comment grer une fentre et son contenu? comment grer des fichiers? comment communiquer sur un rseau? Pour dcouvrir cette bote outils, nous vous proposons quelques lments de mthode ( prendre comme des conseils dami) : comprendre les concepts dfinis dans les packages; se familiariser avec les principales classes de ces packages; ne pas apprendre toutes les mthodes dfinies par ces classes; chercher, fouiller, butiner dans la documentation (trs complte), qui permet par exemple de trouver toutes les mthodes dune classe; examiner galement les mthodes hrites (examiner la super-classe). En rsum, pas de mmorisation systmatique mais plutt de lintuition concernant le comportement gnral dune classe. La mthode propose ici est la seule qui vous permettra de devenir autonome. En effet, les packages de base semblent dj consistants mais lensemble de lAPI java comporte plus de mille classes et plusieurs milliers de mthodes (7000). Seule une utilisation systmatique de la documentation fournie par Sun avec le JDK (Java Development Kit) vous permettra de survivre.
114
Ainsi que les sous-classes connues drives de Rectangle : Les interfaces qui sont implmentes par Rectangle : Rectangle hrite de la classe Rectangle2D des variables suivantes (des masques binaires pour situer un point (x,y) par rapport au rectangle dans lespace) :
OUT_BOTTOM, OUT_LEFT, OUT_RIGHT, OUT_TOP Shape, Serializable
Lobservation du package Java.awt nous indique que ces variables sont de type int et quelles sont public, ce qui signifie quon peut y accder dans toute instance de Rectangle. Le tableau 9.3 numre les constructeurs de cette classe.
Constructeur
Rectangle() Rectangle(int,int) Rectangle(int,int, int,int)
Description Construit un nouveau rectangle. Construit un nouveau rectangle et linitialise avec les paramtres width et height spcifis. Construit un nouveau rectangle et linitialise avec les paramtres x, y, width et height spcifis.
115
Description Construit un nouveau rectangle et linitialise avec le paramtre Dimension (un autre objet). Construit un nouveau rectangle et linitialise avec le paramtre Point (un autre objet). Construit un nouveau rectangle et linitialise avec les paramtres Point et Dimension (deux objets). Construit un nouveau Rectangle, initialis avec les donnes du rectangle spcifi.
Nous constatons que lon peut travailler soit directement sur les variables dinstance des objets Rectangle, soit dans un modle plus labor bas sur les concepts de Point et de Dimension. Les diffrentes mthodes dclares dans la classe Rectangle (tableau 9.4) fournissent des oprations de composition, de manipulation et de comparaison.
Mthode
add(int, int)
Description Ajoute une coordonne (x,y) au rectangle, redfinit les dimensions du rectangle pour que celuici contienne ce point. Ajoute un Point au rectangle, redfinit les dimensions du rectangle pour que celui-ci contienne ce point. Ajoute un Rectangle au rectangle, redfinit les dimensions du rectangle pour que celui-ci contienne ce rectangle. Dtermine si le rectangle contient le point de coordonnes (x,y). Dtermine si le rectangle contient entirement le rectangle spcifi par les coordonnes (x,y) et les dimensions (w,h). Dtermine si le rectangle contient le point. Dtermine si le rectangle contient entirement le rectangle pass en paramtre. Retourne un nouveau rectangle (type Rectangle2D) reprsentant lintersection des deux rectangles.
add(Point)
add(Rectangle)
116
Mthode
createUnion(Rectangle2D)
equals(Object) getBounds()
getBounds2D() getHeight() getLocation() getSize() getWidth() getX() getY() grow(int, int) inside(int,int) intersection(Rectangle) intersects(Rectangle) isEmpty() move(int, int) outcode(double,double)
117
Description Dfinit les bornes du rectangle avec les coordonnes (x,y) et les dimensions (w,h). Dfinit les bornes du rectangle avec celles du rectangle donnes en paramtre. Dplace ce rectangle la position (x,y). Dplace ce rectangle aux coordonnes du point. Dfinit les bornes du rectangle avec les coordonnes (x,y) et les dimensions (w,h) donnes en double prcision. Dfinit ce rectangle la dimension donne. Dfinit ce rectangle aux dimensions (w,h). Retourne sous forme de String les valeurs dfinissant le rectangle. Effectue une translation sur le rectangle. Calcule lunion de deux rectangles.
On peut constater que loutil Rectangle est bien afft, mais quil peut encore tre tendu (si le cur vous en dit) en dfinissant sa surface, son primtre, etc. Mais ce nest pas tout, un objet hrite de nombreuses mthodes de sa filiation. Examinons cette dernire. Mthodes hrites de la classe java.awt.geom.Rectangle2D :
add, add, add, contains, contains, getPathIterator, getPathIterator, hashCode, intersect, intersects, intersectsLine, intersectsLine, outcode, setFrame, setRect, union
Comment se rappeler ce quil y a dans cette classe? Fermez les yeux, imaginez un monde de Rectangles : ils se crent, grandissent, se dplacent, interagissent, fusionnent, etc. Nous avons bien l les bonnes mthodes, celles qui rgissent le
118
monde des Rectangles. Aussi vaut-il mieux comprendre ce monde que tenter de mmoriser les dtails des mthodes de cette classe. Dans la suite de cette partie, nous examinerons plusieurs autres mondes sans pour autant tre exhaustif, car nous nous intresserons principalement aux interactions entre tous ces mondes. Dans la documentation de Sun, on trouvera une description dtaille de chacune des classes ou chacun des champs que nous avons cits. Nous donnons sans le traduire un exemple de cette documentation pour la mthode translate.
public void translate(int x, int y) Translates this Rectangle the indicated distance, to the right along the x coordinate axis, and downward along the y coordinate axis. Parameters: dx - the distance to move this Rectangle along the x axis dy - the distance to move this Rectangle along the y axis See Also: setLocation(int, int), setLocation(java.awt.Point)
la fin de chaque chapitre, nous inviterons le lecteur continuer son exploration en lui proposant quelques exercices.
Chapitre 10
120
une applet ne peut pas communiquer avec dautres machines que celle depuis laquelle elle a t charge; une applet ne peut pas dmarrer lexcution de programmes sur le systme du client; une applet ne peut pas charger de programmes natifs sur le systme du client (DDL, driver, etc.). Le client peut galement configurer le degr de scurit quil dsire. Cette souplesse provient du fait que le code Java est destin tre excut sur une machine virtuelle. Celle-ci (incorpore dans le butineur Web) est le passage oblig entre le systme du client et le code du programme charg. Il est ainsi possible de contrler le comportement de nimporte quel programme : toute opration daccs aux ressources (fichiers, communications) devra obligatoirement transiter par la machine virtuelle, qui peut la refuser si elle nest pas autorise. Nous reviendrons plus en dtail sur ces aspects scurit au chapitre 27.
Une applet, comme nimporte quelle classe, peut tre plus ou moins complexe et faire rfrence dautres classes. Elle peut galement implanter des interfaces. Lexemple suivant est une applet qui dessine un carr noir (voir applet 1) :
import java.awt.Graphics; public class ComportementApplet extends java.applet.Applet { public void paint(Graphics g) { g.fillRect(5,5,40,40); } }
Pour pouvoir excuter cette applet, il faut tout dabord la compiler. Le rsultat de la compilation (une fois les erreurs corriges) est un fichier portant le nom de lapplet suivi de lextension .class (ComportementApplet.class) indiquant quil sagit de code excutable. Il faut ensuite incorporer un appel ce fichier de code dans une page HTML, laide du dlimiteur <APPLET>. Lexemple qui suit montre les paramtres dclarer, dans le cas o la page HTML et le code de lapplet rsident dans le mme rpertoire. Nous devons obligatoirement prciser : le nom du fichier de code de lapplet (ComportementApplet.class); la taille de la surface occupe par lapplet dans la page HTML lors de son excution.
121
Il ne reste alors plus qu charger la page HTML dans un butineur capable dexcuter du code Java pour obtenir notre premire applet :
Que defforts pour un rsultat bien modeste, alors quune simple image gif ferait aussi bien laffaire! Mais que de promesses galement, si lon y rflchit : il est possible de modifier le programme de lapplet afin de lui donner un nouveau comportement sans modifier la page HTML et sans avoir distribuer la nouvelle version aux clients; il est possible dincorporer cette applet dans plusieurs pages HTML et de lui donner des comportements diffrents, selon les paramtres qui lui sont associs; il est possible que dautres serveurs fassent rfrence cette applet; il est possible quun programmeur dveloppe sur un Macintosh du code destin des utilisateurs de PC ou de stations Unix (et vice versa); il est possible de transformer une page HTML en tableur, en modeleur 3D, en cockpit davion, en machine sous, etc.
122
voir dans le code HTML un texte de substitution lapplet. Deux solutions existent : placer du code HTML entre les deux dlimiteurs dinvocation <APPLET> et </APPLET>. Ce code sera alors interprt par le butineur; ajouter loption alt=texte dans le dlimiteur. Ce texte sera affich dans le cas o le butineur connat le dlimiteur <APPLET> mais quil ne peut pas excuter lapplet.
Le diagramme 10.2 dcrit les rgles didentification de lapplet. Loption code est obligatoire, elle dfinit le nom du fichier contenant le code de lapplet. Le chemin daccs doit tre imprativement dfini dans loption codebase sil est diffrent de celui de la page HTML contenant linvocation de lapplet. Loption name permet de donner un nom lapplet lors de son excution dans le butineur. Plusieurs applets peuvent ainsi cohabiter dans une mme page et ventuellement collaborer une tche (changer des informations, se synchroniser).
La taille de lapplet est dfinie laide des deux paramtres width (largeur) et height (hauteur), indiqus en pixels. On peut galement prciser lalignement de lapplet dans la page et lespace laisser vide autour de lapplet (diagramme 10.3).
Examinons ces diffrentes options laide dexemples. Ainsi, lapplet 2 montre que :
123
lespace occup par lapplet se comporte de faon similaire lespace occup par une image; lalignement horizontal situe lapplet par rapport au texte; la mme applet peut tre invoque plusieurs fois dans une mme page.
<html> <head><title>Comportement Applet</title></head> <h1>comme une image</h1> <applet code=ComportementApplet.class width=50 height=50 align=left> votre butineur ne sait pas excuter du Java, dommage!<p> </applet> Ce texte doit continuer droite de l'applet et couler sans problme comme avec une image.<p> <applet code=ComportementApplet.class width=50 height=50 align=right> </applet> Ce texte doit continuer gauche de l'applet et couler sans problme comme avec une image.<p> </body> </html>
Applet 2 : Emplacements occups par une applet dans une page HTML
Lapplet 3 illustre lutilisation des options vspace et hspace qui permettent de dfinir un cadre vide autour de la surface occupe par lapplet :
<html> <head><title>Comportement Applet</title></head> <applet code=ComportementApplet.class width=50 height=50 align=left vspace=50 hspace=30> votre butineur ne sait pas executer du Java, dommage!<p> </applet> <h1>alignement</h1> Ce texte doit continuer droite du cadre de l'applet et couler sans problme comme avec une image.<p> </body> </html>
Enfin, examinons les possibilits dalignement vertical (par le haut, par le milieu et par le bas). Chaque alignement peut agir de deux manires : lune relative au
124
texte actuellement utilis dans la ligne, lautre absolue. Cette seconde manire permet de saligner sur les lments les plus grands de la ligne courante.
Lapplet 4 illustre ces possibilits laide dune deuxime applet dessinant un carr plus grand, afin de crer des diffrences de taille dans la mme ligne.
<html> <head><title>Comportement Applet</title></head> <h1>alignement ...</h1> ligne de base texttop <applet code=ComportementApplet2.class width=80 height=80 align=texttop></applet> absolu absbottom <applet code=ComportementApplet.class width=50 height=50 align=absbottom></applet><br> ligne de base middle <applet code=ComportementApplet2.class width=80 height=80 align=middle></applet> absolu top <applet code=ComportementApplet.class width=50 height=50 align=top></applet><br> ligne de base bottom <applet code=ComportementApplet2.class width=80 height=80 align=bottom></applet> absolu absmiddle <applet code=ComportementApplet.class width=50 height=50 align=absmiddle></applet><br> </body> </html>
125
Comme nous lavons indiqu au point 10.1, une applet peut recevoir des paramtres inclus dans la page HTML, ce qui permet dtendre son comportement (ainsi que celui de HTML). Chaque paramtre est enferm dans un dlimiteur, auquel on associe un nom et une valeur (diagramme 10.5).
Dans lapplet 5, nous utilisons Java pour dessiner des rectangles noirs de diffrentes tailles donnes en paramtres. Pour accder un paramtre depuis lapplet, nous faisons appel une mthode getParameter("nom_du_paramtre") qui permet de rcuprer (dans une chane de caractres) la valeur associe ce paramtre. Ensuite, nous transformons cette chane de caractres en un entier laide de la mthode approprie. Ce programme utilise galement la mthode resize() qui demande au butineur de redimensionner la taille occupe par lapplet (les paramtres width et height sont alors redfinis).
import java.awt.Graphics; public class BlackRect extends java.applet.Applet { String parametre; int tailleRect;
126
On peut aisment imaginer dajouter dautres paramtres permettant de spcifier la couleur ou la forme des objets gomtriques dessiner. On verra plus loin quil est possible de spcifier le chargement dun ensemble de classes dans une applet au moyen des fichiers darchive .jar. Nous avons plac le code permettant de rcuprer les paramtres dans une mthode init() appartenant lapplet. Voyons cela de plus prs, en tudiant le cycle de vie des applets, avant den programmer de plus compliques.
127
init() : aprs son chargement (ou lors dun rechargement), lapplet excute cette mthode dinitialisation; start() : est invoque directement aprs linitialisation, ainsi quaprs un stop(), si le document contenant lapplet redevient nouveau visible pour lutilisateur; stop() : est invoque lorsque le document contenant lapplet disparat (changement de page HTML); en redfinissant stop(), on peut interrompre un traitement (par exemple une animation) si lapplet nest plus visible par lutilisateur; destroy() : est invoque avant la disparition de lapplet, afin de restituer les ressources et de quitter proprement le systme. On peut redfinir chacune de ces mthodes si lon tient donner un comportement particulier lapplet durant ces transitions. En fait, lapplet hrite de la classe java.awt.Component et sa principale activit sera paint(). Ceci explique pourquoi notre premire applet redfinissait cette mthode.
init()
Chapitre 11
Dessiner
Nous allons examiner comment dessiner dans lespace occup par une applet. Pour cela, nous dcrivons en dtail la classe Graphics qui contient de nombreuses mthodes de dessin. Elle se trouve dans le package java.awt et doit tre importe par toute classe dsirant lutiliser. Lactivit principale dune applet graphique est dfinie dans sa mthode paint(). Celle-ci est invoque lors dvnements ncessitant de redessiner la surface occupe par lapplet. La mthode paint() reoit comme paramtre un objet de la classe Graphics dcrivant lenvironnement graphique courant (couleurs, fond). Nos applets auront donc lallure suivante :
import java.awt.Graphics; public class Figure extends java.applet.Applet { public void paint(Graphics g) { ... } }
11.1 La feuille
La feuille de dessin est reprsente par une matrice de points dont chaque coordonne est dfinie par un couple dentiers. La classe Point (variables dinstance x pour horizontal et y pour vertical) permet de manipuler des coordonnes. La mthode getSize() fournit la taille de la feuille sous la forme dun objet de la classe Dimension (variables dinstance width : largeur et height : hauteur). Par consquent, les coordonnes des quatre coins de la feuille sont : (0 , 0) : le coin suprieur gauche; (getSize().width , 0) : le coin suprieur droit;
130
Chapitre 11 Dessiner
2, 5 +Y
En dessinant un ensemble de segments de droites (applet 7), on peut dessiner une fonction f (ne faites pas attention aux appels getSize(), ils sont l pour cadrer la fonction cosinus dans la feuille de dessin). La boucle for calcule, pour chaque coordonne x de la feuille, le segment de droite qui le relie au prochain point de la courbe.
import java.awt.Graphics; public class Figure extends java.applet.Applet { double f(double x) { return (Math.cos(x/10)+1) * getSize().height / 2; } public void paint(Graphics g) {
1. On ne prsente que les extraits significatifs des applets. Le texte complet de lapplet contient : import...; class...; etc.
Rectangles
for (int x = 0 ; x < getSize().width ; x++) { g.drawLine(x, (int)f(x), x + 1, (int)f(x + 1)); } } }
131
11.3 Rectangles
La classe Graphics propose de nombreuses mthodes capables de dessiner des formes gomtriques : rectangles, polygones, ovales et arcs. Pour chacune de ces formes, il existe une paire de mthodes : draw... qui dessine le contour de la forme et fill... qui remplit la forme. Dans le cas des rectangles, nous devons indiquer les paramtres suivants dans lordre : int x : la coordonne x du coin suprieur gauche; int y : la coordonne y du coin suprieur gauche; int width : la largeur du rectangle; int height : la hauteur du rectangle. Lapplet 8 ci-dessous dessine deux rectangles cte cte :
public void paint(Graphics g) { g.drawRect(50,30,20,30); g.fillRect(80,30,20,30); }
La classe Graphics propose galement des rectangles aux coins arrondis; il faut alors ajouter deux paramtres : int arrondiX : largeur de larrondi (axe des X); int arrondiY : hauteur de larrondi (axe des Y). Lapplet 9 le montre en dessinant deux rectangles arrondis cte cte :
public void paint(Graphics g) { g.drawRoundRect(50,70,20,30,15,15); g.fillRoundRect(80,70,20,30,15,20); }
132
Chapitre 11 Dessiner
Enfin, des rectangles peuvent tre dessins en relief (peu visible selon les butineurs). Un paramtre supplmentaire de type boolen indique : false : le rectangle est en relief; true : le rectangle est en creux. Lapplet 10 dessine un rectangle en creux ( gauche) et un en relief ( droite) :
public void paint(Graphics g) { g.draw3DRect(50,110,20,30,true); g.fill3DRect(80,110,20,30,false); }
11.4 Polygones
Le dessin dun polygone requiert deux tableaux de coordonnes. Lun pour les valeurs en X et lautre pour les valeurs en Y. Un polygone nest pas ferm automatiquement. Le nombre de points dessiner doit tre indiqu au moment de lappel la mthode de dessin. Lapplet 11 dessine deux polygones, dont lun est rempli en invoquant la mthode fillPolygon(). On notera au passage la manire dinitialiser des tableaux et celle de rcuprer leur taille grce la mthode length() :
public void paint(Graphics g) { int listeX[]={50,40,80,100,55}; int listeY[]={150,170,200,170,160}; int nbrXY=listeX.length; // nombre de points dessiner g.drawPolygon(listeX, listeY, nbrXY); int listeY2[]={200,220,250,220,210}; g.fillPolygon(listeX, listeY2, nbrXY); }
Gommer, copier
133
che du rectangle). noter que pour obtenir un cercle, hauteur doit tre gale largeur. Lapplet 12 dessine ainsi un ovale et un cercle :
public void paint(Graphics g) { g.drawOval(120,30,20,30); g.fillOval(150,30,30,30); }
Il est galement possible de dessiner des arcs. Deux paramtres supplmentaires (exprims en degrs) sont ncessaires : le premier indique langle de dpart de larc, le second les degrs ncessaires la ralisation du dessin. Lapplet 13 dessine deux arcs. On remarquera que lon peut associer des valeurs ngatives aux paramtres exprims en degrs.
public void paint(Graphics g) { g.drawArc(120,70,20,30,45,180); g.fillArc(150,70,30,30,45,-150); }
La mthode copyArea() copie une zone rectangulaire une nouvelle coordonne (nx, ny) :
g.copyArea(x, y, largeur, hauteur, nx, ny);
134
Chapitre 11 Dessiner
11.7 Colorier
Le package awt dfinit une classe Color pour reprsenter les couleurs. Une couleur est code sur 24 bits : huit pour chacune des trois couleurs fondamentales de la vido (rouge, vert, bleu), ce qui reprsente environ seize millions de possibilits. Le nombre de couleurs effectivement affiches dpend bien entendu des capacits de votre cran et du butineur. La classe Color propose galement une palette de couleurs prdfinies (voir tableau 11.1).
Couleur Blanc Gris ple Gris Gris fonc Noir Rouge Vert Bleu Jaune Magenta Cyan Rose Orange Nom de couleur
Color.white Color.lightGray Color.gray Color. darkGray Color.black Color.red Color.green Color.blue Color.yellow Color. magenta Color. cyan Color.pink Color.orange
On peut dfinir de nouvelles couleurs et tendre la palette laide de la mthode Color(R, V, B) o les valeurs de R, V et B sont comprises entre 0 et 255 (ou entre 0.0 et 1.0). Exemple :
Color bleuPale = new Color(0,0,80);
La couleur du fond (arrire-plan) est dfinie par la mthode setBack ground(Color) de la classe Component (Applet hrite de cette classe abstraite). Lexemple suivant impose un fond blanc :
setBackground(Color.white);
crire
135
tuelle du fond tandis que la mthode setForeground(Color) impose une couleur de dessin, par exemple le rose :
setForeground(Color.pink);
La classe Graphics propose encore les mthodes setColor(Color) pour redfinir la couleur avec laquelle on dessine et getColor() pour connatre la couleur de dessin courante. Regardez la documentation pour les autres constructeurs de Color(). Il existe deux mthodes brigther() et darker() qui permettent dobtenir des couleurs plus claires et plus fonces ayant la mme tonalit que la couleur sur laquelle elles sont appliques.
11.8 crire
La classe Graphics traite non seulement des formes gomtriques mais galement du texte de diffrentes tailles, fontes, couleurs, etc. La mthode drawString() permet de dessiner une chane de caractres partir dune coordonne (x,y). Lapplet 14 montre que la couleur courante est galement utilise pour le dessin des caractres.
import java.awt.Graphics; import java.awt.Color; public class MaPremiereApplet extends java.applet.Applet { public void paint(Graphics g) { g.setColor(Color.black); g.drawString("Ma premire applet politise!", 50, 30); g.setColor(Color.blue); g.drawString("Libert", 50, 60); g.setColor(Color.white); g.drawString("Egalit", 50, 90); g.setColor(Color.red); g.drawString("Fraternit", 50, 120); } }
136
Chapitre 11 Dessiner
Les polices
137
La classe Font fournit des informations propos dune fonte (voir tableau 11.2). Ainsi, la police courante est obtenue laide de la mthode getFont() applique un composant graphique.
Mthode
getName() getSize() getStyle() isPlain() isBold() isItalic()
Description (information propos de la fonte) Retourne un string indiquant le nom de la fonte. Retourne un entier indiquant la taille de la fonte. Retourne un entier indiquant le style (0, 1, 2, 3). Retourne un boolen, vrai si le style est normal. Retourne un boolen, vrai si le style est gras. Retourne un boolen, vrai si le style est italique.
Java 2 a particulirement dvelopp la class Font. Les concepts de caractre et de glyphe sont entirement spars. Il est donc possible dutiliser les ligatures, par exemple les deux caractres, f suivi de i deviennent un seul glyphe fi. Les police connues par Java sont toutes celles connues par le systme sur lequel sexcute le code. La mthode getAllFonts() permet dobtenir cette liste. Il existe des mthodes pour crer, driver et transformer des polices existantes et ainsi den obtenir de nouvelles. Il nexiste donc priori aucune limitation typographique pour le dveloppeur Java. Il ne lui suffit que dun peu de courage pour entrer dans cet univers! En utilisant des polices connues dun seul systme dexploitation, on risque de perdre la mobilit du code Java. Il faut donc obtenir un quilibre entre la mobilit et lesthtique. Pour permettre la justification prcise des caractres, la classe java.awt.FontMetrics calcule la taille occupe par une chane de caractres. Il sera donc possible, par exemple, de centrer un texte dans une applet dont la taille varie. Prcisons que toutes ces mthodes utilisent le point comme unit.
138
Mthode
stringWidth() charWidth() getAscent() getDescent() getLeading() getHeight()
Chapitre 11 Dessiner
Description (information propos dune chane) Retourne un entier indiquant la largeur dune chane. Retourne un entier indiquant la largeur dun caractre. Retourne un entier indiquant la hauteur de la fonte audessus de la ligne de base. Retourne un entier indiquant la hauteur de la fonte audessous de la ligne de base. Retourne un entier indiquant lespace entre les lignes. Retourne un entier indiquant la hauteur totale de la fonte.
Dans lapplet 16, nous dsirons centrer nos chanes de caractres. Nous construisons cet effet une mthode writeCenter() qui reoit pour paramtres : g le composant graphique dans lequel elle va dessiner; s la chane crire; y la hauteur de cette chane. La mthode getFontMetrics(g.getFont()) permet de connatre la mtrique actuellement utilise par le composant graphique. Linstruction java.awt.* importe toutes les classes du package awt :
import java.awt.*; public class MonPremierApplet extends java.applet.Applet { Font helvetica18Normal = new Font("Helvetica",Font.PLAIN,18); public void writeCenter(Graphics g, String s, int y){ FontMetrics metriqueCourante=getFontMetrics(g.getFont()); g.drawString( s, (getSize().width-metriqueCourante.stringWidth(s))/2, y); } public void paint(Graphics g) { g.setColor(Color.blue); g.setFont(helvetica18Normal); writeCenter(g, "Le mme avec emphase au centre!", 30); writeCenter(g, "Libert", 60); writeCenter(g, "Egalit", 90); writeCenter(g, "Fraternit", 120); } }
139
Cet exemple est un peu simplifi. Dans labsolu, on ne connat pas la hauteur des caractres qui vont simprimer et nous aurions d interroger la fonte sur sa taille avec les mthodes de FontMetrics et non utiliser un interligne fixe. La classe FontMetrics propose dautres mthodes que celles dcrites ci-dessus pour mesurer lespace pris par une chane de caractres. noter la mthode getStringBounds() qui existe en plusieurs variantes et qui retourne un objet Rectangle2D donnant les dimensions du texte afficher dans un objet Graphics (une applet, par exemple). Dans lexemple suivant, on a utilis cette mthode pour redfinir la mthode writeCenter(). On remarquera la conversion de type (casting) vers le type Rectangle qui possde la mthode width() et qui est sous-classe de Rectangle2D.
public void writeCenter(Graphics g, String s, int y){ FontMetrics metriqueCourante= getFontMetrics(g.getFont()); g.drawString(s,(getSize().width((Rectangle)metriqueCourante.getStringBounds(s,g)).width)/2, y);
La fonction f reprsenter est le sinus du carr de la distance dun point sur le plan par rapport lorigine (ou plus simplement : une sorte de vague oscillant de plus en plus vite). La valeur de f est comprise entre 1.0 et -1.0.
double f(double x, double y) { return (Math.sin((x*x+y*y)/5000)); }
140
Chapitre 11 Dessiner
Nous redfinissons la mthode paint() et dclarons une variable pour chacune des couleurs de base. offsetx et offsety sont des constantes nous permettant de recentrer le dessin dans lespace occup par lapplet :
public void paint(Graphics g) { int rouge, vert, bleu; int offsetx, offsety;
Nous initialisons nos variables (on peut aussi le faire lors de la dclaration!). getSize().width et getSize().height permettent de rcuprer la taille de la zone de dessin.
vert=0; bleu = 128; offsetx=getSize().width/2; offsety=getSize().height/2;
Nous allons uniquement faire varier la nuance de la couleur rouge (de 0 255) en fonction de la valeur de f pour chaque coordonne du plan. La premire boucle balaie les valeurs x (axe horizontal) :
for (int x = 0 ; x < getSize().width ; x++) {
Pour chaque coordonne (x,y), on calcule la valeur de la fonction et on la convertit en une nuance de rouge :
rouge= (int) ((f(x-offsetx,y-offsety)+1)*128);
Nous pouvons alors dfinir une nouvelle couleur et lutiliser pour dessiner :
g.setColor(new Color(rouge,vert,bleu));
Nous dessinons le point (x,y) (une ligne dont les extrmits sont confondues) :
g.drawLine(x,y,x,y);
Le programme complet de reprsentation de la troisime dimension laide de nuances de rouge est donn ci-dessous (voir applet 17) :
import java.awt.Graphics; import java.awt.Color; public class Figure extends java.applet.Applet {
141
142
double p45=0.707; double f(double x, double y) { return (Math.sin((x*x+y*y)/5000)); }
Chapitre 11 Dessiner
public void paint(Graphics g) { int offsetx=(getSize().width+(int)( p45*getSize().height))/2; int offsety=(getSize().height)/2; for (int x=(int)(p45*getSize().height);x<getSize().width;x++){ for (int y = 0; y<getSize().height; y++) { x3=(int) (x-y*p45); y3=(int) (y*p45-50*f(x-offsetx,y-offsety) +offsety*p45/2); rouge= (int) ((f(x-offsetx,y-offsety)+1)*128); g.setColor(new Color(rouge,vert,bleu)); g.drawLine(x3,y3,x3,y3); } } } }
143
Nous dclarons trois variables (une pour chaque couleur de base) et une instance de la classe Rectangle :
public class Figure extends java.applet.Applet { int rouge,vert,bleu; Rectangle r = new Rectangle ();
Pour chaque rectangle, nous gnrons une couleur partir de trois intensits tires au hasard (notez les conversions en nombres entiers) :
vert = (int)(Math.random()*255.99); bleu = (int)(Math.random()*255.99); rouge = (int)(Math.random()*255.99); g.setColor(new Color(rouge,vert,bleu));
Pour chaque rectangle, nous tirons au hasard x et y, (la coordonne de son coin suprieur gauche) et lui attribuons une taille nulle :
r.x= (int)(Math.random()*getSize().width); r.y= (int)(Math.random()*getSize().height); r.width=0; r.height=0;
Ensuite, nous utilisons la mthode add() qui permet de redimensionner le rectangle afin quil contienne un point tir lui aussi au hasard :
r.add((int)(Math.random()*getSize().width), (int)(Math.random()*getSize().height));
Finalement, nous dessinons le rectangle. On remarquera que lon ne peut pas le dessiner directement, mais que lon doit faire appel ses variables dinstance (x, y, largeur, hauteur) qui, elles, le dfinissent :
g.fillRect(r.x,r.y,r.width,r.height); } } }
144
Chapitre 11 Dessiner
bleu = (int)(Math.random()*255.99); rouge = (int)(Math.random()*255.99); g.setColor(new Color(rouge,vert,bleu)); r.x= (int)(Math.random()*getSize().width); r.y= (int)(Math.random()*getSize().height); r.width=0; r.height=0; r.add((int)(Math.random()*getSize().width), (int)(Math.random()*getSize().height)); g.fillRect(r.x,r.y,r.width,r.height); } }
Premire et dernire
g.setColor(new Color(rouge,vert,bleu)); r.x= (int)(Math.random()*getSize().width); r.y= (int)(Math.random()*getSize().height); r.width=0; r.height=0; r.add((int)(Math.random()*getSize().width), (int)(Math.random()*getSize().height)); if (!r.intersects(interdit)) // test dintersection g.fillOval(r.x,r.y,r.width,r.height); } } }
145
public class MaPremiereApplet extends java.applet.Applet { Font helvetica14Normal = new Font("Helvetica",Font.PLAIN,14); Date maintenant; public void paint(Graphics g) { g.setColor(Color.black); g.setFont(helvetica14Normal); g.drawString("Certificat de la premire Applet", 50, 30); g.drawString("Dcern ", 50, 60);
146
Chapitre 11 Dessiner
g.setColor(Color.red); g.drawString("Nom: ........... , prnom: .........", 50, 90); maintenant = new Date(); g.drawString(maintenant.toString(), 50, 120); }
Chapitre 12
Animer
Avant de dcouvrir comment faire de lanimation en Java, il est important de bien comprendre le cycle de vie de lapplet. Nous rappelons que celui-ci est : init() ! start() " stop() ! destroy() Aprs lactivit start(), lapplet excute la mthode paint() du composant graphique. Cest en redfinissant cette mthode que nous avons introduit nos propres actions. Vous avez sans doute remarqu que si lapplet tait partiellement cache par une autre fentre, celle-ci se redessinait quand elle redevenait visible. En effet, le composant graphique reoit lordre de repeindre le composant. Il excute alors la mthode repaint(), qui elle-mme invoque update(), cette dernire faisant alors appel la mthode paint(). (Voir lapplet 54, p. 229.) Le programme ci-dessous doit vous permettre de tester ces diffrents comportements. chaque fois que le document disparat, il doit changer de couleur lors de son prochain affichage.
import java.awt.Graphics; import java.awt.Color; public class ComportementApplet extends java.applet.Applet { boolean ok; public void init() { ok=true; } public void start() { repaint(); } public void stop() { ok=!ok;}
148
Chapitre 12 Animer
public void paint(Graphics g) { if (ok) g.setColor(Color.green); else g.setColor(Color.red); g.fillRect(0,0,getSize().width,getSize().height); }
Maintenant que nous avons bien compris le comportement dune applet, nous allons faire plusieurs tentatives danimation. Pour simplifier, nous prendrons comme exemple laffichage de lheure (quelque chose de bien suisse et qui change en permanence!). Nous avons repris le programme de notre certificat (applet 21) en retirant tout ce qui ne concerne pas laffichage de la date.
Lide de lessai ci-dessous est de dessiner continuellement lheure en insrant lappel drawString() dans une boucle sans fin :
import java.awt.*; import java.util.Date; public class Animation extends java.applet.Applet { Font timesRoman24Gras = new Font("TimesRoman",Font.BOLD,24); Date maintenant;
149
Le rsultat est assez surprenant : on perd pratiquement tout contrle, car la machine se consacre entirement sa nouvelle tche : peindre et repeindre lheure. De plus, on recouvre continuellement ce que lon a dj dessin, de ce fait on ne voit plus rien! Ce dernier problme peut tre vit en effaant la surface que lon vient de dessiner avant dafficher une nouvelle heure. La boucle devient alors :
while (true) { g.clearRect(0,0,size().width,size().height); maintenant = new Date(); g.drawString(maintenant.toString(), 10, 40); }
Le rsultat est un clignotement trs intense de lheure, qui lutte pour tre affiche mais qui est immdiatement efface. Nanmoins, on voit les secondes dfiler. La remarque suivante doit certainement vous venir lesprit : pourquoi vouloir afficher si souvent un phnomne ne changeant que toutes les secondes? Penchons-nous sur la notion de Thread (dtaille au chapitre 25) afin de dcouvrir une meilleure manire de raliser une horloge ou toute autre animation. En Java, tout processus est un Thread, y compris celui excutant notre applet. Nous pouvons donc lui appliquer les mthodes de cette classe, en particulier celle qui met le processus en veille pendant un certain temps (Thread.sleep()), exprim en millisecondes. Nous en profitons pour entourer lappel Thread.sleep() de deux nouvelles instructions, try et catch, que n ous avons vues au point 8.1.
while (true) { g.clearRect(0,0,size().width,size().height); maintenant = new Date(); g.drawString(maintenant.toString(), 10, 40); try {Thread.sleep(1000);} catch(InterruptedException signal) {} }
Le rsultat est acceptable : chaque seconde, lheure est affiche. Cependant, nous navons pas vraiment ralis une animation. Lapplet a perdu son comportement global, elle ne reoit plus les appels repaint(), stop(), etc. car lexcution du processus est mise en veille dans la mthode paint().
150
Chapitre 12 Animer
Rsumons notre situation : nous voulons conserver le comportement normal de lapplet; nous voulons quelque chose qui force lapplet se redessiner toutes les secondes. Ce quelque chose ne peut malheureusement pas provenir de lapplet elle-mme. En effet, notre applet nest compose que dun seul processus, comme lindique le titre de cette section.
12.2 Multithread
Pour contourner ces difficults, il est ncessaire dutiliser un autre processus (Thread) possdant son propre flot dinstructions indpendant de lapplet. Le cycle de vie dun Thread est le suivant : start() : il est activ et commence excuter la mthode run(); run() : cette mthode constitue la tche effectuer par le processus; pour stopper un processus, il faut le laisser terminer lui-mme sa mthode run(). Pendant quil excute son activit (run()), il est possible quil soit : sleep() : endormi pour une certaine dure; join() : mis en attente de la fin dun autre processus. Cependant, aucun de ces vnements ne peut modifier le flot dinstructions dcrit dans la mthode run() quil excute. Tout au plus, il peut tre ralenti, synchronis ou temporis par rapport lexcution normale de ce flot.
151
stop = true
public class Animation extends java.applet.Applet implements Runnable { boolean stop=false; Font timesRoman24Gras = new Font("TimesRoman",Font.BOLD,24); Date maintenant; Thread actif; public void start() { actif = new Thread(this); actif.start(); } public void stop() { stop = true; actif = null; } public void run() {
152
while (!stop) { repaint(); try {Thread.sleep(1000);} catch(InterruptedException signal) {} } }
Chapitre 12 Animer
public void paint(Graphics g) { g.setColor(Color.red); g.setFont(timesRoman24Gras); maintenant = new Date(); g.drawString(maintenant.toString(), 10, 40); } }
Notre applet est habite par deux processus : le processus habituel qui appelle paint, start, stop suivant les circonstances et le processus actif qui fonctionne dans run et appelle aussi paint (toutes les secondes).
153
Nous avons lgrement modifi les mthodes start() et stop() afin de vrifier que nous ne lanons pas un processus dj actif et que nous narrtons pas un processus inexistant (par exemple, si lon arrte lapplet avant quelle excute la mthode start()). Nous allons maintenant nous familiariser avec ce squelette que nous appliquerons dans plusieurs exemples tout au long des chapitres suivants.
154
int oxm = 10, oym = 10, lm=79, hm=79, dm=4; int oxh = 20, oyh = 20, lh=59, hh=59, dh=6;
Chapitre 12 Animer
En examinant la classe Date, on remarque que les mthodes getHours(), getMinutes(), et getSeconds() nous permettent de rcuprer les valeurs utiles pour notre horloge. La seule difficult est dassocier une valeur horaire une position du cercle trigonomtrique : le sens horaire et le sens trigonomtrique tant opposs, on utilise linversion (le signe moins) pour rtablir la situation; le zro horaire et le zro trigonomtrique ntant pas situs au mme endroit, on utilise une constante (450) pour les dcaler. Douze heures devant correspondre 360 degrs, on multiplie par 30. Soixante minutes ou secondes devant correspondre 360 degrs, on multiplie par 6. On ajoute un petit coup de modulo 360 pour le cas o lon fait plusieurs tours et laffaire est rgle. Nous avons intgr la valeur des minutes dans le calcul de la position des heures, afin que le mouvement de laiguille soit continu (sinon elle ne se dplacerait quune fois toutes les heures). En utilisant ce qui vient dtre dit, nous obtenons les formules suivantes :
h=(-maintenant.get(Calendar.HOUR_OF_DAY)*30(maintenant.get(Calendar.MINUTE)*30)/60+450)%360; m=(-maintenant.get(Calendar.MINUTE)*6+450)%360; s=(-maintenant.get(Calendar.SECOND)*6+450)%360;
Il ne nous reste plus qu utiliser notre squelette danimation et dcrire compltement la mthode paint() afin quelle demande lheure au systme, calcule la position des aiguilles et les dessine chacune dans une couleur diffrente. Nous obtenons alors lapplet suivante :
import java.awt.Graphics; import java.awt.Color; import java.util.*; //<pre> public class Animation extends java.applet.Applet
155
GregorianCalendar maintenant; // on craint pas le bug de lan 2000 Thread actif; boolean stop = false; int int int int h,m,s; oxs = 0, oys = 0, ls=99, hs=99, ds=2; oxm = 10, oym = 10, lm=79, hm=79, dm=4; oxh = 20, oyh = 20, lh=59, hh=59, dh=6;
public void start() { if (actif==null); { actif = new Thread(this); actif.start(); } } public void stop() { stop = true; actif = null; } public void run() { while (!stop) { repaint(); try {Thread.sleep(1000);} catch(InterruptedException signal) {} } } public void paint(Graphics g) { maintenant = new GregorianCalendar(); g.setColor(Color.green); h=(-maintenant.get(Calendar.HOUR_OF_DAY)*30(maintenant.get(Calendar.MINUTE)*30)/60+450)%360; g.fillArc(oxh,oyh,lh,hh,h+dh,-2*dh); g.setColor(Color.blue); m=(-maintenant.get(Calendar.MINUTE)*6+450)%360; g.fillArc(oxm,oym,lm,hm,m+dm,-2*dm); g.setColor(Color.red); s=(-maintenant.get(Calendar.SECOND)*6+450)%360; g.fillArc(oxs,oys,ls,hs,s+ds,-2*ds); } }
156
Chapitre 12 Animer
La classe Actif1 tend la classe Thread. Nous devons donc redfinir la mthode run(). Comme variable dinstance, nous lui fournissons le rectangle dont elle doit contrler la coordonne x; ceci est effectu lors de linstanciation dun objet de la classe Actif1 (dans le constructeur). La mthode run() dfinit deux boucles (aller et retour) qui modifient la coordonne x du rectangle de manire incrmentale. Lattente entre deux modifications est proportionnelle lloignement de lorigine (ce qui donnera une impression dacclration du mouvement de lobjet) lors de son affichage. On remarquera la mthode arret() qui permet de mettre vrai la variable stop et qui permet de terminer la mthode run(). Code de la classe Actif1 :
//<pre> import java.awt.Graphics; import java.awt.Rectangle; class Actif1 extends Thread { private Rectangle r1; boolean stop = false; Actif1(Rectangle r){ r1=r; } public void run() { while (!stop) { for (int i=0;i<80;++i){ r1.x=i; try {Thread.sleep(i+5);} catch(InterruptedException signal) {} } for (int i=80;i>0;--i){ r1.x=i; try {Thread.sleep(i+5);} catch(InterruptedException signal) {} } } }
157
La classe Actif2 est trs semblable, mais elle modifie laxe y. Code de la classe Actif2 :
class Actif2 extends Thread { private Rectangle r1; boolean stop = false; Actif2(Rectangle r){ r1=r; } public void run() { while (!stop) { for (int i=0;i<80;++i){ r1.y=i; try {Thread.sleep(i+5);} catch(InterruptedException signal) {} } for (int i=80;i>0;--i){ r1.y=i; try {Thread.sleep(i+5);} catch(InterruptedException signal) {} } } } public void arret() {stop=true;} }
Dcrivons maintenant notre nouvelle applet, 24e du nom. Nous dclarons deux objets a1 et a2 de type Actif1 et Actif2. Nous conservons le squelette original danimation. La mthode run() de lanimation va initialiser nos deux processus en leur fournissant le rectangle sur lequel elles doivent travailler puis elle va lancer ces processus. Nos deux processus vont travailler sur le mme rectangle, lun le dplaant horizontalement, lautre verticalement. Ensuite, elle demandera rgulirement que lon redessine lapplet. La mthode paint() dessine le rectangle.
public class Animation extends java.applet.Applet implements Runnable { Thread actif; Actif1 a1; Actif2 a2; Rectangle r= new Rectangle(0,0,20,20); public void start() {
158
if (actif==null); { actif = new Thread(this); actif.start(); } } public void stop() { if (a1!=null) a1.arret(); if (a2!=null) a2.arret(); } public void run() { a1=new Actif1(r); a1.start(); a2=new Actif2(r); a2.start(); while (true) { repaint(); try {Thread.sleep(10);} catch(InterruptedException signal) {} } } public void paint(Graphics g) { g.fillRect(r.x,r.y,r.width,r.height); } }
Chapitre 12 Animer
Le rsultat est un rectangle noir qui oscille le long de la diagonale, en ayant une vitesse variable. En laissant fonctionner lapplet assez longtemps, une drive peut apparatre : le rectangle ne reste plus sur la diagonale. Ce comportement prouve bien que les processus ne sont pas compltement synchrones.
159
Nous avons ainsi une attente alatoire qui va faire dvier la trajectoire du rectangle autour de la diagonale. Modifions notre applet afin de contrler trois rectangles (voir applet 25) : les processus a1 et a2 contrlent le rectangle ra; les processus b1 et b2 contrlent le rectangle rb; les processus c1 et c2 contrlent le rectangle rc. La mthode paint() est redfinie afin de dessiner les trois rectangles. Code de lapplet avec trois rectangles :
public class Animation extends java.applet.Applet implements Runnable { boolean stop = false; Thread actif; Actif1 a1,b1,c1; Actif2 a2,b2,c2; Rectangle ra= new Rectangle(0,0,20,20); Rectangle rb= new Rectangle(0,0,10,10); Rectangle rc= new Rectangle(0,0,5,5); public void start() { if (actif==null); { actif = new Thread(this); actif.start(); } } public void stop() { if (actif!=null); { stop=true; if (a1!=null) a1.arret(); if (b1!=null) b1.arret(); if (c1!=null) c1.arret(); if (a2!=null) a2.arret(); if (b2!=null) b2.arret(); if (c2!=null) c2.arret(); actif = null; } } public void run() { a1=new Actif1(ra);a1.start(); a2=new Actif2(ra);a2.start(); b1=new Actif1(rb);b1.start(); b2=new Actif2(rb);b2.start(); c1=new Actif1(rc);c1.start(); c2=new Actif2(rc);c2.start(); while (!stop) { repaint(); try {Thread.sleep(10);}
160
catch(InterruptedException signal) {} } } public void paint(Graphics g) { g.fillRect(ra.x,ra.y,ra.width,ra.height); g.fillRect(rb.x,rb.y,rb.width,rb.height); g.fillRect(rc.x,rc.y,rc.width,rc.height); } }
Chapitre 12 Animer
Ces exemples montrent que lon peut grer de nombreux processus : on peut ainsi dclarer des matrices de processus. Cependant, cela peut poser quelques difficults de gestion. Dans notre cas, chaque processus travaillant sur une variable non partage (x ou y), il ny avait pas de risque de collision dans les activits. Nous verrons plus loin que lon doit utiliser des techniques de synchronisation pour grer des cooprations plus intenses entre les processus.
Un peu de posie
161
Pour raliser notre ide, il nous faut un endroit pour mmoriser les dix planches de quatorze sonnets. Une matrice de String fera parfaitement laffaire :
String q[] [] = new String[10][14];
La mthode run() doit, pour composer un sonnet, tirer au hasard une des dix planches. Ensuite, elle demande redessiner le sonnet nouvellement compos et elle attend une minute. Le rsultat du tirage au sort est mmoris dans le vecteur p :
int p[] = new int[14]; public void run() { while (!stop) { for (int i=0; i<p.length;i++) p[i]=(int)(Math.random()*9.99999); repaint(); try {Thread.sleep(60000);} catch(InterruptedException signal) {} } }
162
Chapitre 12 Animer
La mthode paint() doit redessiner le sonnet gnr (stock dans p). Pour chaque vers i, elle recherche la planche p[i] qui lui donne le vers q[p[i]][i]. Le vecteur strophe[] est utilis pour faire apparatre la structure du sonnet (4-4-3-3).
public void paint(Graphics g) { g.setColor(Color.red); g.setFont(timesRoman14Gras); for (int i=0; i<14;i++) g.drawString(q[p[i]][i], 10, 40+i*20+strophe[i]); } }
Comme toujours, nous utilisons notre squelette pour grer lanimation de lapplet.
import java.awt.Graphics; import java.awt.Color; import java.awt.Font; public class Animation extends java.applet.Applet implements Runnable { boolean stop=false; Font timesRoman14Gras = new Font("TimesRoman",Font.BOLD,14); int p[] = new int[14]; String q[] [] = new String[10][14]; int strophe[] = {0,0,0,0,15,15,15,15,30,30,30,45,45,45}; Thread actif; public void start() { if (actif==null); { actif = new Thread(this); actif.start(); } } public void stop() { if (actif!=null); { stop=true; actif = null; } } public void run() { while (!stop) { for (int i=0; i<p.length;i++) p[i]=(int)(Math.random()*9.99999); repaint(); try {Thread.sleep(60000);} catch(InterruptedException signal) {} }
Invitation explorer
}
163
public void init() { // la premire planche q[0][0]="Le roi de la pampa retourne sa chemise"; q[0][1]="pour la mettre scher aux cornes des taureaux"; q[0][2]="le corndbif en bote empeste la remise"; ... // la deuxime planche q[1][0]="Le cheval Parthnon s'nerve sur sa frise"; q[1][1]="depuis que lord Elgin ngligea ses naseaux"; q[1][2]="le Turc de ce temps-l pataugeait dans sa crise"; ... // les autres planches } public void paint(Graphics g) { g.setColor(Color.red); g.setFont(timesRoman14Gras); for (int i=0; i<14;i++) g.drawString(q[p[i]][i], 10, 40+i*20+strophe[i]); } }
Le lecteur patient pourra se procurer lintgrale des sonnets chez Gallimard afin de complter (pour son usage personnel) le code de la mthode init(). Il possdera ainsi une source inpuisable de posie!
Chapitre 13
Interagir
Jusqu prsent, nos programmes taient insensibles toutes les sollicitations extrieures. Dans ce chapitre, nous allons apprendre grer les interactions provenant de la souris et du clavier (pour dautres priphriques, il faut crire les classes capables de grer les vnements quils gnrent). Entre les versions 1.0 et 1.1 de Java, la gestion des vnements a t profondment modifie. tant donn quil existe encore beaucoup de codes crits selon la version 1.0 et que tous les utilisateurs nont pas encore de butineurs adapts la version 1.1, nous avons choisi de prsenter les deux modles de gestion dvnements. Si vous navez pas grer du code crit pour la version 1.0, vous pouvez aller directement au point 13.7.
166
Chapitre 13 Interagir
mouvements de la souris : chaque fois que cette mthode sera invoque, nous recevrons une instance de lvnement qui lui est associe. Nous pourrons alors connatre linstant (e.when) et la position (x,y) auxquels lvnement sest produit. Nous conservons ces valeurs dans des variables de lapplet (sourisX, sourisY et quand). La mthode mouseMove() doit retourner un boolen. Si celui-ci est vrai, cela signifie que lvnement est considr comme trait, sinon cet vnement peut tre transmis un autre objet pouvant aussi le traiter (par exemple si plusieurs objets sont empils sur la mme coordonne, il peut tre souhaitable que chacun dentre eux reoive lvnement). Code permettant dafficher les mouvements de la souris :
import java.awt.Graphics; import java.awt.Event; public class Interaction extends java.applet.Applet { int sourisX, sourisY; long quand; public boolean mouseMove(Event e, int x, int y){ quand=e.when; sourisX=x; sourisY=y; repaint(); return true; } public void paint(Graphics g) { g.drawString(quand+"=("+sourisX+","+sourisY+")" ,10,20); } }
En dplaant la souris, les coordonnes du curseur sont affiches, une estampille indiquant linstant de lvnement (en millisecondes) :
Gestion de la souris
167
bouton de la souris est enfonc dans la surface de lapplet; public boolean mouseUp(Event e, int x, int y) : invoque quand le bouton de la souris est relch dans la surface de lapplet; public boolean mouseMove(Event e, int x, int y) : invoque quand la souris se dplace, le bouton tant relch; public boolean mouseDrag(Event e, int x, int y) : invoque quand la souris se dplace, le bouton tant enfonc; public boolean mouseEnter(Event e, int x, int y) : invoque quand la souris entre dans la surface de lapplet; public boolean mouseExit(Event e, int x, int y) : invoque quand la souris sort de la surface de lapplet. Exemple de programme traitant les vnements de la souris : dans celui-ci, la position du bouton de la souris dtermine la couleur du dessin (enfonc = blanc, relch = rouge). Le rsultat est reprsent ci-dessous (applet 28) :
import java.awt.Graphics; import java.awt.Color; import java.awt.Event; public class Interaction extends java.applet.Applet { Color c=new Color(0,0,255); public boolean mouseDown(Event e, int x, int y){ c= new Color(255,255,255); repaint(); return true; } public boolean mouseUp(Event e, int x, int y){ c= new Color(255,0,0); repaint(); return true; } public void paint(Graphics g) { g.setColor(c); g.drawLine(0,0,size().width ,size().height); } }
En ajoutant le traitement de lvnement mouseDrag(), on peut modifier lextrmit du trait. Il suit alors tous les mouvements de la souris pendant que le bouton est enfonc (voir applet 29).
168
import java.awt.Graphics; import java.awt.Color; import java.awt.Event;
Chapitre 13 Interagir
public class Interaction extends java.applet.Applet { Color c=new Color(0,0,255); int dx=size().width; int dy=size().height; public boolean mouseDown(Event e, int x, int y){ c= new Color(255,255,255); repaint(); return true; } public boolean mouseUp(Event e, int x, int y){ c= new Color(255,0,0); repaint(); return true; } public boolean mouseDrag(Event e, int x, int y){ dx=x; dy=y; repaint(); return true; } public void paint(Graphics g) { g.setColor(c); g.drawLine(0,0,dx,dy); } }
169
terminer le type de lvnement. Dans le cas o lon ne sait pas comment traiter cet vnement, on fait appel la mthode de la super-classe.
import java.awt.Graphics; import java.awt.Color; import java.awt.Event; public class Interaction extends java.applet.Applet { Color c=new Color(0,0,255); int dx=size().width; int dy=size().height; public boolean handleEvent(Event e){ switch(e.id){ case Event.MOUSE_DOWN: c= new Color(255,255,255); break; case Event.MOUSE_UP: c= new Color(255,0,0); break; case Event.MOUSE_DRAG: dx=e.x; dy=e.y; break; default: return super.handleEvent(e); } repaint(); return true; } public void paint(Graphics g) { g.setColor(c); g.drawLine(0,0,dx,dy); } }
170
import java.awt.Event;
Chapitre 13 Interagir
public class Interaction extends java.applet.Applet { int x0,y0; public boolean handleEvent(Event e){ switch(e.id){ case Event.MOUSE_DRAG: Graphics g= getGraphics(); g.drawLine(x0,y0,e.x,e.y); case Event.MOUSE_DOWN: x0=e.x; y0=e.y; break; default: return super.handleEvent(e);} return true;} }
Touche reprsente Flche haut Flche bas Flche gauche Flche droite Touche home
Gestion du clavier
Constante
Event.END Event.PGUP Event.PGDN Event.F1 Event.F12
171
Touche reprsente Touche fin Dfilement page haut Dfilement page bas Touches de fonction F1 F12
Pour tester les touches de modification du clavier, il existe trois mthodes : public boolean shiftDown() : la touche majuscule est-elle enfonce? public boolean controlDown() : la touche de contrle est-elle enfonce? public boolean metaDown() : la touche de mta (alt) est-elle enfonce? Lapplet suivante (applet 31) montre comment grer le clavier. Ce programme modifie la taille des caractres affichs en utilisant les touches flche haut et flche bas. Il teste galement ltat de la touche majuscule.
import java.awt.Graphics; import java.awt.Font; import java.awt.Event; public class Interaction extends java.applet.Applet { int taille=12; char toucheCourante='?'; boolean majuscule; public boolean keyDown(Event e, int touche){ switch(touche){ case Event.DOWN:--taille;break; case Event.UP: ++taille;break; default: toucheCourante=(char)touche ; } setFont(new Font("Helvetica",Font.BOLD,taille)); majuscule=e.shiftDown(); repaint(); return true; } public void paint(Graphics g) { g.drawString("Taille="+taille+" maj="+majuscule,10,25); g.drawString(String.valueOf(toucheCourante),100,60); } }
172
Chapitre 13 Interagir
173
de possder les mthodes requises pour traiter ce type dvnement. De mme, tout objet peut tre source dvnements, il doit alors : possder une mthode dinscription et de dsinscription dcouteurs; transmettre les vnements en appelant les mthodes requises des couteurs. En gnral, une source peut avoir plusieurs couteurs diffrents qui lui sont attachs et un couteur peut tre inscrit auprs de plusieurs sources diffrentes.
Nous voil prts pour crire une applet qui affiche en permanence les coordonnes de la souris :
import java.awt.Graphics; import java.awt.Event; import java.awt.event.*; public class Interaction extends java.applet.Applet implements MouseMotionListener { int sourisX, sourisY; long quand; public void init() { this.addMouseMotionListener(this); // inscription } public void mouseMoved(MouseEvent e){ // extrait les informations de lvnement quand=e.getWhen(); sourisX=e.getX(); sourisY=e.getY(); repaint(); } public void mouseDragged(MouseEvent e) {} public void paint(Graphics g) {
174
Chapitre 13 Interagir
g.drawString(quand+"=("+sourisX+","+sourisY+")",10,20); }
On obtient le mme comportement que lapplet 27 p.166. Cette manire dcrire une applet qui rpond des vnements est la plus proche de celle utilise avec JDK 1.0, mais elle nest pas la plus lgante car il faut dfinir toutes les mthodes de linterface dcoute (en loccurrence MouseMotionListener), mme celles quon nutilise pas. Pour simplifier lcriture des couteurs, le package java.awt.event propose des classes toutes faites, appeles adaptateurs, qui ralisent chacune un couteur inactif. On dfinira alors un couteur par extension dun adaptateur, ce qui nous donne le code suivant :
import java.awt.Graphics; import java.awt.Event; import java.awt.event.*; public class InteractionI extends java.applet.Applet{ int sourisX, sourisY; long quand; class EcouteSouris extends MouseMotionAdapter { public void mouseMoved(MouseEvent e){ quand=e.getWhen(); sourisX=e.getX(); sourisY=e.getY(); repaint(); } } public void init() { this.addMouseMotionListener(new EcouteSouris()); } public void paint(Graphics g) { g.drawString(quand+"=("+sourisX+","+sourisY+")",10,20); } }
Ici, ladaptateur est une classe interne, ce qui lui permet daccder aux variables de lapplet. Lors de lappel denregistrement, on cre lobjet couteur (new EcouteSouris()). Finalement, on peut utiliser le mcanisme des classes anonymes pour viter de dfinir explicitement une classe couteur :
public class InteractionA extends java.applet.Applet { int sourisX, sourisY; long quand; public void init() { this.addMouseMotionListener(
175
Lexpression new MouseMotionAdapter() { } dfinit une classe qui tend MouseMotionAdapter et cre un objet de cette classe (lcouteur). Lcriture est plus compacte mais nest plus trs lisible car on mlange des dclarations de mthodes lintrieur dexpressions. Il vaut mieux viter dabuser de ce mcanisme. Si linterface MouseMotionListener permet de sinscrire pour recevoir les vnements de dplacement de la souris, linterface MouseListener permet de recevoir les clics souris (mthodes mousePressed(), mouseReleased() et mouseClicked()) et les entres/sorties du curseur sur la surface de composant (mouseEntered() et mouseExited()). Lvnement de type MouseEvent reu contient diffrentes informations que lon peut extraire laide de mthodes telles que : getWhen() : le temps auquel sest produit lvnement; getX(), getY() : la position du pointeur; getClickCount() : le nombre de clics sur ce mme point; isAltDown(), isAltGraphDown(), isControlDown(), isMetaDown(), isShiftDown() : vrai si la touche (modificateur) Alt, AltGr, Ctrl, Meta ou Shift tait enfonce lors de lvnement; getModifiers() : un codage sous forme dun int des touches enfonces. Dans le cas dune souris plusieurs boutons, on peut tester quel bouton a dclench lvnement avec lexpression :
(getModifiers() & BUTTONi_MASK) // i = 1, 2 ou 3
Le rsultat est diffrent de 0 si le bouton i a t press, relch ou cliqu (cest-dire press puis relch). Cependant, pour tre vraiment portable, une application ne devrait pas faire dhypothses sur le nombre de boutons dont est munie la souris.
176
Chapitre 13 Interagir
La mthode keyPressed est invoque lorsquune touche est enfonce. La mthode getKeyCode de la classe keyEvent fournit le code de la touche. Il sagit de codes correspondant un clavier virtuel indpendant de la machine utilise. Ces codes sont dfinis par une liste de constantes KeyEvent.VK_xxx. Dans cet exemple, nous utilisons VK_DOWN et VK_UP qui correspondent aux flches vers le bas et vers le haut. La mthode getKeyChar fournit un caractre lorsque la ou les touche(s) presse(s) corresponde(nt) un caractre. Il existe aussi une mthode keyTyped() qui nest invoque que lorsquun caractre est gnr par la ou les touches presse(s). Cette mthode ne permet videmment pas de capter les actions sur les touches de flches, de fonctions, majuscule, ctrl, alt, etc.
177
De mme que pour les vnement souris, les vnements clavier ont des mthodes isAltDown(), isAltGraphDown(), isControlDown(), isMetaDown() et isShiftDown() pour savoir quelle(s) touche(s) tai(en)t enfonce(s) au moment du clic.
Lorsque nous tudierons les composants dinteraction graphique nous indiquerons chaque fois quels sont les types dvnements quils peuvent gnrer. Il est intressant de noter quon peut considrer les actions de lutilisateur diffrents niveaux de dtail. Par exemple, lorsque lutilisateur agit sur un bouton de linterface on peut sintresser : uniquement au dclenchement de la commande associe au bouton (suite un clic souris); laction enfoncer le bouton (presser sur le bouton de la souris) suivie de laction relcher le bouton (relcher le bouton de la souris); tous les mouvements du pointeur de la souris sur ce composant. Il est donc possible de capter les vnements les plus pertinents selon le degr de sophistication de linterface que lon doit programmer.
178
Chapitre 13 Interagir
Finalement, rappelons que le mcanisme dvnement ne sert pas uniquement grer linterface utilisateur. Il offre un moyen de communication gnral entre objets. On peut, par exemple, concevoir un objet qui signale ses couteurs tout changement de valeur de lune de ses variables.
Chapitre 14
180
Button
Canvas
CheckBox
Choice
List
ScrollBar
Les boutons
public void paint(Graphics g) { g.drawString("Texte dessine", 100, 150); } }
181
Les paramtres dalignement sont des variables de classe constantes : Label.CENTER, Label.LEFT, Label.RIGHT. Par dfaut, lalignement gauche est utilis. Le tableau 14.1 dcrit les principales mthodes de la classe Label.
Mthode
Label() Label(String l) Label(String l, int a) getAlignment() getText() setAlignment(int a) setText(String label)
Dfinition Cre un libell sans texte. Cre un libell de texte. l Cre un libell de texte l et dalignement a. Retourne lalignement du libell. Retourne le texte du libell. Impose un alignement. Assigne un texte au label.
182
Les boutons
Mthode
Button(String b) getLabel() setLabel(String b)
183
Dfinition Cre un bouton avec libell b. Retourne le libell du bouton. Assigne un libell b. Ajoute un couteur daction l. Supprime un couteur. Dfinit le nom de commande qui sera donn aux vnements ActionEvent produits (par dfaut cest le libell du bouton). Retourne le nom de commande dfini.
getActionCommand()
Pour accder aux informations transmises par un vnement de type ActionEvent, on utilisera les mthodes de cette classe dcrites dans le tableau 14.3 cidessous.
Mthode
getSource() getActionCommand() getModifiers()
Dfinition Fournit lobjet qui a mis lvnement (mthode hrite de EventObject). Retourne le String reprsentant la commande associe cet vnement. Retourne un entier qui contient les codes des modificateurs (shift, alt, ctrl) associs lvnement. Retourne une reprsentation sous forme de String de lvnement (utile pour la mise au point).
paramString()
Le recours la mthode getSource() est ncessaire dans le cas o un objet (par exemple notre applet) est abonn plusieurs sources du mme type dvnement (par exemple, plusieurs boutons). Il faut noter que plusieurs boutons peuvent produire la mme commande et quun bouton peut produire diffrentes commandes au cours du temps. La classe ActionEvent fournit quatre constantes : ALT_MASK, CTRL_MASK,
184
META_MASK, SHIFT_MASK pour tester quel(s) modificateur(s) tai(en)t enfonc(s) au moment de lvnement. Par exemple :
public void actionPerformed(ActionEvent e) { if (e.getModifiers() & ActionEvent.SHIFT_MASK) { ... la touche SHIFT tait enfonce ...}
185
public void paint(Graphics g) { composition = ""; double p = 5.00; for (int i=0; i<ingredients.length; i++) if (ingredients[i].getState()) { composition += (" " + ingredients[i].getLabel()); p += prix[i]; } g.drawString(message, 20, 100); g.drawString("Une pizza du chef avec "+composition, 20, 120); g.drawString("Prix: "+p, 20, 140); } }
Dfinition Cre une bote cocher sans libell. Cre une bote cocher avec libell b. Retourne le titre de la bote cocher. Assigne un libell b. Retourne ltat de la bote cocher (boolen). Assigne ltat c la bote cocher.
Pour reconnatre le type de changement subi par une bote, on utilise la mthode getStateChange() de la classe ItemEvent.
186
public void paint(Graphics g) { Checkbox choix = dessert.getSelectedCheckbox(); g.drawString("Un dessert au choix: "+choix.getLabel(), 20, 120); } }
187
Dfinition Cre une bote cocher avec libell b, associe au groupe g dans ltat s. Associe la bote au groupe g.
Tableau 14.5 Mthodes de la classe Checkbox utilisant la notion de groupe Mthode ou constructeur
CheckboxGroup() getSelectedCheckbox() setSelectedCheckbox (Checkbox b)
Dfinition Cre un groupe. Retourne la bote cocher actuellement slectionne. Slectionne la bote cocher b.
188
public class Composant extends Applet implements ItemListener Choice parfum; public void init() { parfum = new Choice(); parfum.addItem("Vanille"); parfum.addItem("CHocolat"); parfum.addItem("Fraise"); parfum.addItem("Pistache"); parfum.addItem("Noisette"); parfum.addItem("Citron"); add(new Label("Parfum de la glace")); add(parfum); // ajoute le menu aprs le libell parfum.select("Vanille"); parfum.addItemListener(this); // l'applet coute le menu } public void itemStateChanged(ItemEvent e) { repaint(); } public void paint(Graphics g) { int parfumNo = parfum.getSelectedIndex() ; g.drawString("Glace no. "+parfumNo, 20, 100); }
Dfinition Cre un menu. Ajoute un article de libell b. Retourne le libell de larticle la position p. Supprime le premier article libell b. Fournit le nombre darticles du menu.
189
Dfinition Fournit le libell de larticle slectionn. Fournit la position de larticle slectionn. Slectionne larticle la position p. Ajoute (supprime) un couteur de slection darticles.
190
Dfinition Cre une liste de choix. Cre une liste de choix de n lignes visibles spcifiant si le choix multiple est autoris. Ajoute un article de libell l. Ajoute un article de libell l la position p. Supprime un article de libell l. Supprime larticle la position p. Remplace le libell de larticle la position p par l. Retourne le nombre darticles de la liste. Retourne le libell (String) de larticle la position p. Autorise ou non le choix multiple. Slectionne larticle la position p. Dslectionne larticle la position p.
191
Dfinition Retourne la position (int) de larticle slectionn. Retourne le libell (String) de larticle slectionn. Retourne les positions (int[]) des articles slectionns. Retourne les libells (String[]) des articles slectionns. Retourne un boolen qui indique si larticle p est slectionn ou non. Ajoute un couteur dactions (double clic et retour). Ajoute un couteur pour les changements de slection.
Dfinition Les classes TextField et TextArea ont leur propres constructeurs. Retourne le texte contenu dans le champ (String). Retourne le texte slectionn (String). Retourne la position de la fin du texte slectionn (int). Retourne la position du dbut du texte slectionn (int). Teste si le champ est ditable. Slectionne le texte de la position dbut la position fin.
192
Mthode
selectAll() setText(String l) setCaretPosition(int pos) getCaretPosition()
Le champ de texte sur une ligne est un objet de la classe TextField. Le contenu du champ peut tre dit par lutilisateur. La touche retour (return) gnre un vnement ActionEvent qui est transmis aux ventuels ActionListeners inscrits. Lvnement gnr contient la valeur du champ au moment o la touche fut presse. De plus, chaque modification du texte gnre un vnement TextEvent transmis aux TestListeners par appel de leur mthode textValueChanged(). Il est possible de spcifier un caractre dcho (exemple : -) afficher la place des caractres entrs, ce qui permet par exemple de saisir des mots de passe sans quils apparaissent en clair lcran. Les mthodes de la classe TextField sont prsentes dans le tableau 14.10; lapplet 38 montre la cration dun masque de saisie comportant plusieurs champs, elle coute les vnements TextEvent du champ code et vrifie si le contenu de ce champ correspond au mot de passe1 :
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Composant extends Applet implements TextListener { String msg; TextField np, adr, tel, code, message; public void init() { add(new Label("Nom et prenom")); add(np = new TextField(30)); add(new Label("Adresse")); add(adr = new TextField(30)); add(new Label("Telephone")); add(tel = new TextField("022/",30)); add(new Label("Code du club pizza!")); add(code = new TextField(10)); code.setEchoChar('-'); add(message = new TextField(15));
1. Attention, ne mettez jamais un mot de passe en clair dans une applet, il pourrait facilement tre retrouv !
193
code.addTextListener(this); } public void textValueChanged(TextEvent e) { if (e.getSource() == code) { if (code.getText().equals("secret")) // vrif. mot de passe message.setText("code OK"); else message.setText("entrez le code!"); } } }
Dfinition Cre un champ. Cre un champ de n caractres. Cre un champ initialis avec le texte l. Cre un champ de n caractres (approximativement), initialis avec le texte l. Teste si le caractre dcho est dfini. Retourne la longueur (int) du champ. Dfinit la longueur du champ de manire ce quil puisse contenir environ n caractres. Retourne le caractre dcho. Dfinit le caractre dcho.
194
import java.awt.*;
public class Composant extends java.applet.Applet { public void init() { add(new Label("Vos commentaires: ...")); add(new TextArea("Entrez vos commentaires ici ...",4,30)); } public void paint(Graphics g) { g.drawString("Merci de votre confiance", 100, 150); } }
En plus des mthodes hrites de TextComponent, TextArea possde les mthodes ci-dessous :
Mthode ou constructeur
TextArea() TextArea (int n, int j) TextArea (String t) TextArea (String t, int n, int j) append(String t) insert(String t,int n) replaceRange(String t, int d, int f)
Dfinition Cre un champ. Cre un champ de n caractres de j lignes. Cre un champ initialis avec t. Cre un champ initialis avec t, de n caractres et j lignes. Ajoute le texte t la fin du champ. Insre le texte t la position n. Remplace le texte des positions d f par le texte t.
195
Dfinition Retourne la longueur (int) du champ. Dfinit la longueur du champ. Retourne le nombre de lignes (int) du champ. Dfinit le nombre de lignes.
getRows() setRows(int k)
196
public void init() { points = new double[N][3]; // construction d'une spirale en 3D dans le cube [-80,80]^3 for (int i = 0; i<N; i++) { points[i][Y] = i*160.0/N - 80.0; double r = 80 - i*80.0/N; double a = i*2*Math.PI/8; points[i][X] = Math.cos(a)*r; points[i][Z] = Math.sin(a)*r; } setLayout(new BorderLayout()); sba = new Scrollbar(Scrollbar.VERTICAL, initial, visi, min,max); add(sba, BorderLayout.WEST); sba.addAdjustmentListener(this); sbb = new Scrollbar(Scrollbar.HORIZONTAL, initial, visi, min,max); add(sbb, BorderLayout.SOUTH); sbb.addAdjustmentListener(this); } public void paint(Graphics g) { double x,y,z; int xp = 0, yp = 0; // mmoire du point prcdent g.setColor(Color.blue); for (int i = 0; i<N; i++) { // rotation selon z x = points[i][X]*Math.cos(alpha)points[i][Y]*Math.sin(alpha); y = points[i][X]*Math.sin(alpha)+points[i][Y]*Math.cos(alpha); z = points[i][Z]; // rotation selon y x = x*Math.cos(beta)-z*Math.sin(beta); z = x*Math.sin(beta)+z*Math.cos(beta); // projection sur (X,Y) (laxe Z est celui qui sort de lcran) if (i>0) g.drawLine(xp, yp, (int)x+150,(int)y+150); xp = (int)x+150; yp = (int)y+150; } } public void adjustmentValueChanged(AdjustmentEvent e) { if (e.getSource() == sba) alpha = e.getValue()*2*Math.PI/100; if (e.getSource() == sbb) beta = e.getValue()*2*Math.PI/100; repaint(); } }
Les fonds
197
Chapitre 15
La classe Panel (panneau) reprsente des conteneurs destins tre placs dans un espace existant (un autre conteneur ou un butineur dans le cas des applets). La classe Applet tend la classe Panel (voir figure 15.2). La classe Window cre des espaces indpendants (nouvelles fentres). Les deux classes directement utilisables sont Dialog, qui permet la gestion des dialogues (avec un comportement modal) et Frame qui cre une surface de travail dans une fentre afin de recevoir des composants graphiques simples. noter que
200
Frame implante linterface MenuContainer, ce qui signifie quil est possible de spcifier les interactions avec des menus propres chaque fentre. La classe FileDialog est une spcialisation de Dialog pour la gestion des interactions par rapport un rpertoire de fichiers (voir point 19.14, p. 260). Nous allons maintenant voir quelques utilisations possibles de ces conteneurs travers des exemples.
Ensuite, chaque fois que lon dessine un segment, on ajoute sa coordonne dans le champ :
import java.applet.*; import java.awt.*; import java.awt.event.*; public class Dessin extends Applet { int x0 = 0, y0 = 0; TextArea t; class MSouris extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { Graphics g = getGraphics(); g.drawLine(x0, y0, e.getX(), e.getY()); t.append("\n("+x0+","+y0+")>("+e.getX()+","+e.getY()+")"); x0 = e.getX(); y0 = e.getY(); } } class CSouris extends MouseAdapter { public void mousePressed(MouseEvent e) { x0 = e.getX(); y0 = e.getY(); } } public void init() { t = new TextArea("(x, y)", 5, 20); this.add(t); addMouseListener(new CSouris()); addMouseMotionListener(new MSouris()); } }
201
Nous constatons que les coordonnes sinscrivent bien dans le champ de texte. Malheureusement, celui-ci occupe une partie importante de notre espace de travail (par ailleurs limit), nous privant ainsi dune large zone de dessin. Que faire dans ce cas? Cest ce que nous allons voir.
202
show(); } public void afficher(String s) { t.append(s); }
} public class Interaction extends Applet { int x0 = 0, y0 = 0; Fenetre f1; class MSouris extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { Graphics g = getGraphics(); g.drawLine(x0, y0, e.getX(), e.getY()); f1.afficher("\n("+x0+","+y0+")>("+e.getX()+","+e.getY()+")"); x0 = e.getX(); y0 = e.getY(); } } class CSouris extends MouseAdapter { public void mousePressed(MouseEvent e) { x0 = e.getX(); y0 = e.getY(); } } public void init() { f1 = new Fenetre("f1"); addMouseListener(new CSouris()); addMouseMotionListener(new MSouris()); } public void stop() { f1.dispose(); } }
203
Dans lexemple ci-dessous, nous montrons comment crer une application qui dmarre une ou plusieurs applet(s). Dans notre cas, chaque applet est un panneau qui demande un cadre afin de pouvoir safficher; nous proposons dutiliser un Frame cet effet.
Object
Component Abstraite
Container Abstraite
Panel
Java.lang
Java.awt
Applet
Java.applet
Nous dclarons une nouvelle classe Fenetre tendant la classe Frame. Nous dclarons ensuite une variable appletCourante permettant de rfrencer lapplet excuter. La classe interne WAction sert dfinir un objet qui coute lvnement de fermeture de la fentre (mthode windowClosing()). Au moment de la fermeture, lapplet sera stoppe et supprime (destroy()) puis la fentre sera supprime (dispose()). Aprs avoir initialis la fentre et son couteur, le constructeur de fentre ajoute lapplet au centre, linitialise (init()) puis rend la fentre visible (show()), et finalement dmarre lapplet (start()). Notons encore que la taille de la fentre est fixe avec setSize() et non calcule par pack() comme dans lexemple prcdent.
import java.applet.*; import java.awt.*; import java.awt.event.*; class Fenetre extends Frame {
private Applet appletCourante; class WAction extends WindowAdapter { public void windowClosing(WindowEvent e) { appletCourante.stop(); appletCourante.destroy(); ((Window)e.getSource()).dispose(); } } Fenetre(Applet a,String titre, int l, int h) { super(titre);
204
Nous rutilisons lapplet 41 afin dillustrer linvocation depuis une application. noter que lapplet ne doit pas utiliser de paramtres (getParameter()).
class Dessin extends java.applet.Applet { ... // comme dans lexemple ''mon applet est trop petite'' ... }
Le programme se rsume lassociation de lapplet sa fentre dexcution. Nous en profitons (applet 43) pour lancer deux excutions simultanes de la mme applet :
import java.awt.*; import java.applet.*; public class Interaction{ public static void main(String args[]){ Fenetre f1=new Fenetre(new Dessin(),"f1",100,200); Fenetre f2=new Fenetre(new Dessin(),"f2",200,250); } }
205
MenuItem : gre les entits de chaque menu de la barre; CheckboxMenuItem : gre les entits cochables des menus.
MenuBar MenuComponent Abstraite MenuItem CheckBoxMenuItem
Object
Menu
Reprenons lexemple de lapplet de dessin munie dune fentre daffichage des coordonnes (applet 42) et voyons comment ajouter des menus cette fentre (applet 44). Nous crons une nouvelle barre de menus laquelle nous rattachons des menus Fichier, Edition, Aide (ajouts au fur et mesure avec add()). Ensuite, nous associons chaque menu ses articles (galement avec add(), sans oublier dassocier un couteur dactions ceux que nous voulons rendre actifs(addActionListener()). Nous insrons galement des sparateurs entre les groupes darticles (addSeparator()). Finalement, nous demandons de rendre la barre de menus active (setMenuBar()).
Fenetre(String titre, int l, int h) { super(titre); setSize(l, h); t = new TextArea("(x, y)", 5, 20); add(t, BorderLayout.CENTER); MenuBar barreDeMenu = new MenuBar(); Menu m1 = new Menu("Fichier"); barreDeMenu.add(m1); Menu m2 = new Menu("Edition"); barreDeMenu.add(m2); Menu m3 = new Menu("Aide"); barreDeMenu.add(m3); barreDeMenu.setHelpMenu(m3); m1.add(new MenuItem ("Nouveau")); m1.add(new MenuItem("Ouvrir...")); m1.addSeparator(); m1.add(new MenuItem ("Enregistrer")); m1.add(new MenuItem ("Enregistrer sous...")); m1.add(new MenuItem ("Enregistrement automatique")); m1.addSeparator(); m1.add(m1Quitter = new MenuItem ("Quitter")); m1Quitter.addActionListener(this); m2.add(m2Effacer= new MenuItem ("Effacer"));
206
La gestion de lvnement gnr par la slection dun article de menu est similaire celle dun bouton. La mthode actionPerformed() de lcouteur est appele chaque slection. Cette dernire agit en fonction de la commande transmise (par dfaut, cest le nom de larticle slectionn).
public void actionPerformed(ActionEvent e) { if (e.getActionCommand().equals("Quitter")) this.dispose(); if (e.getActionCommand().equals("Effacer")) t.setText(""); if (e.getActionCommand().equals("Separer")) afficher("\n-------\n"); } }
Un gestionnaire dalertes
Alerte (Fenetre f, String alerteTexte) { super(f, "Alerte", true); messages = f; add(new Label(alerteTexte), BorderLayout.CENTER); add(boutonOK, BorderLayout.SOUTH); boutonOK.addActionListener(this); pack(); show(); } public void actionPerformed(ActionEvent e) { messages.afficher("--OK--\n"); dispose(); } }
207
chaque fois que lon dsire solliciter lattention de lutilisateur. Lapplet ci-dessous dessine en suivant les mouvements de la souris, mais interdit tout dessin dans la zone 50 < x < 100 et 50 < y < 100. La variable boolenne bloque signale quon a pntr dans la zone interdite. Elle est ncessaire car on peut encore recevoir des vnements souris alors que lalerte est dj affiche et il faut viter douvrir plusieurs alertes superposes.
public class Interaction extends Applet { int x0 = 0, y0 = 0; Fenetre f1; Alerte al; boolean bloque = false; class MSouris extends MouseMotionAdapter { public void mouseDragged(MouseEvent e) { Graphics g = getGraphics(); int x = e.getX(), y = e.getY(); if (!bloque) if (50 < x && x < 100 & 50 < y && y < 100) { bloque = true; f1.afficher("Point interdit: "+x+" "+y+"\n"); Alerte a = new Alerte (f1,"Zone interdite !"); } else { g.drawLine(x0, y0, x, y); x0 = x; y0 = y; } } } class CSouris extends MouseAdapter { public void mousePressed(MouseEvent e) { x0 = e.getX(); y0 = e.getY(); bloque = false;
208
Chapitre 16
BorderLayout
GridBagLayout
GridBagConstraints
Il existe plusieurs protocoles de mise en pages : la mise en pages glissante : classe FlowLayout;
210
la mise en pages par spcification des bords : classe BorderLayout; la mise en pages avec une grille : classe GridLayout; la mise en pages sous forme de cartes : classe CardLayout; la mise en pages avec une quadrillage et des contraintes : classe GridBagLayout et GridBagConstraints. Chaque conteneur est associ un seul protocole de mise en pages. Tous ses composants seront soumis ce protocole. Par contre, il est possible que parmi les composants, il se trouve des conteneurs qui eux sont soumis dautres protocoles de mise en pages. Lutilisation de protocoles de mise en pages permet de rester indpendant de la plate-forme physique. On spcifie les contraintes de la mise en pages plutt que des pixels sur la surface de travail. Tous les protocoles de mise en pages implantent linterface LayoutManager, dont le tableau 16.1 mentionne les principales mthodes.
Mthode
addLayoutComponent(String n, Component c) layoutContainer(Container c) minimumLayoutSize(Container p)
Description Ajoute le composant c et lassocie au nom n. Excute la mise en pages pour le conteneur c. Calcule la taille minimum (Dimension) pour le panneau p pour le parent le contenant. Calcule la dimension prfre (Dimension) pour le panneau p pour le parent le contenant. Supprime le composant c.
preferredLayoutSize(Container)
removeLayoutComponent(Component c)
211
Lutilisation de protocoles de mise en pages permet dadapter celle-ci dynamiquement lors du changement de la taille du conteneur. Les applets 46 et 47 illustrent bien ce phnomne.
Les mthodes des classes grant les protocoles de mise en pages ne doivent pas tre invoques directement. Elles sont appeles travers les conteneurs qui demandent respecter le protocole. Nous allons nous contenter de dcrire les constructeurs, renvoyant le lecteur la description de lAPI pour plus de dtails.
212
Constructeur
FlowLayout(); FlowLayout (int alignement); FlowLayout (int alignement, int xBord, int yBord);
} On peut ainsi observer (applet 48) quen modifiant la dimension du conteneur, la dimension des objets peut varier, mais que leur position relative reste par contre inchange.
Constructeur
BorderLayout(); BorderLayout(int xBord, yBord);
Description Cre un protocole. Cre un protocole en spcifiant lespace entre les composants en x et en y.
213
panneauAlEst.setLayout (new BorderLayout(10,10)); panneauAlEst.add("North",new Button ("b100")); panneauAlEst.add("Center",new Button ("b200")); panneauAlEst.add("South",new Button ("b300")); panneauAlOuest.setLayout (new BorderLayout(10,10)); panneauAlOuest.add("North",new Button ("b1000")); panneauAlOuest.add("Center",new Button ("b2000")); panneauAlOuest.add("South",new Button ("b3000")); panneauAuCentre.setLayout (new BorderLayout(10,10)); panneauAuCentre.add("North",new Label ("ici le centre")); panneauAuCentre.add("Center",new TextArea ("entrez vos ...",4,30)); } }
215
Panel panneau1 = new Panel(); add(panneau1); Panel panneau2 = new Panel(); add(panneau2); Panel panneau3 = new Panel(); add(panneau3); Panel panneau4 = new Panel(); add(panneau4); Panel panneauAuCentre = new Panel(); add(panneauAuCentre); panneau1.add(new Button ("b1")); panneau1.add(new Button ("b2")); panneau1.add(new Button ("b3")); panneau2.add(new Button ("b10")); panneau2.add(new Button ("b20")); panneau2.add(new Button ("b30")); panneau3.setLayout (new BorderLayout(10,10)); panneau3.add("North",new Button ("b100")); panneau3.add("Center",new Button ("b200")); panneau3.add("South",new Button ("b300")); panneau4.setLayout (new BorderLayout(10,10)); panneau4.add("North",new Button ("b1000")); panneau4.add("Center",new Button ("b2000")); panneau4.add("South",new Button ("b3000")); panneau5.setLayout (new BorderLayout(10,10)); panneau5.add("North",new Label ("ici le centre")); panneau5.add("Center",new TextArea ("entrez vos ...",4,30)); } }
216
Constructeur
GridLayout (int n, int m); GridLayout (int n, int m , int xBord, yBord);
Description Cre un protocole. Cre un protocole en spcifiant lespace entre les composants en x et en y.
217
Dfinition Position en x sur la grille du composant. La constante RELATIVE indique un dplacement relatif par rapport au dernier composant. Idem mais pour la position en y. Indique combien de cellules en x sont utilises sur la grille pour ce composant. La constante REMAINDER indique que ce composant est le dernier et quil doit occuper lensemble des cellules restantes. Idem mais pour la taille en y. Permet de pondrer lespace disponible entre les diffrents composants dans la dimension x. la valeur 0 indique que le composant ne doit pas participer cette distribution. Cette variable permet de dfinir plus finement le comportement lors du redimensionnement dun conteneur. Idem mais pour la pondration en y. Permet dindiquer quel coin ou bord de la cellule le composant est attach sil est plus petit que la cellule. Les constantes suivantes sont valides : CENTER, EAST, NORTH, NORTHEAST, NORTHWEST, SOUTH, SOUTHEAST, SOUTHWEST, WEST. Permet dindiquer comment remplir la cellule si elle est plus grande que le composant. Les constantes suivantes sont valides : NONE, BOTH, HORIZONTAL, VERTICAL. Spcifie les marges autour dun composant (haut, bas, gauche, droite). Permet de dfinir la taille interne ajouter en x pour chaque composant. Idem en y.
Pour faciliter la spcification des contraintes, il est recommand de construire une mthode reprsentant une catgorie de contraintes. En effet, le nombre des paramtres peut rapidement rendre la spcification de la contrainte incomprhensible. Dans lexemple suivant, nous avons dfini une mthode xyPosition() qui dclare la contrainte, lassocie au composant graphique et finalement ajoute le composant dans le conteneur. Cette mthode nutilise que les coordonnes
218
du composant placer sur la grille, les autres lments de la contrainte tant dfinis par dfaut dans la mthode. Lapplet 51 ci-dessous place les boutons sur la diagonale de la grille.
import java.awt.*; public class Composant extends java.applet.Applet { GridBagLayout g=new GridBagLayout(); public void init() { this.setLayout(g); // le Panel de l'applet xyPosition(this,new xyPosition(this,new xyPosition(this,new xyPosition(this,new } public void xyPosition(Container conteneur, Component element, int x, int y) { GridBagConstraints c= new GridBagConstraints(); c.gridx=x; c.gridy=x; c.gridwidth=1; c.gridheight=1; c.fill=GridBagConstraints.BOTH; c.weightx=1;c.weighty=1; c.anchor=GridBagConstraints.CENTER; c.insets=new Insets(3,3,3,3); ((GridBagLayout)conteneur.getLayout()).setConstraints (element, c); conteneur.add(element); } } Button Button Button Button ("b0"),0,0); ("b1"),1,1); ("b2"),2,2); ("b3"),3,3);
Invitation explorer
219
Lutilisation efficace de ce protocole demande donc la cration dun ensemble de mthodes de placement. Sa souplesse en fait pour le programmeur une sorte de gnrateur de protocoles de mise en pages. Nous pensons quil ne faut pas trop investir dans une connaissance approfondie de ces protocoles car des gnrateurs graphiques et interactifs dinterfaces devraient rapidement voir le jour. Ces gnrateurs vous permettront de placer des lments sur la surface de travail et gnreront ensuite le code Java ncessaire.
Chapitre 17
PixelGrabber
222
Mthode
getImage(URL url) getImage(URL url, String n) getCodeBase()
Limage doit correspondre au type dextension signal dans lURL. Les mthodes suivantes de la classe Graphics permettent de dessiner une image : drawImage(Image img, int x, int y,ImageObserver o); drawImage(Image img, int x, int y, Color f, ImageObserver o); drawImage(Image img, int x, int y, int l, int h, ImageObserver o); drawImage(Image img,int x,int y,int l,int h,Color f,ImageObserver o). Ces mthodes retournent toujours un boolen, en particulier false si limage nest pas compltement charge au moment de la demande daffichage. Dans ce cas, le gestionnaire de limage (ImageObserver) mettra des messages de mise jour provoquant des affichages rptitifs de limage incomplte. Ceux-ci risquent alors de pnaliser le chargement, augmentant le temps ncessaire laffichage complet. Les diffrents paramtres des mthodes daffichage ont le sens suivant : img : image afficher; x : coordonne horizontale de limage (coin suprieur gauche); y : coordonne verticale de limage (coin suprieur gauche); l : largeur de limage en pixels; h : hauteur de limage en pixels; f : couleur du fond; o : gestionnaire de limage (celui de lapplet). Pour les mthodes drawImage() nincluant pas les paramtres l et h, limage saffiche en taille relle. En modifiant les paramtres l et h, il est possible de crer des effets de zoom ou de rduction. Lapplet 52 charge trois images se trouvant dans un rpertoire (Desimages) situ dans le mme dossier que lapplet. On remarquera lutilisation de la mthode getCodeBase() qui permet de rendre relatif le positionnement des fichiers contenant les images. Initialement, les images ont toutes la mme taille (320x240 pixels), lutilisation des paramtres l et h ayant pour effet de rduire leur taille.
import java.awt.Graphics;
223
224
ces possibilits. Cette applet charge une image, lance une activit danimation qui attend la fin du chargement de limage, puis affiche la mme image mais rduite 25% et effectue ensuite un travelling sur une zone de limage, de la gauche vers la droite. Le gestionnaire de mdias est utilis de la manire suivante : cration de lobjet; ajout dobjets (images) surveiller avec un identifiant; test ou mise en attente jusqu ce que lobjet soit charg. Tout cela est ralis par le programme suivant :
MediaTracker traceur; ... public void init(){ traceur = new MediaTracker(this); this.showStatus("Chargement de l'image"); img1=getImage(getCodeBase(),"DesImages/imgsmall.gif"); // img1 est identifi par le numro 0 traceur.addImage(img1,0); ... public void run() { // le processus attend le chargement de id 0) try {traceur.waitForID(0); } catch(InterruptedException e){} // test du chargement this.showStatus("Chargement de l'image OK"); if (traceur.isErrorID(0)) { this.showStatus("erreur durant le chargement"); }
Le principe du traitement dune image (voir figure 17.2) est assez lgant : on cre un filtre (ImageFilter) qui est la fois un consommateur et un producteur dimages (deux sous-classes dImageFilter implantent un traitement de limage : CropImageFilter et RGBImageFilter); on cre un producteur dimages (FilteredImageSource, qui implante linterface ImageProducer) qui on fournit limage source (obtenue laide de la mthode getSource()) et le filtre; on demande au producteur dimages de crer limage (createImage()). Chacun de ces lments se comporte comme un consommateur-producteur , ce qui permet de les relier ( la manire des pipes) afin de produire de vritables chanes de traitement dimages. Ces diffrentes tapes se traduisent de la manire suivante :
Image img1, crop; ... ImageFilter filtre= new CropImageFilter(i,50,120,120); ImageProducer producteur=new
225
Programme complet :
import import import import java.awt.Graphics; java.awt.Image; java.awt.MediaTracker; java.awt.image.*;
public class UneImage extends java.applet.Applet implements Runnable { boolean stop=false; Image img1, crop; MediaTracker traceur; Thread actif; public void init(){ traceur = new MediaTracker(this); this.showStatus("Chargement de l'image");
226
public void paint(Graphics g) { g.drawImage(img1,0,0,img1.getWidth(this)/ 4,img1.getHeight(this)/4,this); g.drawRect(0,0,img1.getWidth(this)/4,img1.getHeight(this)/4); g.drawRect(0,0,img1.getWidth(this)/4,img1.getHeight(this)/4); } public void update(Graphics g) { g.drawImage(crop,20+img1.getWidth(this)/4, 20+img1.getHeight(this)/4,120,120,this); paint(g); } }
227
La mthode update() intelligente se chargera alors de minimiser leffacement. Pour ne redessiner quune partie de lapplet, on peut utiliser la mthode clipRect() qui slectionne une zone rectangulaire, puis invoquer paint() qui ne redessinera alors que cette zone. Les coordonnes de la zone redessiner sont mises jour par le processus de lanimation. Exemple :
public void update(Graphics g) { g.clipRect(x1,y1,x2,y2) paint(g); }
Pour diminuer le dlai de latence, on peut galement utiliser une mthode dite double tampon . Elle consiste prparer la nouvelle image dans un tampon (zone en mmoire) sans lafficher, puis afficher limage lorsquelle est prte. Pour raliser ce principe en Java, on procdera de la manire suivante. On dclare une image et une surface de dessin (Graphics) :
Image imgTampon; Graphics gTampon;
228
On prpare ensuite une image laide des mthodes de Graphics appliques au tampon (gTampon). Lorsque limage est prte, on invoque repaint(). Dans la mthode paint(), on dessine limage prpare :
g.drawImage(imgTampon,0,0,this);
Pour des cas plus complexes, on imagine bien quil est ncessaire de combiner lensemble de ces principes. Lapplet 54 utilise le double tampon pour dessiner un disque qui sinsre dans un carr.
import java.awt.Graphics; import java.awt.Image; import java.awt.image.*; public class UneImage extends java.applet.Applet implements Runnable { boolean stop=false; Image imgTampon; Graphics gTampon; Thread actif; public void init(){ imgTampon=createImage(getSize().width,getSize().height); gTampon=imgTampon.getGraphics(); } public void start() { if (actif==null); { actif = new Thread(this); actif.start(); } } public void stop() { if (actif!=null); { stop=true; actif = null; } } public void run() { gTampon.clearRect(0,0,getSize().width,getSize().height); while (!stop) { for (int i=1; i<100;++i){ gTampon.clearRect(100,100,i,i); gTampon.fillOval(100,100,i,i); repaint(); try {Thread.sleep(100);} catch(InterruptedException signal) {} }
Ajouter le son
} } public void paint(Graphics g) { g.drawImage(imgTampon,0,0,this); } }
229
play(getCodeBase(),"audio/dingdong.au");
Description Joue le son. Si le son nest pas termin et quon le rejoue, la squence sonore redmarre au dbut. Joue le son et le rpte indfiniment. Arrte de jouer le son. Doit imprativement tre invoque si lapplet se termine, car le son ne dpend pas directement du processus de lapplet.
Si le son doit tre jou plusieurs fois, il est intressant de le stocker dans une variable de type AudioClip. Le son est alors charg en utilisant la mthode getAu-
230
dioClip() de linterface AudioClip. Cette interface dfinit les mthodes de gestion des sons (voir tableau 17.3). Dans le code ci-dessous, nous avons repris lapplet prcdente et nous lui avons ajout les instructions ncessaires pour jouer le son dingdong chaque fois que lanimation recommence son cycle (vos voisins apprcieront!).
public class UneImage extends Applet implements Runnable { ... AudioClip dingdong; public void init(){ ... dingdong=getAudioClip(getCodeBase(),"audio/dingdong.au"); } ... public void stop() { ... dingdong.stop(); } public void run() { while (!stop) { if (dingdong!=null) dingdong.play(); for (int i=1; i<100;i+=3){ ... } ... }
Mthode
play(URL url) play(URL url, String n) getAudioClip(URL url) getAudioClip(URL url, String n)
Description Joue un son se trouvant ladresse indique par url. Joue un son se trouvant ladresse indique par la concatnation de url (nom de dossier) et n (nom de fichier). Charge un son se trouvant ladresse indique par url. Charge un son se trouvant ladresse indique par la concatnation de url et n.
Chapitre 18
232
tions sous forme de table deux dimensions (lignes/colonnes). Un tel composant nexiste en gnral pas tel quel sur les plates-formes habituelles.
(autres surfaces) menuBar contentPane Figure 18.1 Organisation des surfaces daffichage dun conteneur de base
La prsence de ces diffrentes surfaces ne permet plus lajout simple et direct de composants un conteneur de base. Par exemple, pour ajouter une tiquette
233
Les JComponents
Tous les composants Swing sont des descendants de JComponent. Il faut remarquer que JComponent est une sous-classe de Container, ce qui signifie que tout composant Swing peut contenir dautres composants, contrairement aux composants AWT. La classe JComponent est pour le moins complexe puisquelle possde 105 mthodes propres, en hrite 39 de java.awt.Container et 106 de java.awt.Component! Pour y voir un peu plus clair, on peut regrouper ces mthodes selon quelques grandes fonctions. Look-and-feel : associer au composant un objet responsable de son apparence et de son comportement; Dessin : dessiner et redessiner le composant, sa bordure et ses souscomposants; Focus : dterminer quand le composant devient actif ou inactif par rapport aux entres du clavier; Taille et position : dfinir et contrler la taille et le positionnement du composant (taille minimum, maximum, prfre, etc.); Clavier : dterminer les ractions aux frappes clavier, les raccourcis clavier, etc.; Aide immdiate : fixer le texte daide afficher quand la souris passe sur le composant; Accessibilit : dterminer la manire dont le composant doit apparatre des personnes souffrant de handicaps (affichage de trs grosse taille, remplacement de limage par le son, le braille, etc.).
234
AWT Canvas Checkbox JToggleButton JCheckBox JRadioButton ButtonGroup JCheckboxMenuItem JPopupMenu JComboBox JComponent Swing
Component
Dialog FileDialog
JDialog JFileChooser
Frame
JFrame
235
Scrollbar ScrollPane
JScrollBar JScrollPane
TextArea
JTextArea
Swing propose galement de nouveaux composants. Ils sont dcrits dans le tableau suivant.
Classe Box JColorChooser JDesktopPane JEditorPane JInternalFrame Description Un conteneur qui utilise la mise en pages Box. Un panneau pour slectionner une couleur. Un conteneur pour crer des bureaux (desktop) virtuels contenant plusieurs fentres (InternalFrames). Composant texte qui permet dditer diffrents types de contenus : texte simple, HTML, RTF, etc. Comme un JFrame mais lger et fait pour vivre lintrieur dun DesktopPane.
236
Classe JLayeredPane JOptionPane JProgressBar JRootPane Description Panneaux superposs.
Panneau dinformation ou derreur avec boutons (OK, Cancel, etc.). Un composant montrant lvolution dun processus sous forme dune barre qui grandit. Le composant de dpart dans une hirarchie de composants. Contient dautres panneaux : contenu, transparent, barre de menu, panneaux superposs. Un rgle gradue avec un curseur pour choisir une valeur. Juxtaposition de deux composants gauche/droite ou haut/ bas, avec possibilit de dplacer la limite. Panneaux superposs avec des onglets slectionner au choix. Prsentation dinformation sous forme de table deux dimensions (lignes/colonnes). Prsentation de texte contenant des indications de style. Barre doutils. Contient un texte daide associ un composant qui apparat et disparat en fonction des mouvements de la souris. Prsentation dinformations arborescentes sous forme de listes imbriques (exemple : une arborescence de rpertoires). La partie visible dun composant se trouvant dans un JScrollPane.
On notera que tous ces composants correspondent ceux que lon a lhabitude de trouver dans les interfaces de type X-Windows, Windows et MacOS. Swing ne propose ce jour aucun composant sortant de lordinaire.
Le look-and-feel modifiable
237
puisquil comprend la liste de caractres formant le texte afficher, plus dventuelles indications de formatage). La vue est la manire dont ltat de lobjet (dfini par le modle) est reprsent sur lcran (ou sur un autre dispositif). Par exemple, un bouton peut tre reprsent comme un rectangle avec un texte lintrieur, lorsque le bouton est enfonc, on dessine une ombre sous le rectangle. Le contrleur dfinit la raction de lobjet aux actions de lutilisateur. Que se passe-t-il si on clique sur le bouton, si on double-clique, si on tape sur une touche du clavier, etc.? Dans Swing, larchitecture MVC est utilise pour rendre le systme dinterface trs ouvert et reconfigurable dynamiquement. Chaque objet dinterface Swing est associ deux objets : un objet modle, qui stocke ltat du composant et un objet dinterface utilisateur (appel dlgu), qui gre la fois la vue (look) et le contrle (feel) du composant. Dans le cas dun simple bouton, lobjet modle reprsente simplement ltat (enfonc/non enfonc et le nom du bouton); lobjet dinterface dessine le bouton en fonction de son tat et interprte les clics souris sur le dessin du bouton pour modifier ltat (le modle) en consquence.
look-and-feel B look-and-feel A
Objets dinterface
Composants
Objets modles
La dfinition dun nouveau look-and-feel complet est une tche denvergure puisquil faut redfinir toutes les classes dinterface utilisateur de tous les types de composants (ButtonUI, ColorChooserUI, , TreeUI, ViewPortUI). Heureusement, il existe dj un certain nombre de look-and-feel prts lemploi : Metal, Windows, Motif, MacOS. Pour utiliser un look-and-feel particulier, ici Metal, il faut crire les instructions suivantes :
UIManager.setLookAndFeel( "javax.swing.plaf.metal.MetalLookAndFeel"); SwingUtilities.updateComponentTreeUI(topComponent);
Lexemple qui suit montre : la cration dune interface avec des composants Swing (curseur, panneau, libells, boutons); la cration et lajout de bords certains composants; lutilisation dun nouveau gestionnaire de mise en pages : BoxLayout; lobtention de la liste des look-and-feel disponibles; le changement dynamique de look-and-feel (chaque fois quon clique sur le bouton).
import java.awt.*; import java.awt.event.*; import javax.swing.event.*; import javax.swing.border.*; import javax.swing.*; class SliderF extends JFrame implements ChangeListener, ActionListener { JLabel l1; JSlider s; JPanel p, pi; DisquePanel dp; JButton changeLAF; int diametre = 50; Color clr = Color.red; UIManager.LookAndFeelInfo laf[]; int lafNo = 0; // un panneau avec un disque de taille variable au centre class DisquePanel extends JPanel { DisquePanel() { setPreferredSize(new Dimension(130,130)); } public void paint(Graphics g) { g.setColor(clr); g.fillOval(65-diametre/2,65-diametre/2,diametre, diametre);
Le look-and-feel modifiable
} } public void init() { // liste des LAF disponibles laf = UIManager.getInstalledLookAndFeels(); // on cre linterface dans le contentPane getContentPane().add(p = new JPanel()); BoxLayout bxl = new BoxLayout(p, BoxLayout.Y_AXIS); p.setLayout(bxl); p.add(l1 = new JLabel("LAF: " + UIManager.getLookAndFeel().getName() + " (initial)")); l1.setBorder(BorderFactory .createMatteBorder(5, 8, 5, 8, Color.orange)); // un curseur avec divisions et subdivisions p.add(s = new JSlider(0,120,40)); s.setMajorTickSpacing(30); s.setMinorTickSpacing(5); s.setPaintTicks(true); s.addChangeListener(this); p.add(pi = new JPanel()); pi.add(dp = new DisquePanel(), BorderLayout.CENTER); pi.setBorder(BorderFactory.createEtchedBorder()); p.add(changeLAF = new JButton("Change")); changeLAF.addActionListener(this); setSize(300,250); setVisible(true); } public void stateChanged(ChangeEvent e) { // lit la valeur du curseur if (e.getSource() == s) diametre = s.getValue(); repaint(); } public void actionPerformed(ActionEvent e) { // change de LAF - on prend le suivant dans la liste lafNo = (lafNo + 1) % laf.length; try { UIManager.setLookAndFeel(laf[lafNo].getClassName()); SwingUtilities.updateComponentTreeUI(this); } catch (Exception exc) { } l1.setText("LAF: " + UIManager.getLookAndFeel().getName()
239
240
+ "(" + lafNo + ")"); repaint(); } } // la classe de lapplication public class SF {
La figure 18.4 montre deux copies dcran effectues pendant lexcution de cette application sous MacOS. On remarquera que la fentre englobante (JFrame) est gre par la plate-forme dexcution (MacOS), alors qu lintrieur Swing gre aussi bien un look-and-feel Metal quun look-and-feel CDE/Motif.
Pour terminer, signalons quil vaut mieux viter de mlanger les composants AWT et Swing car il peut en rsulter des conflits daffichage. Il faut galement tre prudent dans la redfinition de la mthode paint() qui risque dempcher le dessin dventuels sous-composants.
Chapitre 19
242
tes les entres-sorties utilisent donc la notion de flux pour la circulation des informations.
Classes
Les classes permettant la lecture et lcriture de caractres dans des flux sont prsentes respectivement sur les figures 19.1 et 19.2. Elles hritent des classes abstraites Reader ou Writer dont elles utilisent le nom comme suffixe. La plupart de ces classes ont leur quivalent pour les octets (voir figures 19.3 et 19.4), elles hritent alors de la classe abstraite servant de suffixe leur nom, InputStream ou OutputStream.
BufferedReader LineNumberReader
PushBackReader
FileReader
PipedReader
StringReader
Les classes BufferedReader et BufferedWriter (BufferedInputStream et BufferedOutputStream pour les octets) lisent ou crivent sur un canal en plaant les caractres (ou les octets) dans un tampon (buffer), ce qui diminue le nombre daccs au flux. Ces oprations sont videmment beaucoup plus performantes que celles impliquant des flux sans tampon. Les classes LineNumberReader et LineNumberInputStream conservent le numro de ligne courant durant toute la lecture du flux. Les classes CharArrayReader, CharArrayWriter, ByteArrayReader et ByteArrayWriter lisent ou crivent des tableaux de donnes en mmoire principale. Les classes abstraites FilterReader, FilterWriter, FilterInputStream et FilterOutputStream effectuent des lectures et des critures filtrantes. Les classes filtrantes PushBackReader et PushBackInputStream sont des sous-classes de leur lecteur respectif, elles autorisent des retours en arrire sur des donnes dj lues, la longueur du retour en arrire est fixe la cration de linstance.
Description du package
243
BufferedWriter
CharArrayWriter
java.lang. Object
Writer Abstraite
FilterWriter Abstraite
OutputStreamWriter
FileWriter
PipedWriter
PrintWriter
StringWriter
Les classes InputStreamReader et OutputStreamWriter convertissent respectivement les octets en caractres et les caractres en octets, et ce, en fonction dun encodage spcifi la cration de linstance. Les classes FileReader, FileWriter, FileInputStream et FileOutputStream lisent ou crivent des fichiers de donnes en mmoire secondaire. On accde aux fichiers directement partir de leur nom. Les classes PipedReader, PipedWriter, PipedInputStream et PipedOutputStream lisent ou crivent des donnes dans des pipelines (pipes) qui permettent, par exemple, la communication entre processus. La classe StringReader lit les caractres dun String. La classe StringWriter crit dans un StringBuffer qui peut tre converti en String. La classe StringBufferInputStream, qui est dprcie en Java 2.0, convertit de manire incorrecte en octets des caractres lus partir dun String. Les classes PrintWriter et PrintStream sont des classes qui facilitent lcriture de diffrents types de donnes dans des flux de caractres. Elles sont par exemple trs utiles pour imprimer la valeur dun rel ou dun entier. Les classes DataInputStream et DataOutputStream lisent et crivent des types de donnes prdfinis dans Java, indpendamment du systme dexploitation. La classe SequenceInputStream concatne logiquement plusieurs fichiers dentre en un seul, la lecture senchanant dun fichier lautre de manire transparente.
ByteArrayInputStream BufferedInputStream FileInputStream DataInputStream java.lang. Object InputStream Abstraite FilterInputStream Abstraite LineNumberInputStream PipedInputStream PushBackInputStream SequenceInputStream
StringBufferInputStream
ByteArrayOutputStream
java.lang. Object
OutputStream Abstraite
DataOutputStream
PrintStream PipedOutputStream
Outre la persistance et les flux dentres-sorties, le package java.io contient quelques autres classes utiles illustres figure 19.5. La classe File permet de construire des noms de fichiers et de rpertoires. Elle permet ainsi de reprsenter les fichiers du systme dexploitation sous-jacent. La classe FileDescriptor permet dobtenir des poignes (handles) de bas niveau sur des fichiers ou des sockets ouverts. La classe RandomAccessFile est utilise pour la manipulation de fichiers accs direct. La classe StreamTokenizer sert faire de lanalyse lexicale en lisant le flux dentre, unit lexicale par unit lexicale.
Description du package
245
File
RandomAccessFile
StreamTokenizer
ObjectInputStream
ObjectInputStream.GetField
ObjectStreamField
OutputStream Abstraite
ObjectOutputStream
La srialisation consiste lire et crire un objet dans un flux. Lobjet est transform en une squence doctets, qui est lue ou crite en une seule fois. Les classes qui permettent la srialisation dobjets sont prsentes la figure 19.6 Les classes ObjectInputStream et ObjectOutputStream permettent la lecture et lcriture dobjets srialisables dans des flux (ventuellement des fichiers). Elles comportent respectivement une mthode de lecture et dcriture qui effectue lopration souhaite en une seule fois, les objets qui composent lobjet considr subissant ipso facto la mme opration de manire transparente. Un objet est srialisable si sa classe implante linterface Serializable. Les deux classes internes ObjectInputStream.GetField et ObjectOutputStream.PutField permettent laccs aux champs persistants dun objet. Les classes ObjectStream-
246
Class et ObjectStreamField donnent accs aux informations dcrivant la srialisabilit dune classe quelconque. Elles ne sont utiles que pour la gestion de problmes de version entre la dfinition de la classe et celle de lobjet persistant ou srialis.
Interfaces
Linterface Serializable ne contient ni champ ni mthode, il suffit de la mentionner dans la dclaration de la classe des objets srialiser. Une autre interface trs utile de ce package est FilenameFilter. Elle dfinit une seule mthode, accept(), permettant la slection des entres dun rpertoire. Cette interface est rfrence par une mthode list() de la classe File et par la classe FileDialog du package AWT.
Exceptions
Les exceptions les plus utilises sont les suivantes : la classe EOFException sert indiquer que la fin de fichier a t atteinte lors de la lecture. La plupart des classes, hormis DataInputStream, retournent une valeur spciale en fin de fichier; la classe FileNotFoundException indique quun fichier na pu tre trouv; la classe IOException signale quun problme dentre-sortie est survenu. Beaucoup de mthodes du package la gnre; la classe InterruptedIOException signale quune entre-sortie a t interrompue.
Entres-sorties clavier/cran
247
Les fichiers accs direct (classe RandomAccessFile) peuvent eux aussi tre crs directement avec un nom de fichier ou un File.
La classe InputStream est abstraite, ainsi la classe effective du canal in est une sous-classe de InputStream. Le programme suivant calcule et affiche cette classe, savoir java.io.BufferedInputStream.
import java.io.*; public class classSystemIn { static public void main(String[] args) {System.out.println(System.in.getClass().getName());}}
Ainsi, toute saisie au clavier est insre dans un tampon (buffer). La mthode available() renvoie le nombre doctets en attente dans le tampon. Selon votre systme dexploitation, ce nombre peut varier en fonction du caractre spcifiant la fin de la saisie, Control-D (Unix), Control-Z (MSDOS) ou retour chariot (Entre).
248
La classe Fichier
La classe abstraite Fichier est une sous-classe de File. Son intrt est de disposer dune mthode retournant le rpertoire dans lequel se trouve le fichier correspondant. Ce sont ses deux sous-classes (FichierLecture et FichierEcriture) qui testeront les droits daccs lors de la cration dinstances.
249
La classe Fichier
La classe FichierLecture
Elle tend la classe Fichier en nautorisant que la cration de rfrences des fichiers pour lesquels on dispose dun droit de lecture.
import java.io.*; public class FichierLecture extends Fichier{ public FichierLecture(String s) throws IOException, NullPointerException super(s); if (!this.exists() || !this.isFile()) throw new IOException( this.getName() + ": fichier inexistant."); if (!this.canRead()) throw new IOException( this.getName() + ": fichier non lisible."); } }
La classe FichierLecture
La classe FichierEcriture
Elle tend la classe Fichier en nautorisant que la rfrence des fichiers pour lesquels on dispose dun droit dcriture (sur le fichier ou sur le rpertoire de sa rfrence, selon lexistence ou non du fichier considr).
250
import java.io.*; public class FichierEcriture extends Fichier{ public FichierEcriture(String s) throws IOException { super(s); if (this.exists()){ if (this.isFile()){ if (!this.canWrite()) throw new IOException( this.getName() + ": n'est pas modifiable."); } else throw new IOException( this.getName() + ": n'est pas un fichier."); } else // le fichier n'existe pas { // il faut tester le droit en ecriture dans le repertoire File Dir=new File(this.repertoireDe()); if (!Dir.exists()) throw new IOException( Dir.getName() + ": n'est pas un repertoire"); if (!Dir.canWrite()) throw new IOException( Dir.getName() + ": n'est pas modifiable."); } } }
La classe FichierEcriture
La classe Repertoire
Cest une sous-classe abstraite de File permettant de rfrencer un rpertoire et dafficher des informations sur toutes les entres de celui-ci. Cette classe ne teste aucun droit daccs sur les rpertoires. Son rle est doffrir des mthodes daccs au contenu du rpertoire pour ses deux sous-classes : RepertoireLecture et RepertoireEcriture.
import java.io.*; public abstract class Repertoire extends File { private static final int lim=20; public Repertoire(String s) throws IOException{ super(s);} private void afficheUnFichier(String ref){ File unElement= new File(this,ref); System.out.print((unElement.canRead())? "L":" "); System.out.print((unElement.canWrite())? "E":" "); System.out.print(" "+ref); if (unElement.isDirectory()) System.out.println("\t"+"repertoire"); else if (unElement.canRead())
251
La classe Repertoire
La classe RepertoireLecture
Son instanciation nest autorise que pour les rpertoires existants pour lesquels on dispose du droit de lecture.
import java.io.*; public class RepertoireLecture extends Repertoire { public RepertoireLecture(String s) throws IOException { super(s); if (!this.exists() || !this.isDirectory()) throw new IOException( this.getName() + ": repertoire inexistant."); if (!this.canRead()) throw new IOException( this.getName() + ": repertoire non lisible."); } }
La classe RepertoireLecture
La classe RepertoireEcriture
Son instanciation nest autorise que pour les rpertoires existants pour lesquels on dispose du droit dcriture.
import java.io.*; public class RepertoireEcriture extends Repertoire{ public RepertoireEcriture(String s) throws IOException super(s); if (!this.exists() || !this.isDirectory()) throw new IOException( this.getName() + ": repertoire inexistant."); if (!this.canWrite()) throw new IOException( this.getName() + {
252
La classe RepertoireEcriture
Les exemples suivants illustrent les diffrentes classes de ce package et rutilisent les classes ci-dessus.
Application 2 : AfficheRpertoire
Filtrage
La dfinition dun filtre seffectue en implantant linterface FileNameFilter. Le
1. Comme la commande dir de MSDos ou ls de Unix.
253
filtrage de la liste proprement dit se fait grce la mthode list() de la classe File qui admet comme paramtre linterface FileNameFilter. Le filtre implant dans la classe ci-dessous permet la slection des entres du rpertoire (fichiers ou sous-rpertoires) se terminant par un mme suffixe.
import java.io.*; class FiltreSuffixe implements FilenameFilter{ private String suffixe; public FiltreSuffixe(String suffixe) {this.suffixe=suffixe;} public boolean accept(File dir, String nom) {return nom.endsWith(suffixe);} }
La classe FiltreSuffixe
254
public Afficheur(URLConnection urlc) throws IOException { super(urlc.getURL().toExternalForm()); DataInputStream canal=new DataInputStream(urlc.getInputStream()); this.RemplitFenetre(canal,(int) urlc.getContentLength()); } // Afficheur public void actionPerformed (ActionEvent e) { if (e.getSource()==Quitter) {this.setVisible(false); this.dispose(); System.exit(0);} } //actionPerformed }
La classe Afficheur
Laffichage du contenu dun URL (voir point 20.3) est rendu possible car une connexion labore partir dun URL ouvre un flux de lecture.
Utilisation
Le programme suivant, dont un exemple dexcution est prsent dans la figure 19.8, utilise la classe Afficheur. Le nom du fichier afficher est pass comme argument sur la ligne de commande. On tente de crer une instance de la classe FichierLecture qui servira de paramtre au constructeur de Afficheur.
import java.io.*; public class AfficheUnFichier { static public void main(String[] args){ if (args.length!=1) { System.out.println ("Usage: java AfficheUnFichier <nom de fichier>"); System.exit(0);} try { FichierLecture fichier= new FichierLecture(args[0]); Afficheur f= new Afficheur(fichier);} catch (IOException e) {System.out.println(e);} } //main }
Application 3 : AfficheUnFichier
255
256
s.close(); d.close(); } // try catch (IOException e) {System.err.println(e.getMessage());} } // copie public static void main(String args[]){ if (args.length!=2){ System.err.println("Usage: java CopieurFichier <src> <dest>"); return;} copie(args[0],args[1]); } }
Dfinition du filtre
La classe Ponctuation est une sous-classe de la classe PushbackReader qui permet de rinsrer des caractres dj lus dans le flux de ceux qui restent lire (mthode unread). Nous avons redfini les deux mthodes read de la classe PushbackReader dans la sous-classe afin de raliser le filtrage qui consiste ponctuer correctement un texte.
import java.io.*; public class Ponctuation extends PushbackReader { private int dernierLu=-1; public Ponctuation (Reader fichier) { super(fichier,1); } public int read() throws IOException { int c=super.read();//appel read de PushbackReader if ((",;:".indexOf(dernierLu)>=0) && (c!=' ')) { unread(c); c=' '; } if (c==' ') { int d=super.read(); if (d!=',') unread(d); else c=',';
257
} public int read(char[] cbuf , int off,int len) throws IOException { int c=0; for (int i=0;(i<len) && (c!=-1);i++) { c=read(); cbuf[off++]=(char) c; } if (c!=-1) return len; else return -1; } }
La classe Ponctuation
Utilisation du filtre
import java.io.*; public class Ponctue { public static void main(String args[]) { char[] buf= new char[20]; int c; if (args.length!=1) { System.err.println("java Ponctue <nom de fichier>"); return; } try { FichierLecture f=new FichierLecture(args[0]); Ponctuation fp=new Ponctuation (new FileReader(f)); do { c=fp.read(buf,0,20); if (c!=-1) System.out.print(buf); } while (c!=-1); fp.close();} catch (IOException e) {System.err.println(e.getMessage());} } //main } //class
258
Comment faire une classe implantant la gestion de fichiers accs direct dentiers?
La gestion des fichiers accs direct dentiers ne requiert (outre un constructeur au moins pour la cration dinstance) que les mthodes suivantes, lunit de positionnement tant alors lentier :
void close(); int read(); void write(int v); void seek(long pos); public long getFilePointer(); public long length();
Nous ne pouvons pas implanter la classe dsire par extension de la classe RandomAccessFile puisque nous ne pouvons pas interdire lhritage de certaines mthodes. Il nous faut alors composer ou, sans faire de jeu de mots, construire la classe dsire par composition.
La classe FichierEntierAccesDirect
Analyse lexicale
259
260
TT_NUMBER, etc.). Si lunit lexicale est de type nombre, sa valeur est stocke dans la variable dinstance nval, si cest un mot dans sval. La mthode nextToken() permet de lire les units lexicales les unes aprs les autres. Le programme suivant utilise la classe StreamTokenizer pour compter les mots et les nombres dun fichier.
import java.io.*; public class Compteur { public static void main(String args[]){ int nNombres=0; int nMots=0; Reader r=null; StreamTokenizer st=null; try { r = new BufferedReader(new FileReader(args[0])); st = new StreamTokenizer(r);} catch (IOException e) {System.out.println("usage : java Compteur <filename>"); try {r.close();} catch (IOException e1) {}; System.exit(1);} st.eolIsSignificant(true); st.wordChars((int) '_',(int)'_'); st.ordinaryChar((int) '.'); try {while (st.nextToken()!=st.TT_EOF) {if (st.ttype== st.TT_WORD) {System.out.println(st.sval); nMots++;} if (st.ttype== st.TT_NUMBER) {System.out.println(st.nval); nNombres++;} } } catch (IOException e) {System.out.println("error when reading.");} finally {try {r.close();} catch (IOException e1) {};} System.out.println("mots : "+ nMots); System.out.println("nombres : "+ nNombres); } //main }
261
fentre standard douverture et de fermeture de fichiers de linterface graphique du systme dexploitation utilis. Le constructeur de cette classe admet un paramtre indiquant le type de fentre souhait : pour louverture dun fichier, sa valeur est FileDialog.LOAD, pour la sauvegarde dun fichier, sa valeur est FileDialog.SAVE. Cette classe a des mthodes permettant de rcuprer et de spcifier le rpertoire et le fichier. Ces mthodes sont : getDirectory(); getFile(); setDirectory(String dir); setFile(). La mthode setFileNameFilter(FileNameFilter f) permet le filtrage des noms dentres affichs dans la fentre.
262
La classe Arbre
Le programme ci-dessous cre un arbre binaire de recherche partir dune phrase passe en paramtre sur la ligne de commande, puis appelle la mthode parcours qui imprime les nuds de larbre dans lordre alphabtique. Larbre est rendu persistant par lcriture de lobjet (mthode writeObject) dans un ObjectOutputStream.
import java.io.*; class DemoArbre { static public void main(String[] args) { Arbre a=new Arbre(null); if (args.length==0) { System.out.println("Usage : java DemoArbre <X1> .. <Xn>"); System.exit(0); } for (int i=0; (i<args.length); i++) { a.inserer(args[i]); } a.parcours(); // rendre l'arbre persistant try { FileOutputStream fos = new FileOutputStream("arbre.tmp"); ObjectOutputStream oos = new ObjectOutputStream(fos); oos.writeObject(a); oos.flush(); oos.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } } // main }
Invitation explorer
263
Le programme ci-dessous lit cet objet persistant (mthode readObject de la classe ObjectInputStream).
import java.io.*; class DemoArbreLecteur { static public void main(String[] args) { Arbre b=null; try { FileInputStream fis = new FileInputStream("arbre.tmp"); ObjectInputStream ois = new ObjectInputStream(fis); b = (Arbre) ois.readObject(); ois.close(); } catch (Exception e) { e.printStackTrace(); System.exit(1); } b.parcours(); } // main }
La srialisation de la racine a entrane bien celle de tous les autres nuds de larbre. La persistance des objets est donc ralise avec la lecture ou lcriture dun objet en une seule opration. Les difficults apparaissent seulement si des versions diffrentes des classes dobjets srialiss sont incompatibles. Il est prfrable de ne pas modifier la dfinition dune classe tant quil en existe des instances persistantes. Certaines modifications peuvent en effet poser des problmes dincompatibilit comme, par exemple, la destruction dun champ. La srialisation permet galement, avec une grande facilit, la circulation des objets aussi complexes soient-ils, entre des applications distribues.
Chapitre 20
266
les classes de haut niveau permettent de se connecter sur un URL, den tlcharger le contenu et de faire de la communication interprocessus sur le rseau Internet. Les classes de bas niveau Ces classes sont trs utiles si lon souhaite grer de nouveaux types MIME absents dans lenvironnement Java ou des protocoles. Les classes permettant de dfinir des types MIME sont (figure 20.1) : ContentHandler : cette classe abstraite dfinit ce quest un gestionnaire de type MIME. Un tel gestionnaire tlcharge un contenu partir dune connexion sur un URL et transforme ce contenu en une instance dune classe dobjets, classe prdfinie dans Java ou implante par vousmme. La mthode getContent() ralise cette transformation. Par exemple, Java incorpore un gestionnaire pour les images au format gif. Ce gestionnaire dimages est une sous-classe de la classe ContentHandler; URLStreamHandler : cette classe abstraite dfinit ce quest un protocole pour la connexion sur un URL. Par exemple, Java implante un protocole permettant la connexion sur des serveurs HTTP. Ce gestionnaire de protocole est une sous-classe de la classe URLStreamHandler.
ContentHandler Abstraite Object URLStreamHandler Abstraite
Les classes permettant lenvoi et la rception de paquets sur le rseau sont (figure 20.2) : DatagramPacket : cette classe reprsente un paquet envoyer ou recevoir travers le rseau. Un paquet envoyer est compos dun tableau doctets et dune adresse Internet (un objet de la classe InetAddress). Un paquet recevoir est compos dun tableau doctets; DatagramSocket : cette classe reprsente un metteur-rcepteur de paquets (mthodes send() et receive()) mais sans aucune garantie concernant lordre darrive des paquets ni leur arrive elle-mme. Il est
1. MIME est un acronyme de Multipurpose Internet Mail Extensions. LURL http://www.imc.org/rfcs.html#mime dcrit compltement cette spcification pour la mise en forme de messages Internet.
Description du package
267
prfrable dutiliser des objets des classes Socket et ServerSocket pour communiquer de manire plus sre sur le rseau; la classe MulticastSocket permet lenvoi et la rception de paquets un groupe de destinataires et plus un seul, comme la classe prcdente; SocketImpl : cette classe dfinit un ensemble de mthodes ncessaires limplantation de la communication travers des sockets.
DatagramPacket finale DatagramSocket MulticastSocket
Les classes de haut niveau La classe InetAddress reprsente des adresses Internet. Elle est utilise par lun des constructeurs de la classe Socket et par celui de la classe DatagramSocket pour lenvoi de paquets. La classe ServerSocket permet la construction de serveurs : un serveur attend des demandes de connexion manant de clients sur un port particulier. La mthode accept() renvoie un socket lorsquune demande est reue. La classe Socket permet la communication interprocessus travers le rseau. En spcifiant une machine (ou une adresse Internet) et un numro de port, un socket peut tre construit. Le protocole par dfaut est celui des flots (streams). Les mthodes getInputStream() et getOutputStream() permettent la rcupration des canaux de lecture et dcriture. La classe URL (Uniform Resource Locator) permet le tlchargement des ressources rfrences par un URL. Elle offre trois possibilits de tlchargement : directement par la mthode getContent(). Cette mthode renvoie un objet dont la classe correspond un type MIME pour lequel on dispose dun gestionnaire (un ContentHandler);
indirectement par une URLConnection obtenue par la mthode openConnection(), puis ensuite par la mthode getContent() qui est similaire la prcdente; par un canal de type InputStream obtenu par la mthode openStream(). Cette voie est la seule possibilit si lURL contient des informations qui ne sont pas dun type MIME pour lequel on dispose dun gestionnaire.
Authenticator Abstraite PasswordAuthentication finale URL finale
URLEncoder
Les classes Authenticator et PasswordAuthentication permettent laccs par des programmes Java des ressources dsignes par un URL et protges par mot de passe, condition videmment dtre un utilisateur autoris de ces ressources. La classe abstraite URLConnection a pour rle doffrir un meilleur contrle sur le tlchargement de ressources rfrences par un URL. Cette classe dispose de mthodes permettant de connatre le type, len-tte, la date de dernire modification dun contenu. Cette classe permet le tlchargement des donnes brutes de ce contenu. La classe abstraite HttpURLConnection tablit des connexions vers des URL en utilisant les spcificits du protocole HTTP; il est par exemple possible de savoir si la connexion passe au travers dun proxy ou non. La classe abstraite JarURLConnection tablit des connexions vers des archives Java ou des entres dune archive Java partir dun URL afin de les tlcharger. Les classes URLDecoder et URLEncoder offrent chacune une seule mthode de
Description du package
269
classe, dont le but est de coder/dcoder un URL en une chane de caractres plus portable et inversement. Les espaces et les caractres non alphanumriques sont cods diffremment.
Interfaces
Les interfaces de ce package fournissent les signatures des mthodes pour les classes de bas niveau. Ces interfaces sont : ContentHandlerFactory : cette interface ne dfinit que la signature dune seule mthode, ContentHandler createContentHandler(String mimetype). Cette mthode dfinit lassociation entre un type MIME et le gestionnaire correspondant; FileNameMap : cette interface sert dterminer, partir du nom dun fichier, le nom du type MIME qui va en permettre la lecture; URLStreamHandlerFactory : cette interface joue le mme rle pour les protocoles que linterface ContentHandlerFactory pour les gestionnaires de type MIME; SocketImplFactory : cette interface est utilise par les classes Socket et ServerSocket pour raliser les implantations effectives des sockets; SocketOptions : cette interface est utilise pour lire et crire des options lies une nouvelle implantation de sockets.
Exceptions
BindException : cette classe dexception indique un problme dtablissement de liaison entre un socket, une adresse et un port locaux; ConnectException et NoRouteToHostException : ces deux classes dexception indiquent un problme dtablissement de la connexion entre un socket, une adresse et un port distants; MalformedURLException : cette classe dexception permet de signaler la non-reconnaissance dun protocole connu dans la chane de caractres spcifiant un URL, ou lchec de lanalyse lexicale de cette chane; ProtocolException : cette classe dexception signale les erreurs dans un protocole, par exemple une erreur TCP; SocketException : cette classe dexception signale une mauvaise utilisation des sockets; UnknownHostException : cette classe dexception signale que ladresse IP dun hte na pu tre dtermine; UnknownServiceException : cette classe dexception signale la nonreconnaissance dun type MIME ou une tentative dcriture sur un URL avec accs en lecture seulement.
270
De nombreuses classes de ce package ont des mthodes signalant des exceptions de la classe IOException. Les exemples suivants utilisent les classes URL, URLConnection, Socket, ServerSocket, Authenticator et PasswordAuthentication.
271
La Classe Identification
La seconde tape consiste installer une instance de cette classe dans le programme daccs aux URL. La ligne de code ci-dessous peut se rajouter lapplication 10 dans la mthode main avant linstruction qui demande la connexion.
Authenticator.setDefault(new Identification());
Lorsque lapplication accde un URL protg, la mthode getPasswordAuthentication de la classe Identification est appele afin dobtenir un compte utilisateur et un mot de passe.
272
public class AfficheUnURL { static public void main(String[] args){ if (args.length!=1) { System.out.println("Usage : java AfficheUnURL <URL>"); System.exit(0);} try { URL url= new URL(args[0]); Afficheur f= new Afficheur(url.openConnection());} catch (IOException e) {System.out.println(e);} }
La classe ValiditeURLConnexion
Ce vrificateur dURL est trs simple puisquil suppose que : les balises autour dun URL sont spcifies ainsi : <A HREF="un url">texte affich</A>, les guillemets dlimitant la chane de caractres spcifiant lURL vrifier; les URL sont des rfrences absolues et non relatives un URL courant; Le principe de cette vrification est le suivant : 1. partir dune URLConnexion obtenue par la cration dun URL pass dans la ligne de commandes, on teste son type MIME. Sil sagit dun text/html, son contenu est vrifi. Ce contenu est lu, unit lexicale par unit lexicale. 2. Pour chaque ligne, on cherche le motif <A, puis on saute deux units lexicales correspondant HREF et =. LURL analyser est contenu
Vrificateur dURL
273
entre deux guillemets. On appelle ensuite la mthode test() de la classe ValiditeURLConnexion pour vrifier la validit de cet URL. Les rglages de lextracteur dunits lexicales (StreamTokenizer) sont importants puisquils assemblent en une seule unit lexicale, dune part, le symbole < avec les mots (voir la mthode wordChars) et, dautre part, tous les caractres compris entre deux guillemets en une chane de caractres (voir la mthode quoteChar).
import java.io.*; import java.net.*; public class VerifieURL { public static void verifie(URLConnection u) throws IOException { if (!u.getContentType().equals("text/html")) { System.out.println("seuls les text/html sont verifies."); System.exit(0);}; Reader r=new InputStreamReader(u.getInputStream()); StreamTokenizer st=new StreamTokenizer (r); st.wordChars('<','<'); st.quoteChar('"'); while (st.nextToken()!=st.TT_EOF) { if ((st.ttype== st.TT_WORD) && (st.sval.compareToIgnoreCase("<a")==0)) { st.nextToken(); // saute href st.nextToken(); // saute = st.nextToken(); // extrait l'URL System.out.println(st.sval); try {ValiditeURLConnexion.test(st.sval);} catch (IOException e) { System.out.println("URL incorrect :"+st.sval);} } // if } // while r.close(); } public static void main(String args[]) throws MalformedURLException, IOException { if (args.length!=1) {System.out.println("Usage : java verifieURL <URL>"); System.exit(0);} URLConnection c=null; try { URL url =new URL(args[0]); ValiditeURLConnexion.test(url); c= url.openConnection(); System.out.println(c.getClass().getName());} catch (IOException e) {System.out.println("URL incorrect : "+args[0]); System.exit(0);} verifie(c); }}
274
demande de connexion
message MESSAGE
application client
machine hte processus sexcutant sur la machine du client Figure 20.4 Schma de communication entre processus
La demande de connexion par le client est la cration dune instance de la classe Socket indiquant la machine hte et un numro de port. Le lancement du serveur sur lhte de nom mycpu seffectue ainsi :
>java Serveur Serveur en ecoute sur le port: 45678
Le serveur est en attente de connexions de la part des clients. Un client demande une connexion ainsi :
>java Client mycpu Connexion: mycpu/189.154.12.87 port: 45678 ?toto !TOTO ?lulu !LULU ?fin Connexion stoppee par le serveur
Le point dinterrogation indique que le client attend un message de lutilisateur. Le point dexclamation prfixe le service rendu par la connexion.
Un exemple client-serveur
275
Serveur
Le serveur est un processus dont lune des variables dinstance est une instance de ServerSocket initialise la cration du serveur. La mthode run() de ce processus est une boucle interruptible par un signal de la classe IOException. Cette boucle effectue le cycle suivant : attente dune demande de connexion (mthode accept()) puis cration dune instance de la classe Connexion partir du Socket que lui a renvoy la mthode accept(). Cest la classe Connexion qui ralise le service de transformation des caractres en majuscules.
import java.io.*; import java.net.*; public class Serveur extends Thread { protected static final int PORT=45678; protected ServerSocket ecoute; public Serveur () { try { ecoute=new ServerSocket(PORT);} catch (IOException e) { System.err.println(e.getMessage()); System.exit(1); } System.out.println("Serveur en ecoute sur le port :"+PORT); this.start(); } public void run() { try { while (true) { Socket client=ecoute.accept(); Connexion c= new Connexion(client); }} catch (IOException e) { System.err.println(e.getMessage()); System.exit(1); } } public static void main(String[] args) { new Serveur(); } }
La classe Serveur
Connexion
Une instance de la classe Connexion est cre par le serveur. Cette Connexion ralise la transformation des caractres en majuscules. Il y a un processus de cette classe pour chaque client. Le canal de communication entre le client et une connexion est le socket que le serveur a fourni la suite dune demande de connexion dun client.
276
processus connexion
application client
in out
socket
socket
canalEcriture canalLecture
Les canaux de lecture et dcriture sur les sockets sont rcuprs par les mthodes getInputStream() et getOutputStream() de la classe Socket.
import java.io.*; import java.net.*; class Connexion extends Thread{ protected Socket client; protected BufferedReader in; protected PrintStream out; public Connexion(Socket client_soc) { client=client_soc; try {in =new BufferedReader(new InputStreamReader(client.getInputStream())); out =new PrintStream(client.getOutputStream());} catch (IOException e) { try {client.close();} catch (IOException e1) {}; System.err.println(e.getMessage()); return; } this.start(); } public void run() { String ligne; try { while(true) { ligne=in.readLine(); // lecture avec attente message client // test de la fin de connexion demande par le client if (ligne.toUpperCase().compareTo("FIN")==0) break; out.println(ligne.toUpperCase()); //ralisation du service }} catch (IOException e) {System.out.println("connexion :"+e.toString());} finally {try {client.close();} catch (IOException e){};} }
La classe Connexion
Un exemple client-serveur
277
Un client est une application sexcutant sur une autre1 machine. La connexion se fait par la demande de cration dun socket sur un hte et sur un numro de port. Ce numro de port doit tre identique celui du serveur.
import java.io.*; import java.net.*; public class Client { protected static final int PORT=45678; public static void erreur() { System.err.println("Usage: java Client <hostname>"); System.exit(1); public static void main(String[] args) { Socket s=null; if (args.length!=1) erreur(); try { s=new Socket(args[0],PORT); BufferedReader canalLecture=new BufferedReader(new InputStreamReader(s.getInputStream())); BufferedReader console=new BufferedReader(new InputStreamReader(System.in)); PrintStream canalEcriture= new PrintStream(s.getOutputStream()); System.out.println("Connexion : "+ s.getInetAddress()+ " port : "+s.getPort()); String ligne; while (true) { System.out.print("?"); System.out.flush(); ligne=console.readLine(); // saisie message utilisateur canalEcriture.println(ligne); //demande du service ligne=canalLecture.readLine();//lecture service ralis // test de fin de connexion if (ligne==null){ System.out.println("Connexion stoppee par le serveur"); break;} // le service rendu est affich lcran System.out.println("!"+ ligne); } } // try catch (IOException e) {System.err.println(e);} finally {try {if (s!=null) s.close();} catch (IOException e2){}} } // main }
Client du serveur
Application 13 : Client
1. Lapplication fonctionne galement si le client est sur la mme machine que le serveur.
278
Le client indique la fin dune connexion par lenvoi du message fin. Lorsque ce message est reu par linstance de la classe Connexion, celle-ci ferme le socket. Le processus termine alors son excution. Le client identifie la fin effective de la connexion en dtectant la fin du fichier sur le canal de lecture. En effet, la mthode readLine() renvoie la chane null en fin de fichier.
20.7 Tldiscussion
Cet exemple est bas sur une relation client-serveur avec des clients communiquant par lintermdiaire du serveur, celui-ci maintenant une liste des connexions. Le fonctionnement de ce serveur est simple. Il envoie tous les clients le message quil a reu dun client. Un tel service constitue une tldiscussion entre plusieurs personnes communiquant par lintermdiaire de leur clavier. Tous les messages envoys sont prfixs par le nom du client afin didentifier les propos des diffrents interlocuteurs. La tldiscussion n personnes ncessite le maintien dune liste des connexions courantes. Cette liste doit tre mise jour chaque nouvelle connexion dun client et chaque dpart dun client de la discussion. Ds quune connexion re oit un message de son client, elle doit accder la liste des connexions pour envoyer ce message tous les clients. Plusieurs processus accdent en lecture et en criture cette liste des connexions, qui doit tre protge (voir p. 107). Le mot cl synchronized garantit cette protection.
Tldiscussion
279
ou est rveill par une connexion. Son rle est de tester lactivit dune connexion. Si celle-ci est inactive, elle est retire de la liste. Une connexion est inactive si sa mthode run() a termin son excution; lapplication client : son rle est de permettre la saisie des messages de lutilisateur, et dafficher les messages de sa connexion (venant en fait dautres clients via leur connexion respective). Contrairement lexemple prcdent, o lmission et la rception de messages taient synchronises, ici un client peut rester couter la discussion, en intervenant de temps en temps; lcoute et la rception sont donc asynchrones. Un second processus, lcouteur est donc ncessaire; le processus couteur : il sexcute sur la mme machine que le client. Son rle est dafficher tous les messages quil reoit de la connexion. Il fonctionne indpendamment de lutilisateur; Tous les processus sexcutant sur la machine hte accdent de manire exclusive la liste des connexions : le serveur pour ajouter des connexions; le nettoyeur pour en enlever; chaque connexion pour rpercuter les messages sur toutes les connexions (y compris elle-mme) afin que la discussion soit partage par tous.
Le serveur
Le constructeur de ce processus cre une instance de ServerSocket pour grer les demandes de connexions, une instance de Vector pour stocker la liste des connexions et une instance du processus Nettoyeur.
import java.io.*; import java.net.*; import java.util.*; public class ServeurTD extends Thread { protected static final int PORT=45678; protected ServerSocket ecoute; protected Vector connexions; protected Nettoyeur nettoyeur; public ServeurTD () { try {ecoute=new ServerSocket(PORT);} catch (IOException e) {System.err.println(e.getMessage()); System.exit(1); } System.out.println("Serveur en ecoute sur le port :"+PORT); connexions=new Vector(); nettoyeur=new Nettoyeur(this);
280
La classe ServeurTD
Tldiscussion
281
La cration dune nouvelle connexion entrane son ajout dans la liste connexions, cet ajout tant protg de lexcution simultane dautres processus.
Une connexion
Les instances de cette classe sont galement des processus. Le constructeur de cette classe reoit plusieurs rfrences en paramtres. Le socket est la liaison entre le client et la connexion. La rfrence au serveur permet laccs la liste des connexions; celle du nettoyeur permet son rveil par la connexion. La mthode run() de ce processus attend un message du client sur son socket. Lorsquelle en reoit un, elle demande laccs exclusif la liste des connexions, puis crit sur le socket de chaque connexion de cette liste le message quelle a reu. Pendant cette criture, il est noter que toutes les connexions de la liste (si elles sont actives) sont en attente soit dun message de leur client, soit de laccs la liste des connexions (cest--dire quelles ont reu un message, mais ne lont pas encore trait). Une connexion non active peut figurer dans la liste car le nettoyeur nest pas prioritaire pour laccs la liste; cela ne produira pas derreur car la mthode println() de la classe PrintStream ne signale pas dexception en cas de problme.
import java.io.*; import java.net.*; import java.util.*; import java.io.*; import java.net.*; import java.util.*; class ConnexionTD extends Thread{ protected Socket client; protected ServeurTD serveur; protected BufferedReader in; protected PrintStream out; protected Nettoyeur nettoyeur; public ConnexionTD(Socket client_soc, Nettoyeur n, ServeurTD s) {client=client_soc; nettoyeur=n; serveur=s; try{ in =new BufferedReader(new InputStreamReader(client.getInputStream())); out =new PrintStream(client.getOutputStream());} catch (IOException e){ try {client.close();} catch (IOException e1) {}; System.err.println(e.getMessage()); return; } this.start(); }
282
La classe ConnexionTD
Le nettoyeur
Le nettoyeur est un processus dont le constructeur requiert une rfrence au serveur pour laccs la liste des connexions. La mthode run() de ce processus est une boucle sans fin (larrt du serveur entranera larrt du nettoyeur). Cette boucle fait attendre le nettoyeur cinq secondes puis demande laccs exclusif la liste des connexions pour en vrifier lactivit. Une connexion inactive est retire de la liste. Le parcours de cette liste se fait de la fin au dbut car la mthode de retrait de la liste compacte les lments restant dans la liste1. La veille du nettoyeur peut tre interrompue par une notification provenant dune connexion.
import java.io.*; import java.net.*; import java.util.*; class Nettoyeur extends Thread{ protected ServeurTD serveur; protected Nettoyeur(ServeurTD serveur) {this.serveur=serveur; this.start(); }
1. Le faire dans lautre sens impliquerait, en cas de retrait, de ne pas incrmenter lindice de la boucle. Dans les boucles for, cet indice est mis jour automatiquement et une bonne pratique de programmation consiste ne pas le modifier dans le corps de la boucle. Un second intrt de ce parcours lenvers rside dans le temps pass conserver exclusivement une ressource partage : lvaluation de la taille de la liste na lieu quune seule fois pour initialiser lindice, et non chaque itration dans un parcours du dbut la fin. Le paralllisme est donc augment.
Tldiscussion
public synchronized void run() { while(true) {try {this.wait(5000);} catch (InterruptedException e){}; synchronized(serveur.connexions) {for (int i=serveur.connexions.size()-1;i>=0;i--) {ConnexionTD c= (ConnexionTD) serveur.connexions.elementAt(i); if (!c.isAlive()) {serveur.connexions.removeElementAt(i); System.out.println("Fin de connexion : OK"); } }} // for } // while }
283
La Classe Nettoyeur
Lapplication client
Linterface de cette application (application 14, figures 20.7 et 20.8) est une fentre compose de deux champs de texte : un en bas pour la saisie et un en haut pour laffichage des messages. Cette fentre contient galement deux boutons envoi et stop. La classe AppliClient est une sous-classe de la classe Frame. Le constructeur de lapplication client appelle le constructeur de la classe Frame, puis demande la cration dun socket sur la machine sur laquelle fonctionne le serveur. Le processus couteur est cr pour permettre la lecture sur le socket de manire asynchrone avec la saisie des messages de lutilisateur. La mthode actionPerformed() traite les messages de fin de ligne dans la zone de saisie et lappui sur le bouton envoi. Le traitement de ce message consiste crire sur le socket le texte que lutilisateur a tap. Lappui sur stop signale la demande de fin de connexion de la part dun client puis arrte lapplication client.
import java.io.*; import java.net.*; import java.awt.*; import java.awt.event.*; public class AppliClient extends Frame implements ActionListener { public static final int PORT=45678; Socket s; PrintStream canalEcriture; TextField entree; TextArea visu; Button envoi,stop; Panel boutons; String Nom; public AppliClient(String n, String host) {
284
public void actionPerformed(ActionEvent e) { if ((e.getSource()==envoi) || (e.getSource()==entree)) { canalEcriture.println(Nom+">"+entree.getText()); entree.setText(""); } if (e.getSource()==stop) { canalEcriture.println(Nom+">FIN"); System.exit(0); } } // actionPerformed public static void main(String[] args) { Frame f= new AppliClient(args[0],args[1]); } //main
Le client prend un paramtre sur la ligne de commande, le nom de lutilisateur, afin de prfixer chaque message par son auteur.
Tldiscussion
285
Le processus couteur
Le processus couteur est assez simple. Il attend les messages provenant du socket et les affiche au fur et mesure dans le champ de texte adquat de la fentre graphique.
import java.io.*; import java.net.*; import java.awt.*; class Ecouteur extends Thread{ BufferedReader canalLecture; TextArea visu; public Ecouteur(Socket s,TextArea out) throws IOException { canalLecture= new BufferedReader (new InputStreamReader(s.getInputStream())); visu=out; this.start(); } public void run() { String ligne; try {while (true) {ligne=canalLecture.readLine(); if (ligne==null) break; visu.append("\n"+ligne); }} catch (IOException e) {visu.setText(e.toString());} finally {visu.setText("connexion interrompue par le serveur");} }
Le processus Ecouteur
Les copies dcrans ci-dessous montrent une tldiscussion entre Gilles et Andr. Les deux clients fonctionnent respectivement sur Windows 95 et sur Sun.
286
Partie IV
21. Conception des classes 22. Mcanismes pour la rutilisation 23. Structures de donnes 24. Composition du logiciel 25. Processus et concurrence 26. Intgration des applets 27. Scurit en Java 28. Java et les bases de donnes 29. Fabriquer des objets rpartis avec RMI 30. Fabriquer des objets rpartis avec CORBA 31. Les autres API de Java
Chapitre 21
Modularit et encapsulation
La modularit est une technique de dveloppement, que lon retrouve du reste dans la plupart des disciplines dingnierie, qui consiste voir un systme complexe comme un assemblage de parties plus simples, appeles modules. Pour que la technique soit efficace, il est primordial que la construction de chaque module soit aussi indpendante que possible de celle des autres modules. Lencapsulation est une technique pour raliser cette indpendance entre modules ; elle est base sur une nette sparation entre les parties publique et prive de chaque module. La partie publique dun module, souvent appele inter-
290
face, dfinit les services que ce module offre aux autres. La partie prive, appele implantation, dfinit la faon dont le module ralise les services offerts; cette partie contient des structures de donnes et les instructions excutables ncessaires. Lorsquun module veut obtenir un service dun autre module, il sadresse toujours et uniquement linterface publique de ce dernier, il na aucun accs sa partie prive. La figure 21.1 illustre ce principe.
A
public demande du service B
priv
rponse
structures de donnes
instructions
C
Figure 21.1 Demande dun service un module
Lintrt de cette sparation public-priv rside dans le fait que la partie prive peut tre ralise et modifie sans que les clients du module ne soient perturbs, puisquils voient toujours la mme interface. Un logiciel modulaire avec encapsulation sera donc plus facile dvelopper et surtout maintenir quun logiciel monolithique dont toutes les parties sont interdpendantes.
Les origines
291
Il sensuit une manire de dfinir les types de donnes en deux phases : premirement, on sintresse aux oprations et leur signification, cest la partie abstraite de la dfinition; deuximement, on choisit une reprsentation pour ce type de donnes et on crit le corps (les instructions) des oprations, cest la concrtisation (aussi appele rification). Une mme dfinition abstraite peut donner lieu plusieurs ralisations concrtes suivant les moyens disposition, les contraintes, les normes de programmation, etc. Si lon reprend lexemple prcdent du type rectangle, on commencera par dfinir un ensemble doprations telles que : rect : (entier, entier, entier, entier) ! rectangle; translation : (rectangle, entier, entier) ! rectangle; agrandissement : (rectangle, entier, entier) ! rectangle; qui servent produire des rectangles. Lopration rect(X, Y, L, H) fournit le rectangle dont le coin suprieur gauche est (X, Y), la largeur L et la hauteur H. Lopration translation(R, DX, DY) fournit le rectangle obtenu par translation du rectangle R dune distance horizontale DX et verticale DY. Lopration agrandissement(R, DL, DH) fournit le rectangle situ au mme endroit que R mais dont la largeur et la hauteur sont celles de R agrandies de DL et DH respectivement.
Les oprations suivantes sont des oprations daccs qui fournissent des proprits dune valeur de type rectangle. gauche : (rectangle) ! entier; haut : (rectangle) ! entier; bas : (rectangle) ! entier; droite : (rectangle) ! entier; largeur : (rectangle) ! entier; hauteur : (rectangle) ! entier; Pour complter la description dun type abstrait, il faut expliquer la signification des oprations. On peut bien sr le faire laide dun texte en fran ais mais si
292
lon veut une explication absolument non ambigu, il est prfrable de recourir un ensemble dquivalences telles que : 1. 2. 3. 4. 5. 6. Gauche(rect(X, Y, L, H)) " X. Largeur(rect(X, Y, L, H)) "L. Gauche(translation(R, DX, DY)) " gauche(R) + DX. Gauche(agrandissement(R, DL, DH)) " gauche(R). Largeur(agrandissement(R, DL, DH)) " largeur(R) + DL. Droite(R) " gauche(R) + largeur(R).
Ces quivalences dfinissent formellement la signification des oprations, de sorte quun utilisateur du type abstrait peut comprendre prcisment ce qui va se passer lorsquil utilisera telle ou telle opration. Par exemple, lquivalence 5 exprime le fait que le rectangle obtenu par agrandissement est plus large de DL que le rectangle original. La dfinition complte dun type abstrait peut savrer assez fastidieuse, car il faut videmment noncer toutes les proprits des oprations. Le lecteur intress trouvera de nombreux ouvrages de gnie logiciel traitant de ce sujet, comme par exemple [12] ou [1].
Objets et classes
class Rectangle { /* schma de la partie prive */ private int gauche, haut, largeur, hauteur; /* schma de la partie publique */ public void positioner(int posX, int posY) { haut = posX; gauche = posY; } public void deplacer(int dv,int dh) { haut += dv; gauche += dh; } // etc. } ... /* instanciation */ Rectangle r = new Rectangle();
293
deplacer() positionner()
haut largeur
105 gauche 10 12 33
hauteur
La variable echelle appartient la classe elle-mme, elle est partage par toutes les instances. Dans lexemple ci-dessus, la mthode surface() utilise la variable
294
de classe echelle. Les variables de classe se rapprochent des variables globales qui existent dans les langages procduraux comme Pascal ou C. Pour excuter une mthode de classe, il faut la prfixer du nom de sa classe. Par exemple :
Rectangle.defEchelle(4.25);
En fait, tout se passe comme si defEchelle() tait une mthode dinstance dun objet appel Rectangle.
qui apparat dans un programme indique que lon peut utiliser les instructions (aprs la cration de lobjet r) :
r.positionner(x, y) r.deplacer(dx, dy) etc.
Interfaces
class Rectangle { private int haut, bas, gauche, droite; public void positionner(int x, int y) { int l = droite - gauche; int h = bas - haut; haut = x; gauche = y; bas = haut + h; droite = gauche + l; } public int bas() { return bas; } public defBas(int b) { bas = b; } public int surface() { return (bas-haut)*(droite-gauche); } /* variante 2. */
295
class Rectangle { private int haut, gauche, hauteur, largeur; public void positionner(int x, int y) { haut = x; gauche = y; } public int bas() { return haut + hauteur; } // les coordonnes croissent vers le bas ! public defBas(int b) { hauteur = b - haut; } public int surface() { return (hauteur * largeur); }
21.3 Interfaces
La notion dinterface en Java correspond une spcification de type abstrait sans aucune implantation, cest--dire une spcification de type dcrite uniquement par la liste de ses oprations. Une interface est compose dun ensemble den-ttes de mthodes et ventuellement de constantes. Par exemple :
interface public public public } Vendable { int prix(); int rabais(int quantite); void changerPrix(int prix);
296
La ralisation concrte dune interface est dlgue une classe devant possder (ou hriter) une mthode concrte pour chaque mthode abstraite de linterface. Par exemple :
class Moto implements Vendable { private String marque, modele; private int prix, cylindree, poids, puissance; // mthodes servant impanter Vendable public int prix() { return prix; } public int rabais(int quantite) { if(quantite > 5) return prix/10; else return 0;} public void changerPrix(int prix) { this.prix = prix; } // autres mthodes Moto(String m, int p) {marque = m; prix = p; } void imprime() {System.out.println(marque + " prix: " + prix);} }
La notion dinterface pousse lextrme le dcouplage entre la spcification et limplantation dun type. Une interface dfinit un type de donnes qui peut servir typer des variables ou des paramtres de mthodes. On peut affecter une variable dclare dun type interface I tout objet dune classe qui implante I. Par exemple :
Vendable v; v = new Moto("Honda", 16678);
De mme, partout o un paramtre de type I est attendu, on peut passer un objet dune classe qui implante I.
Description textuelle
Une manire simple de dcrire leffet dune mthode consiste crire un texte en franais. Un tel texte prsente les avantages et inconvnients de la langue
297
naturelle : dun ct, il est facilement lisible par un tre humain et peut sappuyer sur toutes sortes de connaissances implicites; dun autre ct, il peut prsenter des ambiguts telles que deux lecteurs pourront linterprter diffremment. La langue naturelle peut galement savrer trop lourde pour dcrire des faits qui sexpriment trs simplement dans un langage plus formel comme les mathmatiques. Cest pourquoi nous proposons dajouter une description plus formelle de chaque mthode et de chaque classe. Il existe pour cela de nombreux formalismes plus ou moins abstraits et plus ou moins simples manipuler; nous examinerons la technique des pr- et postconditions et des invariants.
Les prconditions
Une mthode travaille partir dun objet (this) et des paramtres qui lui sont fournis. Cependant, certaines valeurs de paramtres ou variables dinstance de lobjet peuvent ne pas avoir de sens pour la mthode. Par exemple, la mthode qui modifie la largeur dun rectangle ne peut rien faire dun paramtre ngatif, de mme une mthode calculant la moyenne des nombres contenus dans une liste na pas de sens pour une liste vide. Les prconditions fixent donc les conditions dans lesquelles une mthode peut sexcuter correctement. Elles dpendent de ltat de lobjet this (tat dfini par ses variables dinstance) et des paramtres. Exemples :
public void defLargeur(int lrg) { // PRE-CONDITION: lrg > 0 ... } public void deplace(int dh, int dv) { // PRE-CONDITION: this.gauche() + dh > 0 // et this.haut() + dv > 0 ... }
La condition ci-dessus garantit quon ne tente pas un dplacement qui amnerait le rectangle hors du systme de coordonnes (qui commence (0,0)). On remarque sur ce dernier cas, que la prcondition est exprime laide des mthodes publiques gauche() et haut() et non des variables prives gauche et haut. Cette expression est donc publique, ce qui signifie quon peut la tester depuis lextrieur de la classe Rectangle, par exemple avant dappeler la mthode.
Rectangle r; ... r = new Rectangle; ... if (r.gauche() + deplH > 0 & r.haut() + deplV > 0) { r.deplace(deplH, deplV); } else ...
298
Alternativement, si la prcondition est teste dans la mthode et dclenche une exception, la mthode appelante saura, si elle capte lexception, que lexpression de prcondition est fausse. Une telle prcondition est indpendante de la reprsentation interne de lobjet, elle est donc compatible avec le principe dencapsulation et fournit une information sur le comportement dune mthode de la classe comprhensible indpendamment des dtails internes de la classe.
Les post-conditions
Si la prcondition garde la porte dentre dune mthode, la postcondition indique ce quest devenu lobjet aprs lexcution de la mthode, sil a t transform ou non, et quel est lventuel rsultat produit. Nous utiliserons deux pseudovariables : resultat qui reprsente le rsultat retourn par la mthode, sil y en a un, et this_post qui reprsente la valeur de lobjet this aprs lexcution de la mthode. Considrons tout dabord le cas dune mthode qui ne modifie pas lobjet mais fournit un rsultat de calcul.
public int surface() { // PRE-CONDITION: aucune // POST-CONDITION: resultat = this.hauteur() * this.largeur() ... }
La postcondition dtermine la valeur qui sera retourne comme rsultat en fonction de ltat de lobjet (ici sa largeur et sa hauteur). Il faut bien voir que la postcondition nest pas l pour dire comment le calcul est fait; le calcul dpend de la reprsentation interne de lobjet. Comme dans le cas des prconditions, on exprime les postconditions laide des paramtres, de lobjet this et des mthodes publiques de manire rendre cette condition lisible de lextrieur de la classe. Lorsque la mthode modifie lobjet, on peut exprimer ce changement soit par son effet sur les variables dinstance de lobjet, soit en disant ce qui se passe lorsquon applique des mthodes daccs sur lobjet transform. La deuxime technique est la meilleure car elle ne met pas en jeu la reprsentation interne de lobjet. Compltons ainsi nos dfinitions des mthodes defLargeur et deplacer de la classe Rectangle.
public void defLargeur(int l) { // PRE-CONDITION: l > 0 // POST-CONDITION: this_post.largeur() = l // (le nouveua rectangle a une largeur l)
Exceptions
... } public void deplace(int dh, int dv) { // PRE-CONDITION: this.gauche() + dh > 0 // et this.haut() + dv > 0 // POST-CONDITION: this.gauche() = this_pre.gauche() + dh // et this.haut() = this_pre.haut() + dv ... }
299
Les invariants
Les invariants sont des expressions logiques qui doivent rester vraies durant toute la vie dun objet. Un invariant ne dcrit pas ce que fait une mthode mais ce quest et doit rester un objet de cette classe. Dans notre classe Rectangle, on pourrait ajouter linvariant :
pour tout Rectangle r: r. hauteur() >= 0 et r.largeur() >= 0
pour prciser quen toute circonstance ni la largeur ni la hauteur dun rectangle ne peuvent devenir ngatives. Dans une classe RectanglePlat destine reprsenter des rectangles dont la largeur est suprieure la hauteur on aura linvariant :
pour tout RectanglePlat c: c.hauteur() <= c.largeur()
Les invariants induisent bien videmment lobligation pour toutes les mthodes de la classe de les maintenir vrai . Par exemple, dans le cas de notre classe RectanglePlat, la mthode defLargeur(int l) devra dune manire ou dune autre garantir que la largeur reste suprieure la hauteur.
21.5 Exceptions
Le mcanisme dexceptions offre un moyen lgant de structurer la gestion des erreurs ou des cas exceptionnels qui empchent le bon droulement des oprations. Dun point de vue purement syntaxique, le mcanisme dexceptions simplifie lcriture du code en remplaant : des cascades de if imbriqus; la transmission dindicateurs de succs ou dchec des mthodes. Dans le premier cas, un fragment de code de la forme :
if (erreur) traiterErreur(); else { ... if (erreur) traiterErreur(); else { ... if (erreur) traiterErreur();
300
else { ... etc. } } }
devient :
try { if (erreur) throw new MonException(); ... if (erreur) throw new MonException(); ... if (erreur) throw new MonException(); ... etc. } catch (MonException me) traiterErreur();
Il ny a plus dimbrication de if et le traitement de lerreur nest spcifi quune seule fois, ce qui garantit quil est uniforme pour toutes les erreurs dun type donn. La propagation des exceptions aux mthodes appelantes remplace les codes de retour que la mthode appelante devrait tester pour sassurer que tout sest bien pass :
if (canal.lire(desBytes) != 0) traiterErreur(); else { ... if canal2.ecrire(desBytes) != 0) traiterErreur(); else { ... suite } }
devient :
try { canal.lire(desBytes); // il ny a plus de code tester ... canal2.ecrire(desBytes); ...} catch (ExceptionCanal ec) traiterErreur();
Malgr ces possibilits attrayantes, il ne faut pas abuser de lutilisation des exceptions. Le traitement dexceptions doit rester limit aux cas exceptionnels. La propagation et la capture des exceptions sont relativement coteuses en temps de calcul. Le try... catch ne doit donc pas servir de nouvelle structure de contrle, les if, switch, while et for tant amplement suffisants pour exprimer
301
les algorithmes et sexcutant beaucoup plus rapidement. Il ne faut pas non plus en faire un goto dguis. Dautre part, certains types dexceptions ne devraient pas tre capturs car ils reprsentent des erreurs profondes, souvent irrparables. Les capturer reviendrait poursuivre lexcution du programme dans un tat instable qui ne conduirait qu de nouvelles erreurs. La hirarchie des exceptions prdfinies en Java est ainsi subdivise en deux parties : les erreurs qui sont des sous-classes de Error; les exceptions qui sont des sous-classes de Exception.
302
Il est commode de reprsenter graphiquement les relations entre classes. De nombreux formalismes ont t dvelopps cet effet, du modle Entits-associations des annes 70 au modle unifi UML [http://www.rational.com/uml] qui tend devenir le standard actuel. Dans ce formalisme, on reprsentera les relations entre commandes, clients, marchandises et factures que nous avons nonces plus haut de la manire suivante :
1 facturation * Facture 1 concerne > Client 1 passage-commande * * Commande 1 Marchandise
Les relations sont reprsentes par des lignes tiquetes par un nom. Les symboles 1 et * aux extrmits indiquent les cardinalits uniques ou multiples des relations. Par exemple, la relation passage-commande peut associer un client une ou plusieurs commande(s) mais chaque commande au plus un client. Le symbole > suivant un nom de relation indique simplement un sens de lecture ( une facture concerne une commande et non une commande concerne une facture )
303
Remarquons toutefois que la reprsentation par variables dinstance est sens unique. Dans notre exemple, on peut atteindre un client depuis une facture, grce la variable client, par contre on ne peut pas trouver partir dun client toutes les factures le concernant. Il faudrait pour cela ajouter une variable Facture [] factures dans la classe Client et sassurer quen tout temps, il y a cohrence entre client et factures. Sur un diagramme, on peut indiquer le ou les sens de parcours autoriss en ajoutant des pointes de flches aux extrmits des lignes figurant une relation. Il est galement possible de reprsenter certaines relations laide de mthodes. Par exemple, la relation facturation de Facture Client peut tre calcule par une mthode, en se basant sur lhypothse que le client facturer est celui qui a pass la premire commande faisant lobjet de la facture.
class Facture { Client client() { return commandes[0].client; } ...
Nous verrons dans le chapitre consacr aux structures de donnes quil existe dautres possibilits de raliser des relations en utilisant les classes collections. Parmi les relations entre concepts, la relation gnrique-spcifique ou est un (une chaise est un meuble, un ordinateur est une machine, etc.) joue un rle particulier que nous tudierons dans le cadre de lhritage entre classes. En rgle gnrale, on vitera de reprsenter cette relation par une variable ou une mthode.
304
Cette solution est base principalement sur quatre classes dobjets : Terrain, PointMobile, Serpent et Appat. Le diagramme ci-dessous dcrit les relations qui nous intressent entre ces classes.
JeuSerpent 1 se_joue_sur 1 Terrain 1 < sur 1 1 Figure 21.6 Structure des classes de lapplet JeuSerpent Serpent 1 position_tte 1 1 < sur * Appat * position 1 1 *
PointMobile
position_corps 1 position_queue
Un terrain est le lieu o se droule le jeu, il est compos dune surface de jeu dont les cases sont arranges en lignes et colonnes. Chaque case du terrain peut contenir rien, une partie du cadre, une partie du serpent ou un appt. Les oprations sur un terrain consistent essentiellement lire ou modifier le contenu dune case, et dessiner le terrain en entier ou juste une case. La classe dfinit un ensemble de constantes qui permettent dcrire du code plus lisible. La position du corps du serpent est reprsente par les cases du terrain qui contiennent lune des constantes DROITE, GAUCHE, BAS ou HAUT. Ces constantes indiquent la direction suivre pour arriver la case suivante du serpent. On peut donc dire que ces cases matrialisent la relation position_corps.
class Terrain { // constantes static final Color
305
COULEUR_VIDE = Color.lightGray, COULEUR_CADRE = Color.black, COULEUR_APPAT = Color.red, COULEUR_SERPENT = Color.yellow; static final char CADRE=C, VIDE =V, APPAT=A, DROITE=D, GAUCHE=G, HAUT=H, BAS=B; // representation du terrain par une matrice de caracteres private char t[][]; public int largeur,hauteur; public int tailleCase; // taille dune case en pixel private Graphics g; // la feuille de desin de lapplet Terrain(int l, int h, int tc, Graphics appletG){ g = appletG; largeur = l;hauteur = h;tailleCase = tc; t = new char [l+1][h+1]; // initialisation du terrain: cadre au bord et vide a linterieur for (int i = 0; i <= largeur; i++) for (int j = 0; j <= hauteur ; j++) { if ((i==0) | (i==largeur) | (j==0) | (j==hauteur)) t[i][j]= CADRE; else t[i][j]=VIDE; } } public int taille() { return (largeur+hauteur)/2;} public char contenuCase (PointMobile p) {return t[p.x][p.y];} public void modifCase (PointMobile p, char v) {t[p.x][p.y]=v;} public void redessine(){ PointMobile p = new PointMobile(0,0); for (int i = 0; i <= largeur; i++) for (int j = 0; j <= hauteur ; j++){ p.deplacer(i,j); dessineCase(p); } } // Modifie le contenu dune case et la redessine public void majCase(PointMobile p, char v) { modifCase(p, v); dessineCase(p); } // Dessine une case, la couleur indique le contenu public void dessineCase (PointMobile p) { switch (t[p.x][p.y]) { case APPAT: g.setColor(COULEUR_APPAT); break; case CADRE: g.setColor(COULEUR_CADRE); break; case VIDE: g.setColor(COULEUR_VIDE); break; default: g.setColor(COULEUR_SERPENT); }
306
Un pointMobile reprsente une position sur le terrain, il peut se dplacer dans les quatre directions droite, gauche, haut, bas.
class PointMobile { public int x, y; PointMobile(int initx, int inity){ x=initx;y=inity; } public void deplacer(int cx, int cy){ x=cx;y=cy; } public void avance(char direction){ switch (direction) { case Terrain.DROITE: x++;break; case Terrain.GAUCHE: x--;break; case Terrain.BAS: y++;break; case Terrain.HAUT: y--;break; } } }
Un serpent volue dans un terrain, on peut dfinir la direction dans laquelle le serpent doit avancer (defDirection) et faire avancer le serpent (avance). Le serpent fournit aussi un message qui indique son tat. La reprsentation interne du serpent est compose des deux variables de type PointMobile : pTete et pQueue, qui implantent les relations position_tte et position_queue du diagramme de classes. La variable terrain implante la relation sur entre Serpent et Terrain.
class Serpent { String PointMobile PointMobile int Terrain char char int msg; pTete = new PointMobile(3,3); // position tete pQueue = new PointMobile(3,3); // position queue longueur = 1; terrain; directionTete = Terrain.BAS; directionQueue; grandir = 0;
Serpent (Terrain t){ terrain=t; terrain.majCase(pTete,directionTete); } // Avance la tete du serpent dans la direction directionTete
307
Un appt occupe une case dun terrain. Un appt disparat au bout dun laps de temps pour rapparatre ailleurs. La variable terrain implante la relation sur entre Serpent et Terrain.
class Appat{ private PointMobile position = new PointMobile(0,0); private int vieAppat = 0; private Terrain terrain; Appat (Terrain t){ terrain = t; } public void vivre(){ if (vieAppat > 0) vieAppat--; if (vieAppat==0) { if (terrain.contenuCase(position)==Terrain.APPAT) // effacement dun appat non consomme terrain.majCase(position,Terrain.VIDE); // lappat mort reapparait sur une autre case vide do {
308
Un jeu est compos dun terrain, dun serpent, de deux appts et dun processus danimation (runner) qui met jour rgulirement la position du serpent et des appts ainsi que le score. La variable terrain implante la relation se_joue_sur entre JeuSerpent et Terrain. Quant aux variables s, a1 et a2, elles permettent daccder directement au serpent et aux appts qui sont sur le terrain de jeu. Cest lapplet qui par son processus runner anime le jeu. La mthode run() met jour le serpent et les appts puis sendort un moment et recommence.
public class JeuSerpent extends java.applet.Applet implements Runnable, KeyListener, MouseListener{ Thread runner; Terrain t; Serpent s; Appat a1,a2; int tailleCase = 10; // taille en pixel dune case int vitesse = 50;// nb. de millisecondes entre chaque mouvement du serpent int hauteur = 100,largeur = 200; public void init() { String parametre; this.addKeyListener(this); this.addMouseListener(this); // lecture et initialisation parametres parametre = getParameter("vitesse"); if (parametre != null) vitesse = 1000 - Integer.parseInt(parametre); parametre = getParameter("hauteur"); if (parametre != null) hauteur = Integer.parseInt(parametre); parametre = getParameter("largeur"); if (parametre != null) largeur = Integer.parseInt(parametre); parametre = getParameter("grain"); if (parametre != null) tailleCase =
309
t = new Terrain((int)(this.getSize().width / tailleCase )-1, (int)(this.getSize(). height / tailleCase)-1, tailleCase,this.getGraphics()); setBackground(Terrain.COULEUR_VIDE); s = new Serpent (t); a1 = new Appat (t); a2 = new Appat (t); } public void start() { if (runner == null); { runner = new Thread(this); runner.start(); } } public void stop() { if (runner != null); { runner.stop(); runner = null; } } public void run() { int scoreMax = (t.largeur-1)*(t.hauteur-1); while (true) { if (s.avance()) { this.showStatus(s.msg+" Score="+s.longueur+ " maximum="+scoreMax); stop(); } a1.vivre(); a2.vivre(); try { Thread.sleep(vitesse);} catch (InterruptedException e) { } showStatus("Score="+s.longueur+" maximum="+scoreMax); } } public void paint(Graphics g) { t.redessine(); } /// implantation de KeyListener /// public void keyPressed(KeyEvent e) { int key = e.getKeyCode(); switch (key) { case KeyEvent.VK_DOWN: s.defDirection(Terrain.BAS); break; case KeyEvent.VK_UP:
310
if (Math.abs(xm - s.pTete.x*tailleCase) > Math.abs(ym s.pTete.y*tailleCase)) { // la distance horizontale (x) entre la tete et le click est // superieure a la distance verticale (y) if (xm>s.pTete.x*tailleCase) s.defDirection(Terrain.DROITE); else s.defDirection(Terrain.GAUCHE); } else { // la distance en y est plus grande if (ym>s.pTete.y*tailleCase) s.defDirection(Terrain.BAS); else s.defDirection(Terrain.HAUT); } } public void mouseEntered(MouseEvent e) { } public void mouseExited(MouseEvent e) { } public void mousePressed(MouseEvent e){ } public void mouseReleased(MouseEvent e){ } }
Le choix des classes retenu pour cette applet nest bien entendu pas le seul possible; il correspond un choix de concepts du domaine (le terrain, les points, le serpent, les appts). Nous aurions pu en faire un autre o apparatraient les classes Bord, Trajectoire, Score, etc. Nanmoins, le fait que notre logiciel soit structur en classes tend amliorer sa maintenabilit et son volutivit. Ainsi, vous devriez tre capable de crer de nouvelles versions de lapplet qui rpondent de nouvelles spcifications telles que : le serpent change de couleur chaque fois quil mange un appt; par endroits, le serpent passe au-dessus du sol, ce qui lautorise se croiser lui-mme;
311
la surface de jeu est une sphre . Si le serpent sort gauche, il revient par la droite (il ny a plus de bords); les appts se dplacent et cherchent fuir le serpent; il y a deux serpents symtriques sur la surface de jeu! etc.
Chapitre 22
314
mentalement. On dispose de ce fait dune technique de rutilisation trs souple. Passons tout dabord en revue les principales caractristiques de lhritage en Java.
un objet de la classe PointTopographique possdera trois variables dinstance x, y et alt, et on pourra lui appliquer les mthodes : distanceOrigine, distance et deplacer (mthodes hrites); altitude, ajusterAltitude (mthodes propres).
Hritage et sous-classes
Point p = new Point(3, 5); PointTopographique q = new PointTopographique(6, 4, 12); Point r = q; // r fait rfrence un PointTopographique
315
sera excute, le systme dexcution choisira la bonne mthode distanceOrigine(), en fonction de la classe de lobjet dsign par r, indpendamment du type dclar de r. En loccurrence, ce sera la mthode distanceOrigine() de la classe PointTopographique qui sera choisie. La dclaration de r comme Point et le fait quon ne puisse affecter r que des objets de sous-classes de Point garantit que lobjet dsign par r possde forcment une mthode distanceOrigine, et quil ny aura pas derreur dexcution du genre cette mthode nexiste pas pour cet objet .
Redfinition et surcharge
Contrairement dautres langages, en Java, la redfinition dune mthode doit avoir strictement les mmes paramtres que loriginale, sinon il ny a pas redfinition mais surcharge. Si, dans la classe PointTopographique on dfinit une mthode :
public double distance(PointTopographique p) {...}
on ne redfinit pas la mthode distance() hrite de Point mais on la surcharge, cest--dire que notre classe possde dsormais deux mthodes distance :
public double distance(Point pt) {...} // hrite public double distance(PointTopographique p) {...} // nouvelle
lune sappliquant si le paramtre effectif p est un Point et lautre si le paramtre effectif est un PointTopographique.
316
La rgle consiste choisir la mthode la plus spcifique, cest--dire celle dont les paramtres sont le plus bas dans la hirarchie des classes.
Point p1, p2; PointTopographique pt1, pt2; d=p1.distance(p2); // excute distance de Point car p1 est un Point d=p1.distance(pt1); // idem, un paramtre dune sous-classe est admis d=pt1.distance(p1); // excute la mthode distance(Point pt) hrite // car p1 est un Point d=pt1.distance(pt2);// excute distance(PointTopographique p) car // pt1 est un PointTopographique (liaison dynamique) // et pt2 est un PointTopographique
Cette rgle nexclut pas les ambiguts. Considrons deux mthodes m(Point p, PointTopographique pt) et m(PointTopographique pt, Point p) et p1, p2 et p3 qui sont PointTopographique. Linstruction p1.m(p2, p3) est alors ambigu car les deux mthodes sont applicables mais aucune nest plus spcifique que lautre. En Java, ces ambiguts provoquent une erreur la compilation.
Classes abstraites
Les classes abstraites sont des classes dont certaines mthodes, dites abstraites, sont dclares (nom et paramtres) mais ne possdent pas de corps dinstructions. Les diffrents types de classe et de mthode sont les suivants : une mthode est concrte si elle comporte un corps dinstructions (ventuellement vide {}); une mthode est abstraite si elle ne possde pas de corps dinstruction. Une telle mthode doit tre ncessairement implante dans une sousclasse dsire concrte; une classe est abstraite si elle dfinit une ou plusieurs signatures de mthodes abstraites; une classe est implicitement abstraite si elle ne dfinit aucune signature de mthode abstraite et si elle hrite de mthodes abstraites de ses super-classes directes ou non; une classe est concrte si toutes ces mthodes hrites ou non sont concrtes. Seules les classes concrtes sont instanciables. Le modificateur abstract doit prfixer la dfinition des classes et mthodes abstraites. Les classes abstraites ne sont pas instanciables, elles peuvent cependant servir typer des variables (ou des paramtres). Une telle variable fera toujours rfrence un objet dune sous-classe concrte.
Utilisations de lhritage
317
Eiffel, distingue douze manires rellement diffrentes dutiliser lhritage en programmation oriente objet. Nous ne les expliciterons pas toutes mais mettrons en vidence quelques points qui nous semblent importants. Nous distinguerons essentiellement deux types dutilisation de lhritage : lhritage dimplantation et lhritage de modlisation.
Hritage dimplantation
Lintrt de lhritage tient videmment lconomie dcriture de code. On ne rinvente pas ce qui existe et qui nous satisfait dj partiellement. De plus, on peut complter ce qui est hrit, voire le redfinir, de manire raliser le comportement voulu. Lextension est donc une technique de rutilisation relativement souple qui se distingue du tout ou rien . Suppression du traitement des cas Du point de vue de larchitecture du logiciel, lhritage combin la liaison dynamique peuvent nettement simplifier lcriture des mthodes en vitant les traitements de cas particuliers. Considrons une classe Piece qui reprsente des pices fabriques par une usine et supposons que ces pices peuvent tre soit simples, soit composes dautres pices. Si lon ne dfinit quune seule classe pour reprsenter toutes les pices, on obtient une dfinition de la forme :
class Piece { String nom; boolean estComposee; // la pice est-elle compose ? int poids; int nbComposantes; Piece [] composantes; ... int poidsTotal() { if (estComposee) { int pt = 0; for (int i = 0; i < nbComposantes; i++) pt += composantes[i].poidsTotal(); return pt; } else return poids; } ...
Cette classe prsente deux problmes : premirement, certaines variables dinstance sont utilises seulement si la pice est simple (poids) et dautres seulement si elle est compose (nbComposantes et composantes); deuximement, la mthode poidsTotal doit tester le genre de la pice pour calculer son poids. Il en est de mme pour toutes les mthodes qui doivent se comporter diffremment suivant le genre de pice. Sil y avait encore dautres types de pices, on verrait prolifrer les instructions switch dans le corps des mthodes. Pour obtenir du code plus simple, et donc moins sujet erreur, introduisons une petite hirarchie de classes : la classe Piece contient tout ce qui est commun
318
tous les genres de pice. Chaque sous-classe dfinit la structure et les traitements particuliers un type de pice. Piece est abstraite car les pices sont forcment soit simples soit composes, donc il ny a pas dinstance de Piece.
abstract class Piece { String nom; abstract int poidsTotal(); } class PieceSimple extends Piece { int poids; int poidsTotal() {return poids} } class PieceComposee extends Piece { int nbComposantes; Piece [] composantes; int poidsTotal() { int pt = 0; for (int i = 0; i < nbComposantes; i++) pt += composantes[i].poidsTotal(); return pt; } }
Nous obtenons un code beaucoup plus clair, qui ne comporte plus ni variables inutilises ni tests du genre de pice dans les mthodes. En fait, cest le mcanisme de liaison dynamique qui fait le travail de slection notre place. Une instruction :
p.poidsTotal()
appellera soit la mthode poidsTotal() de PieceSimple soit celle de PieceComposee, en fonction de la classe de lobjet dsign par p. Factorisation Lexemple ci-dessus illustre galement le processus de factorisation des proprits communes plusieurs classes. La variable nom existe pour toute pice, quelle soit simple ou compose, cest pourquoi elle est dfinie dans Piece. On peut galement factoriser des mthodes ou des parties de mthodes. Par exemple, la mthode affiche de Piece :
void affiche() { System.out.println("nom:" + nom + " poids: " + this.poidsTotal()); void affiche() { System.out.println("Pice simple "); super.affiche() // utilise la partie commune }
Lintrt de la factorisation est de dfinir les parties communes plusieurs classes en un seul endroit. Ceci garantit automatiquement la cohrence des caract-
Utilisations de lhritage
319
ristiques communes car il ny a pas vrifier quelles sont bien dfinies de la mme manire pour tous les types de pices.
Hritage de modlisation
tre ou avoir? Si nous reprenons loptique selon laquelle les classes forment un modle du domaine dapplication, il est alors intressant de considrer la relation entre une sous-classe et une classe comme un lien est un entre des concepts du domaine. Par exemple, un technicien est un employ dune organisation, autrement dit, lensemble des techniciens est inclus dans lensemble des employs. Ainsi la classe Technicien devrait tre une sous-classe de Employe. Par contre, un employ fait partie dune organisation mais nest pas une organisation, on peut aussi dire quune organisation a des employs. Ds lors Employe ne devrait pas tre une sous-classe de Organisation et la relation entre ces classes (voir figure 22.1) correspond celle que nous avons vue au point 21.6.
Employe fait partie de Organisation
est un (sous-classe) Technicien Figure 22.1 Deux natures de liens entre classes
Cette vision de lhritage clarifie larchitecture du logiciel, car la hirarchie des classes correspond assez naturellement celle des concepts du domaine. Du reste, dans certaines disciplines scientifiques comme la botanique ou la zoologie, il existe dj des hirarchies compltes de classification des objets (appeles taxonomies). Modliser ou implanter? Il arrive parfois que la vision taxonomique soppose lhritage dimplantation qui, comme nous lavons vu, a pour objectif de rutiliser un maximum de code dj crit. Prenons lexemple des deux classes Carre et Rectangle. Si lon ne pense quen termes dimplantation, on dfinira tout dabord Carre avec trois variables : x, y (coordonnes du coin suprieur gauche) et cote (longueur des cts). Puis on dira que Rectangle hrite de Carre et on ajoutera une variable coteHorizontal pour reprsenter la longueur du ct horizontal alors que cote servira pour la longueur du ct vertical.
class Rectangle extends Carre { int coteHorizontal; ... }
320
La hirarchie ainsi cre est exactement loppos de ce que nous connaissons en gomtrie o un carr est en fait un rectangle particulier dont les deux cts sont de mme longueur. Une solution plus proche du domaine de la gomtrie consisterait dfinir Carre comme une sous-classe de Rectangle. Dans ce cas, la sous-classe najoutera aucune proprit celles hrites mais dfinira la contrainte hauteur = largeur. Ngocier Il est trop strict dimposer le principe de lhritage bas sur le lien est un , car il existe bien des cas o ce lien nest pas vident. Dans notre exemple du point 22.1, la classe PointTopographique est une sous-classe de Point. Or, dun point de vue gomtrique, on ne peut pas dire que lensemble des points topographiques tel que nous lavons dfini (deux coordonnes plus une altitude) est un sous-ensemble de lensemble des points du plan (deux coordonnes). Malgr cela, on peut se dire quun point topographique est bien une sorte de point. En rsum, il est prfrable de rester le plus proche possible dune hirarchie correspondant au lien est un sans en faire un dogme absolu.
Hritage multiple
Java ne permet pas lhritage multiple dans la hirarchie des classes, par contre une classe peut la fois hriter dune autre et implanter une ou plusieurs interfaces. Cette situation correspond un cas frquent dutilisation de lhritage multiple dans les langages qui lautorisent. Une classe C hrite de A et de B mais nutilise que limplantation des mthodes de A et redfinit celles provenant de B. B nest l que pour apporter son interface. Par exemple, une classe PileParTableau qui hrite de Pile et de Tableau, utilisera limplantation de Tableau pour grer sa structure de donnes internes, et linterface de Pile dont elle redfinira les mthodes empiler, depiler, etc. Ce genre dhritage asymtrique correspond en Java une classe C qui hrite de A et implante linterface B. La situation que Java ne couvre pas est celle o limplantation des deux superclasses A et B serait rellement utilise.
Polymorphisme
321
sommet dune taxonomie stricte o toute pice doit forcment tre classe dans lune des sous-classes. La classe Dictionary du package java.util nous offre un autre cas dutilisation dune classe abstraite. Dictionary dfinit ce quest un dictionnaire (une structure o lon peut stocker des paires clvaleur) mais nimpose aucune ralisation. La classe Hashtable est une sous-classe concrte de Dictionary qui, elle, dfinit une structure de stockage (une table de hachage) et redfinit concrtement les mthodes de stockage et de recherche de Dictionary. Lide est de fournir un cadre gnral et de laisser les dveloppeurs raliser des classes concrtes qui satisfont des besoins particuliers, par exemple implanter les classes ArbreBinaire ou B_Arbre comme autres sous-classes de Dictionary.
22.4 Polymorphisme
Hritage et polymorphisme
Daprs les rgles de typage de Java, si une variable est dclare de type C, on peut lui affecter un objet de C ou de nimporte quelle sous-classe de C. A fortiori, si la variable est de type Object, on peut lui affecter nimporte quel objet, car toute classe est sous-classe de Object. Cette proprit permet de crer des structures polymorphes composes dobjets provenant de diverses classes. Par exemple, la dclaration :
Piece[] composantes;
indique que le tableau tabPieces contiendra des objets de PieceSimple ou de PieceComposee. Par contre, il sera interdit dy mettre des objets de Point ou de Rectangle, qui ne sont pas des sous-classes de Piece. Le polymorphisme est ici contrl (limit) par la classe Piece. Le polymorphisme nous vite la cration dautant de structures quil y a de types dobjets stocker ou traiter. Sans polymorphisme, nous aurions d dfinir un tableau pour les pices simples et un autre pour les pices composes. Les deux classes Vector et Hashtable permettent de crer des structures de donnes polymorphes sans restriction car leurs mthodes acceptent des paramtres de type Object. On peut, par exemple, mettre dans un mme Vector : un Rectangle, une Applet et... un Vector.
Interfaces et polymorphisme
Les interfaces offrent une seconde manire de crer des structures polymorphes contrles indpendamment de la hirarchie dhritage. Si une variable est dclare dun type interface I, on peut lui affecter un objet de nimporte quelle classe qui implante I.
322
Si les classes Moto, Montre et Casserole implantent toutes linterface Vendable, un tableau de type Vendable[6] pourra contenir deux motos, trois montres et une casserole, bien que leur classe respective nait aucune super-classe commune, mis part Object.
Dfinissons ensuite une classe Trieuse qui possde une mthode de classe tri() :
class Trieuse { public static void tri(Comparable[] x) { Comparable tmp; /* un simple tri par change */ for (int i = 0; i<x.length - 1; i++) for (int j = i+1; j<x.length; j++) if (x[j].plusPetitOuEgal(x[i])) { tmp = x[i]; x[i] = x[j]; x[j] = tmp; } } }
Nous voulons trier des motos selon leur prix, pour cela nous dfinissons une sous-classe de Moto qui implante linterface Comparable :
class MotoTriable extends Moto implements Comparable { public boolean plusPetitOuEgal(Object c) { return this.prix() <= ((Moto)c).prix(); } MotoTriable(String m, int p) {super(m,p); } }
Finalement, nous pouvons utiliser, par exemple dans un programme principal, notre mthode de tri :
public static void main(String[] args) { MotoTriable mt[] = {new MotoTriable("Honda", 16678), new MotoTriable("Kawasaki", 15099), new MotoTriable("Puch", 16000)}; Trieuse.tri(mt);
Gnricit et interface
for (int i = 0; i<mt.length; i++) mt[i].imprime(); }
323
Cet exemple montre une limite de la gnricit en Java. Dans linterface Comparable, nous avons dfini la mthode plusPetitOuEgal(Object c) dont le paramtre est de type Object, ce qui signifie quun objet est considr comme comparable seulement sil est comparable nimporte quel autre objet. En fait, il nous suffirait que lobjet soit comparable un autre objet de la mme classe. Or ceci nest pas exprimable en Java. De plus, dans la mthode tri(Comparable[] x), il nest pas possible de spcifier que le paramtre x doit contenir des objets qui sont tous des instances de la mme classe. On acceptera donc de trier des tableaux contenant la fois des motos, des vlos et des montgolfires. lheure actuelle, Java noffre donc pas de vritable mcanisme de gnricit indpendant du polymorphisme. De tels mcanismes existent depuis longtemps dans des langages comme Ada (packages, procdures, fonction gnriques), C++ (templates) ou Eiffel (classes gnriques).
Chapitre 23
Structures de donnes
Un objet est un module qui contient des donnes et des oprations daccs et de modification de celles-ci. Jusqu prsent, nous avons essentiellement rencontr des objets dont les donnes taient simples : soit des variables dun type de base; soit des rfrences dautres objets; ou encore des tableaux. Suivant le genre de problme que lon attaque, nous aurons besoin de donnes de structure beaucoup plus complexes, pensons par exemple un objet reprsentant en dtail lensemble de toutes les lignes ferroviaires dun pays. Ltude des structures de donnes sert prcisment raliser de tels objets complexes de manire systmatique et efficace. Nous verrons dans ce chapitre que lAPI Java peut venir notre secours dans ce domaine. Avant dexaminer les structures de donnes proprement dites, il est bon de se remmorer quelques notions relatives lidentit et lgalit des objets. Lune des difficults de la programmation par objets vient en particulier du fait que la distinction entre un objet et sa valeur reste souvent implicite. Pour les types de donnes primitifs, cette distinction na pas de raison dtre, on peut dire que lobjet 4 et la valeur 4 sont la mme entit. Par contre, pour les objets plus labors, il nen va pas de mme. Prenons par exemple trois rectangles construits de la manire suivante :
r1 = new Rectangle(10, 10, 8, 4); r2 = new Rectangle(10, 15, 7, 3); r3 = new Rectangle(10, 10, 8, 4);
Il sagit bien de trois objets diffrents (les tests r1 == r2, r1 == r3 et r2 == r3 donneraient chaque fois la valeur false), cependant r1 et r3 ont les mmes valeurs (si on les dessinait, ils seraient parfaitement superposs). Cest pourquoi il existe une mthode equals() qui teste non pas lidentit des objets, mais lgalit de
326
leur valeur. Ce test est bas sur le contenu des variables dinstance des objets. Dans lexemple ci-dessus, on aurait : r1.equals(r2) vaut false mais r1.equals(r3) vaut true.
Comparaisons
Bien que les chanes de caractres possdent en Java une reprsentation littrale sous forme dun texte entre guillemets, il est essentiel de se souvenir quil sagit dobjets et non de valeurs simples comme les boolens, entiers, flottants ou caractres. Cela signifie en particulier quil faut bien prendre garde distinguer lgalit et lidentit entre deux chanes. Par exemple, si lon crit :
String s1 = "Panoramix"; String s2 = "Pano" + "ramix";
rien ne garantit que (s1 == s2) donne comme rsultat true. En effet, s1 et s2 peuvent tre reprsents par deux objets diffrents qui ont tous deux la valeur "Panoramix", cela dpend de limplantation de la classe String. Par contre, il est certain que (s1.equals(s2)) donne true car equals() compare les deux objets caractre par caractre.
Reprsentation canonique
Lutilisation de equals() peut savrer coteuse en temps de calcul si lon doit comparer un grand nombre de fois des chanes de grande taille. Pour remdier cela, la classe String offre une reprsentation canonique des chanes grce la mthode intern(). Lexcution de s.intern() place la chane s dans un pool de chanes internes la classe String. Si le pool contient dj une chane t gale s, s.intern() retourne t comme rsultat, sinon s. Donc le pool ne contient jamais deux chanes de mme valeur, ce qui fait que si s1.equals(s2) vaut true alors s1.intern() == s2.intern() vaut aussi true, et rciproquement. Lorsquon travaille sur des chanes immuables que lon doit comparer trs souvent, cela vaut donc la peine de les remplacer par leur reprsentation canonique obtenue par intern(). On peut alors utiliser sans problme ==, qui est beaucoup plus rapide que equals() puisquil compare les identits dobjets et non les contenus.
Performances et StringBuffer
La reprsentation des chanes comme objets (instances de la classe String) peut galement avoir de fcheuses consquences sur les performances des program-
Les collections
327
mes si lon ny prend garde. Ceci est d au fait que les objets String sont immuables, ce qui signifie que toute modification dune variable String implique la cration dun nouvel objet String. Si lon excute le code suivant :
String allStars = "*"; for (int i = 1; i<10000; i++) allStars = allStars + "*";
chaque tour dans la boucle crera un nouvel objet. On se retrouvera la fin avec un objet String contenant la chane souhaite et 9999 objets inutiles contenant les valeurs "*", "**", "***", etc. Si lon tient compte des temps dallocation et de dsallocation de lespace mmoire occup par ces objets, la performance du programme sera nettement affaiblie par cet usage des Strings. Pour des programmes faisant un usage intensif de chanes de caractres dont la valeur change, il est fortement conseill dutiliser la classe StringBuffer. Cette dernire offre des chanes modifiables sans cration de nouvel objet et donc de bien meilleures performances. On crira par exemple :
StringBuffer allStarsB = new StringBuffer("*"); for (int i = 1; i<10000; i++) allStarsB.append("*"); String = allStarsB.toString();
328
tion peut interdire certaines oprations. Par exemple, on pourrait crer une implantation ListeCroissante de List qui permet dajouter des lments mais interdit den retirer. Les interfaces Set, List et Map hritent de Collection. Dans chacun de ces trois types de collection, on retrouve des mthodes pour : ajouter un ou des lments; retirer un ou des lments; tester lappartenance dlments de la collection; obtenir des caractristiques de la collection (taille, vide/non vide, comparaison); effectuer des oprations propres ce type. Cest la smantique de ces oprations qui distingue ces types de collections entre eux. Examinons plus en dtail chaque type. Dun point de vue pratique, lutilisation dune collection consiste choisir le type de collection adapt au problme traiter, puis choisir limplantation qui convient le mieux en termes de performances. Dans un programme Java, on aura en gnral :
<InterfaceCollection> maCollection; maCollection = new <classe implantant InterfaceCollection>(...);
Par exemple :
Set motsCles; motsCles = new TreeSet(); ...etc...
tableau dynamique
arbre quilibr
cellules lies
Les collections
329
Ensembles (Set)
Un ensemble est une collection, ventuellement vide, dobjets qui ont tous des valeurs diffrentes. Donc si deux objets a et b sont dans le mme ensemble, a.equals(b) est forcment faux. De mme, le pseudo-objet null peut se trouver au plus un fois dans un ensemble. Il ny a pas dordre des lments dans un ensemble, on ne peut donc pas parler du premier ou du quatorzime lment dun ensemble. Les principales mthodes de linterface Set sont les suivantes.
Mthode
add(Object e)
Dfinition Ajoute llment e lensemble. Retourne vrai si e a effectivement t ajout, faux sinon (par exemple, sil y avait dj un lment de mme valeur). Retire e de lensemble, cest--dire retire tout lment gal e. Retourne vrai si lensemble a effectivement t modifi, faux sinon. Retourne vrai si lensemble contient un lment gal e, faux sinon. Vrai si lensemble est vide. Nombre dlments de lensemble. Retourne vrai seulement si o est un ensemble et tous les lments de o sont contenus dans cet ensemble et tous les lments de cet ensemble sont contenus dans o. Ajoute tous les lments de c cet ensemble. Retire de cet ensemble tous les lments qui sont aussi dans c. Retire tous les lments sauf ceux qui sont aussi dans c. Vrai si lensemble contient tous les lments de c.
remove(Object e)
Il ne faut pas ngliger les quatre dernires mthodes de la liste ci-dessus car elles permettent deffectuer les oprations ensemblistes classiques : s1.addAll(s2) revient faire lunion s1 = s1 # s2; s1.retainAll(s2) revient faire lintersection s1 = s1 $ s2; s1.removeAll(s2) revient faire la diffrence s1 = s1 \ s2;
330
b = s1.containsAll(s2) teste linclusion s1 = s2 % s1; Remarquons quun ensemble ne stocke que des objets (Objects). Pour y ranger des valeurs de types simples (char, int, double, etc.), il est ncessaire de les envelopper dans lune des classes prvues cet effet : Character, Integer, Double, etc. (voir point 6.10, p. 95). Les deux implantations des ensembles fournies par le package java.util diffrent par leurs performances et lordre de stockage des lments. HashSet : une implantation par table de hachage1, lajout et le test dappartenance sont trs rapides (temps quasi constant). TreeSet : les lments sont placs dans un arbre de recherche binaire quilibr, lajout et le test dappartenance prennent un temps proportionnel au logarithme du nombre dlments (cest encore rapide); de manire interne, les lments sont maintenus tris selon leur ordre naturel (dfini par la mthode compare()), ce qui permettra, par exemple, de parcourir facilement les lments par ordre croissant (voir point 23.3 Itrateurs). Un exemple : le compteur de mots La programme suivant compte le nombre de mots diffrents contenus dans un fichier de texte. La mthode est simple, il suffit dajouter chaque mot lu un ensemble. Si le mot y est dj, il nest pas ajout une seconde fois. la fin, la taille de lensemble donne le nombre de mots diffrents.
import java.io.*; import java.util.*; class CompteDiff { public static void main(String[] args) { try { // initialisation du lecteur de mots (voir chap. Entrees/ Sorties) Reader r=new FileReader(args[0]); StreamTokenizer st=new StreamTokenizer (r); st.whitespaceChars('.','.') ; // le '.' est un sparateur Set mots = new HashSet(); while (st.nextToken()!=st.TT_EOF) { if (st.ttype== st.TT_WORD) { mots.add(st.sval); // st.sval contient le mot lu
1.
Dans une table de hachage, un objet est stock une position donne par une fonction de hachage applique la valeur de lobjet et qui fournit un entier compris entre 0 et la taille de la table - 1. On utilise la mme fonction pour retrouver la place dune paire stocke. Si deux objets doivent occuper la mme position, lun des deux est dplac selon une rgle de rsolution de collision . Tant quil y a peu de collisions, laccs aux donnes est extrmement rapide.
Les collections
331
} } r.close(); System.out.println("Nb. de mots fifferents: "+mots.size()); } catch (FileNotFoundException e) {System.out.println("Fichier non trouve");} catch (IOException e) {System.out.println("Erreur de lecture");} }}
Squences (List)
Une squence est une collection ordonne dobjets. Chaque objet possde une position dans la squence et plusieurs objets de mmes valeurs peuvent apparatre dans une squence, On voit dans la table ci-dessous que les mthodes dajout, de suppression, etc., demandent comme paramtre la position laquelle doit seffectuer lopration.
Mthode
add(int i, Object e) add(Object e) remove(int i) remove(Object e) clear() set(int i, Object e) contains(Object e) indexOf(Object e) lastIndexOf(Object e) get(int i) size() isEmpty() equals(Object o) addAll(Collection c)
Description Ajoute e la position i. Ajoute e la fin de la squence. Retire llment se trouvant la position i. Retire la premire occurrence de e dans la squence. Vide la squence de tous ses lments. Remplace llment la position i par e. Vrai si cette squence contient e. Retourne la position (int) de la premire occurrence de e dans la squence ou 1 sil ny est pas. Position de la dernire occurrence de e. Retourne lobjet plac la position i. Nombre dlments dans la squence. Vrai si la squence est vide. Vrai si o est une liste qui contient des lments gaux des positions identiques. Ajoute c la fin de la squence (concatnation).
332
Mthode
addAll(int i, Collection c) containsAll(Collection c) removeAll(Collection c) retainAll(Collection c) subList(int debut, int fin)
Les trois implantations offertes pour les listes se distinguent par leurs performances. ArrayList : la liste est maintenue dans un tableau, laccs un lment par sa position est trs rapide, par contre linsertion au dbut prend un temps proportionnel la taille de la liste. Cest en rgle gnrale un bon choix. LinkedList : la liste est forme de cellules lies par des rfrences, linsertion est rapide, par contre laccs un lment par sa position prend un temps proportionnel la position. Intressante essentiellement si lon fait de frquentes insertions au dbut et de nombreux parcours avec suppressions. Vector : cest la classe originellement fournie avec les premires versions de lAPI Java, elle est similaire ArrayList. La liste est stocke dans un tableau dont on peut contrler les paramtres dallocation. Cette classe est employe dans de nombreux programmes Java dvelopps pour lAPI 1.0 et 1.1. Les mthodes sont synchronises : deux processus concurrents ne peuvent accder simultanment au mme Vector.
Fonctions (Map)
Une fonction dun ensemble S vers un ensemble D est un ensemble de liens s ! d o s est un lment de S et d un lment de D. un objet de la source S peut correspondre au plus un seul objet de la destination D. Par contre, un mme objet peut tre la destination de plusieurs liens. On peut donc avoir les liens s1 ! d et s2 ! d dans la mme fonction, mais pas s ! d1 et s ! d2. Dans un lien s ! d, on appelle s la cl et d la valeur et on parle donc de paire cl-valeur. Comme dans le cas des ensembles, on a une implantation par hachage (HashMap) et une implantation par arbre (TreeMap). Pour pouvoir parcourir les cls en ordre croissant, il faut choisir le TreeMap. Le HashMap est plus rapide.
Les collections
Mthode
put(Object cle, Object val)
333
Description Ajoute la fonction le lien cle ! val. Retourne lancienne valeur associe cle ou null si cle ntait pas associe. Retire le lien de cl c, sil existe. Retourne lancienne valeur associe cle. Vide la fonction. Vrai si la fonction associe la cl c une valeur. Vrai sil existe une ou plusieurs cl(s) associe(s) la valeur v. Retourne la valeur (Object) lie la cl c dans cette fonction, ou null sil ny en a pas. Teste lgalit entre deux fonctions (mmes paires cl-valeur). Vrai si la fonction est vide. Ajoute toutes les paires cl-valeur de t cette fonction. Retourne le nombre de paires cl-valeur de cette fonction. Fournit un Set contenant lensemble des cls de cette fonction. Attention, cet ensemble partage ses lments avec la fonction! Fournit une collection contenant les valeurs de cette fonction.
remove(Object c) clear() containsKey(Object c) containsValue(Object v) get(Object c) equals(Object o) isEmpty() putAll(Map t) size() keySet()
values()
la fin du paragraphe 23.3 sur les itrateurs, nous prsenterons un exemple complet utilisant les fonctions. Une remarque de modlisation : fonctions et encapsulation des liens Les fonctions permettent dtablir des liens entre objets sans briser lencapsulation, cest--dire sans toucher la structure interne des classes concernes. Supposons que lon dsire tablir des liens entre des objets de la classe Avion et de la classe Aroport pour indiquer laroport o seffectue lentretien de chaque avion. La premire manire de procder, que nous avons vue au point 21.6, consiste ajouter une variable dinstance entretien de type Aeroport dans la classe Avion. Ce qui nous oblige modifier la classe Avion.
334
Les fonctions nous offrent une autre solution qui consiste crer une fonction entretien sous forme dune Map pour stocker des liens (avion ! aroport). La classe Avion reste alors indpendante de la fonction entretien.
Map entretien = new HashMap(); Avion hb56 = ... ; Aeroport gva = ...; entretien.put(hb56, gva); // associe hb56 gva.
Fonctions et multiensembles Un multiensemble correspond un ensemble o un mme lment pourrait apparatre plusieurs fois; on parle alors du nombre doccurrences dun lment. En fait, un multiensemble est une fonction qui associe chaque cl un nombre entier qui reprsente son nombre doccurrences. On peut donc facilement raliser une classe MultiEnsemble laide de Map.
Itrateurs (Iterator)
335
Remarque Jusqu la version 1.1, lAPI Java offrait la classe Enumeration, munie des mthodes hasMoreElements() et nextElement() comme mcanismes ditration. Il est dsormais prfrable dutiliser Iterator qui permet de retirer des lments en cours de route. Un exemple : lindexation dun texte Ce petit programme lit un texte et cre un index qui contient, pour chaque mot, la liste des numros de lignes o il apparat.
import java.io.*; import java.util.*; class Indexeur { public static void main(String[] args) { try { Reader r=new FileReader(args[0]); StreamTokenizer st=new StreamTokenizer (r); st.whitespaceChars('.','.') ; st.eolIsSignificant(true); // reconnait les fins de ligne Map index = new TreeMap(); // fonctions avec cls ordonnes int noLigne = 1; while (st.nextToken()!=st.TT_EOF) { if (st.ttype == st.TT_EOL) noLigne++; // fin de ligne if (st.ttype== st.TT_WORD) { // mot List lignes = (List)index.get(st.sval); if (lignes == null) { // premiere fois qu'on trouve ce mot lignes = new ArrayList(); // une liste vide index.put(st.sval, lignes); // lui est associee } lignes.add(new Integer(noLigne)); } } // while r.close(); // Parcours de toutes les cles de la fonction Iterator i = index.keySet().iterator(); while (i.hasNext()) { Object mot = i.next(); System.out.print((String)mot); List lignes = (List)index.get(mot); // Parcours de la liste des nos de lignes Iterator j = lignes.iterator(); while (j.hasNext()) { int ligne = ( (Integer)j.next() ).intValue(); System.out.print(" " + ligne); }
336
System.out.println(); }
Dans ce programme, on utilise une fonction (index) qui associe chaque mot lu une liste contenant les numros des lignes o apparat le mot. Cest donc une structure de collection deux niveaux. Pour imprimer lindex, on parcourt avec litrateur i lensemble des cls de la fonction (obtenu par keySet()) et, pour chaque cl, on parcourt avec litrateur j la liste qui lui est associe. Lexcution de ce programme avec son propre texte source comme fichier de donnes produit :
ArrayList 21 EOF 16 EOL 17 FileNotFoundException 46 FileReader 8 IOException 47 Indexeur 4 Integer 24 39 Iterator 30 37 List 19 19 34 34 Map 13 etc.
Deux fractions sont gales si leur numrateur et leur dnominateur le sont, mais ce nest pas tout. Tout le monde sait que 1/2 = 2/4 = 3/6, etc. Deux fractions sont gales si les multiplications croises {numrateur de a * dnominateur de
337
b} et {numrateur de b * dnominateur de a} donnent le mme rsultat. Il faut donc crire une mthode equals() spcifique pour les fractions :
public boolean equals(Fraction f) { return (this.numerateur * f.denominateur == this.denominateur * f.numerateur); }
Dans le cas o les variables dinstance des objets comparer ne contiennent pas des valeurs primitives (int, long, float, etc.), la mthode equals doit en tenir compte et dcider dappliquer soit le test didentit (==), soit le test dgalit (equals) sur celles-ci. Prenons par exemple une classe ListeRect dont chaque objet a pour but de grer un ensemble de rectangles stocks dans un tableau :
class ListeRect { private Rectangle[] lesRectangles; private int nbRectangles;
338
transitive : si a.equals(b) et b.equals(c) donnent true, alors a.equals(c) doit aussi donner true.
Copie dobjets
La copie dobjets soulve le mme genre de questions que lgalit. En effet, loprateur = neffectue aucune copie dobjet. Par exemple, si lon a :
r1 = new Rectangle(0, 0, 10, 15);
lopration : ne cre pas une nouvelle instance de Rectangle mais place dans r2 une rfrence lobjet rfrenc par r1. Aprs cette opration, r1 == r2 vaut true. Le but dune opration de copie est de crer un nouvel objet qui soit gal (au sens de equals()) lobjet de dpart. Dans le jargon Java, on parle dopration de clonage. On veut donc une opration clone() telle quaprs linstruction :
r2 = r1.clone() r2 = r1;
on ait r2 != r1 mais r2.equals(r1). De mme que pour lgalit, on peut dfinir des oprations de clonage de surface ou de clonage profond. Si lon reprend la classe ListeRect, une copie de surface de la ListeRect a consiste crer un nouvel objet b qui contient son propre tableau lesRectangles, et faire :
for (i=0; i<nbRectangles; i++) {b.lesRectangles[i] = a.lesRectangles[i]; }
On ne cre pas de nouveaux rectangles, la nouvelle liste fait rfrence aux rectangles de la prcdente liste. Pour une copie en profondeur, on crera au contraire un nouvel exemplaire de chaque rectangle :
for (i=0; i<nbRectangles; i++) {b.lesRectangles[i] = a.lesRectangles[i].clone(); }
Lopration de clonage doit tre trs clairement dcrite pour viter toute mauvaise interprtation par les futurs utilisateurs de la classe (ou par lauteur qui ne sait plus trs bien ce quil a fait il y a six mois). On notera en particulier que le clonage de surface introduit un partage dobjets, cest--dire que deux objets ListeRect font rfrence aux mmes objets Rectangle. Donc, si lon modifie lun de ces Rectangle, la modification apparat dans les deux ListeRect; nouveau, cela peut tre considr comme un avantage ou un inconvnient mais il faut en tre conscient.
Invitation explorer
339
Chapitre 24
Composition du logiciel
Bien que la notion de classe permette de construire une application de manire modulaire, elle nest plus suffisante lorsquon se trouve face des applications de grande taille (ce que les anglophones nomment programming in the large). Cest pour cette raison que certains langages et mthodes orients objet proposent de regrouper les classes dans des structures de plus haut niveau. Le langage Java offre dans ce but la notion de package. Nous verrons galement dans ce chapitre comment dfinir laccessibilit aux objets dans des projets impliquant plusieurs packages. Si les packages constituent un outil de structuration du logiciel, les Java Beans ouvrent, quant eux, la possibilit de construire du logiciel par composition dobjets. Nous verrons pour terminer le mcanisme dintrospection ncessaire au dveloppement des Java Beans.
Une classe ne peut appartenir qu un seul package. Certains environnements de dveloppement Java exigent que tous les fichiers de code source et de byte-code des classes dun package se trouvent dans le mme
342
rpertoire du systme de fichier, ce rpertoire portant ncessairement le mme nom que le package. Les packages peuvent eux-mmes tre organiss hirarchiquement, il faut alors utiliser une notation pointe pour nommer chaque package. Un nom de la forme :
packA.packB
spcifie un sous-package de packA qui se nomme packA.packB. Les classes de ce package doivent alors tre places dans un sous-rpertoire de packA nomm packB. Si aucun package nest dclar en dbut de fichier, les classes dfinies dans ce fichier appartiennent un package anonyme. Ces classes ne sont importables dans aucun autre package. Il sagit dune facilit de test pour de petits programmes, qui doit tre abandonne ds quil faut aborder un dveloppement consquent.
343
Une classe non publique est donc encapsule dans son package, ce qui permet de ne montrer lextrieur du package que les classes que lon dsire mettre disposition des autres. Les classes non publiques sont en gnral des classes auxiliaires qui ne prsentent pas dintrt pour lutilisateur du package, mais qui sont techniquement ncessaires sa ralisation. Le mot rserv public, plac devant la dfinition dune classe, indique que celleci est publique, sinon elle est usage interne du package. Pour utiliser une classe C dun package p depuis un autre package, il faut : soit prfixer son nom par celui du package (p.C) chaque rfrence; soit importer la classe (import p.C), ce qui permet de nutiliser que le nom C par la suite. Notons que lon peut importer dun coup toutes les classes dun package p en faisant import p.*
344
S ou une sous-classe de S ou si e est la pseudovariable super. En dautres termes, S ne peut accder au membre m dobjets qui sont de type C mais pas de type S. Nous prsentons ci-dessous quelques cas dutilisation des modificateurs daccessibilit. Transparence des objets Un membre priv nest visible qu lintrieur de sa classe. Cela correspond lencapsulation la plus forte en Java. Notons cependant que les objets dune mme classe sont compltement transparents les uns par rapport aux autres. Une mthode peut donc accder aux membres privs de this mais aussi aux membres privs de tout objet de la mme classe que this (cette possibilit surprendra les habitus de Smalltalk) :
class Piece { private String type; boolean memeType(Piece p) { // accs une variable prive d'un autre objet Piece return p.type == this.type; } ... }
Hritage des variables prives Le modificateur private, plac devant une variable, rend celle-ci inaccessible dans les sous-classes, bien quelle soit hrite. Ainsi, lorsquune mthode dune sous-classe veut modifier une variable hrite mais inaccessible, elle doit forcment faire appel une mthode de modification de la super-classe, comme dans lexemple ci-dessous :
package p1; class Piece { private String type; int noSerie; void defType(String s) {type = s;} void defSerie(int i) {noSerie = i;} } class PieceSimple extends Piece{ void uneMethode() { // acces a la var. heritee travers une mthode de Piece: // this.type = "vis" causerait une erreur ! this.defType("vis"); // accs une variable hrite visible noSerie = 455848; } }
345
Modificateur protected Cet exemple illustre la rgle particulire demploi des variables protges :
package p1; public class Piece { protected int cout; ... } package p2; import p1.Piece; class PieceSimple extends Piece{ ... void uneMethode(Piece p) { PieceSimple ps = new PieceSimple(); this.cout = 345; // accs autoris // p.cout = 456; // accs interdit car p est de type Piece qui // pas une sous-classe de PieceSimple ps.cout = 765; // accs autoris } }
nest
Accessibilit et redfinition
Si une classe qui hrite dune mthode m() la redfinit, en donnant donc le mme nom et les mmes types de paramtres une nouvelle mthode, la mthode redfinie doit tre au moins aussi accessible que la mthode hrite. Cette rgle garantit quun objet dune sous-classe sait faire tout ce que sait faire un objet de sa super-classe. Si ce ntait pas le cas, on ne pourrait plus considrer quune sous-classe tend sa super-classe; on perdrait alors la proprit selon laquelle partout o un objet dune classe est requis, on peut le remplacer par un objet dune de ses sous-classes. Le compilateur ne pourrait plus faire de contrle statique des types des expressions, et des erreurs dexcution pourraient sensuivre.
346
plus les variables dune classe sont caches, plus celle-ci est indpendante des autres et donc facile maintenir; plus le projet sur lequel on travaille est grand, plus les choix de visibilit portent consquence. LAPI Java constitue un exemple extrme car pratiquement tout programme Java crit quelque part dans le monde utilise les classes de lAPI; lextension de la visibilit dune variable peut parfois viter dcrire plusieurs mthodes qui ne servent qu accder aux variables des objets; si la visibilit est limite au package, on na pas craindre quun grand nombre de classes se mette accder la variable; il nest pas toujours vrai que laccs direct aux variables est plus rapide que le passage par une mthode daccs, car les compilateurs modernes peuvent trs bien optimiser ces mthodes (par exemple, par expansion directe du code). De plus, les compilateurs peuvent tenir compte du modificateur final qui empche la redfinition dune mthode, ce qui vite de passer par le mcanisme de liaison dynamique lors des appels. En ce qui concerne les mthodes, on peut noter deux cas o il parat judicieux de limiter la visibilit : il peut tre utile de cacher des mthodes auxiliaires qui ont un usage interne important mais noffrent pas de service intressant aux autres classes. De cette manire, on allge linterface de la classe et on en facilite la rutilisation par dautres concepteurs; dans le mme ordre dide, on vitera galement de rendre publiques des mthodes dont leffet peut savrer dsastreux si elles ne sont pas utilises selon des rgles bien prcises, en gnral connues du dveloppeur seul.
347
virtuelle Java. Les applets sont fournies lutilisateur en fonction des tches quil veut effectuer. DCOM Larchitecture de composants distribus dfinie par MicroSoft permet dcrire des composants logiciels capables de communiquer avec dautres composants DCOM pour sintgrer dans un systme distribu. AppleScript Ce langage de haut niveau permet dinvoquer des services de diffrentes applications (tableurs, traitements de texte, bases de donnes, etc.) pour crire une macro-application . Des ensembles de services standards sont rpertoris dans des dictionnaires.
348
classes de Beans
Les vnements
Le modle dvnements dcrit au chapitre 13 est une composante essentielle de larchitecture Java Beans, car cest le support de la communication entre Beans. Un Bean communique avec dautres Beans, qui se sont inscrits comme couteurs, en leur envoyant des vnements. Rappelons brivement comment fonctionne ce modle. Pour quun Bean puisse produire des vnements de type T il faut : dfinir une classe TEvent qui contiendra la mmoire de lvnement, cest--dire les donnes transmettre aux couteurs; dfinir une interface dcoute TListener qui spcifie quelles mthodes les couteurs doivent implanter. Ces mthodes ont en gnral un seul paramtre de type TEvent; dfinir dans la classe du Bean une mthode dinscription et une mthode de retrait dcouteurs : public void addTListener(TListener ecouteur) public void removeTListener(TListener ecouteur) ; ventuellement dfinir une classe dadaptateurs TAdapter qui implante TListener.
349
Pour transmettre un vnement, le Bean source parcourt la liste de tous les couteurs inscrits et invoque pour chacun deux lune des mthodes de linterface TListener.
Bean cr configuration - proprits - vnements Bean configur
Bean srialis
utilisation
Bean prt
dsrialisation
Les proprits
Une proprit est un attribut dun Bean qui est identifie par un nom et possde une valeur dun type quelconque. Par exemple, un Bean reprsentant un vlo pourra avoir une proprit poids de type double. Pour quune proprit de nom P soit reconnue comme telle, le Bean doit possder une mthode daccs getP() et une mthode daffectation setP(). Notre vlo aura donc une mthode getPoids() qui retourne un double et une mthode setPoids(double valeur). Une proprit peut tre indexe, dans ce cas sa valeur est un tableau de valeurs. Les mthodes getP() et setP() ont alors un paramtre supplmentaire qui est lindice dans le tableau. Par exemple, si la proprit couleur est indexe on crira :
Couleur couleurPrincipale = monVelo.getCouleur(0); monVelo.setCouleur(1, couleurSecondaire);
Un Bean peut galement avoir des proprits lies, ce qui signifie que tout changement de valeur doit tre signal dautres objets. Lors dun changement de valeur, le Bean doit crer un vnement de type PropertyChangeEvent et le transmettre tous les objets inscrits en appelant leur mthode property-
350
Change(). La classe PropertyChangeSupport aide grer les inscriptions et transmissions de tels vnements. Une proprit peut tre lie encore plus fortement dautres objets, on dit alors que la proprit est contrainte. Dans ce cas, le Bean signale aux abonns quil veut changer la valeur de la proprit et leur permet de sopposer au changement. En cas dopposition, un abonn lance une exception de type PropertyVetoException lorsque le bean appelle sa mthode vetoableChange(). Si le Bean reoit une telle exception, il doit renvoyer un vnement pour dfaire le changement, sinon il envoie un vnement de changement normal pour confirmer le changement tous les abonns. Il sagit donc dun protocole deux phases. Les conventions de dnomination stricte des mthodes lies aux proprits et aux vnement sont l pour permettre aux outils de dveloppement de reconnatre les proprits et vnements dun Bean. On remarquera que les classes de lAWT, de mme que celles de Swing respectent toutes les conventions dcriture des Beans. Les objets de ces classes sont donc des Beans, ce qui permet de les utiliser dans les outils de dveloppement dinterfaces graphiques.
24.4 Introspection
Mais comment un outil de dveloppement peut-il connatre les mthodes offertes par une classe sans lire le code source de celle-ci? Cest prcisment pour rpondre cette question qua t introduite lintrospection en Java. Lintrospection permet un systme de se regarder lui-mme pendant quil fonctionne. En Java, les objets de la classe Class reprsentent les classes du systme et les objets de la classe Method (dans le package java.lang.reflect) reprsentent les mthodes. Voici quelques exemples dintrospection : rechercher une classe daprs son nom
Class classeBouton = Class.forName("Bouton");
Sil existe dans la classe Bouton une mthode efface avec un paramtre de type Rectangle, on linvoque sur lobjet monBouton.
// cre le tableau des types de paramtres Class [] typesParam = { Class.forName("Rectangle") }
Introspection
351
// cre le tableau des types de paramtres Class [] typesParam = { Class.forName("java.awt.Rectangle") }; Method efface = classeBouton.getDeclaredMethod("efface", typesParam); // prpare les parametres effectifs Object[] valParam = {new Rectangle(1,1,100,191)}; efface.invoke(monBouton, valParam);
Ces exemples montrent quon peut non seulement connatre les mthodes dune classe et leurs paramtres, mais que lintrospection nous autorise crer des objets (newInstance()) et invoquer des mthodes (invoke()). Cest exactement ce que fait un outil de dveloppement interactif avec les Beans.
Chapitre 25
Processus et concurrence
La machine virtuelle Java permet lexcution concurrente de plusieurs processus dans un programme. Un processus Java est un objet auquel est associ un fil dexcution (thread) qui possde : un tat actif ou inactif, ltat actif tant subdivis en : prt lexcution, en excution, et en attente; un nom (une chane de caractres pas forcment unique); un contexte dexcution (instruction courante, pile de mmorisation des appels de mthodes, etc.). Les deux possibilits consistant crer des processus sont soit dfinir une sousclasse de Thread qui redfinit la mthode run(), soit crer un objet de Thread en donnant comme paramtre un objet de type Runnable (qui possde une mthode run()). La mthode start() initialise le processus et passe le contrle la mthode run() du processus ou de lobjet pass comme argument au constructeur du processus. Le processus sarrte lorsquil sort de la mthode run(). Diffrentes mthodes permettent de contrler et de synchroniser les processus : stop(), suspend(), resume(), sleep(), yield() (passe le contrle un autre processus en attente), join() (attend la fin dun processus). Par dfaut, une application Java ne contient quun seul processus qui est implicitement mis en marche au lancement de lapplication et qui appelle la mthode main().
354
Une applet simple est contrle par un processus du butineur qui appelle les mthodes init(), start(), stop(), repaint(), etc., suivant les besoins.
aprs que A ait test a[1] != 0 mais avant quil ait eu le temps de faire b/a[1], alors une erreur de division par 0 se produira dans A, malgr le test qui prcde. Une manire dviter ce type de problme consiste garantir laccs exclusif un objet pendant lexcution dune ou plusieurs instructions.
La synchronisation en Java
355
Pour que les instructions de lexemple prcdent fonctionnent correctement, il aurait fallu crire :
synchronized (a) if (a[1] != 0) { ...; c = b/a[1]; ... }
dans le processus A et :
synchronized (a) a[1] = 0;
dans B. La technique des moniteurs introduit un raffinement supplmentaire dans la synchronisation. Lorsquun processus possde laccs un objet, il peut appeler la mthode wait() de lobjet pour se mettre en attente et librer lobjet. Pour le sortir de cette attente, il faut quun autre processus excute un notify() sur cet objet et que lui-mme obtienne nouveau laccs exclusif lobjet. Les mthodes wait() et notify() existent pour tout objet (elles sont hrites de Object); elles ne peuvent tre appeles que lorsque le processus possde un accs exclusif lobjet. noter que lexcution de notify() ne libre pas lobjet. Lexemple suivant illustre leur utilisation; il sagit dun cas classique de producteur-consommateur. Un processus producteur produit des donnes (de simples entiers dans notre cas) et les place dans une file dattente. Un consommateur prend ce quil trouve dans la file. La file est ici limite un lment. Chaque objet de la classe Produit est une file dattente qui, pour simplifier, peut contenir 0 ou 1 lment entier (contenu). On peut ajouter ou retirer un lment et tester si la file est vide.
class Produit { int contenu; boolean vide; Produit() {vide = true;} void ajoute(int x) {contenu = x; vide = false;} int retire() {vide = true; return contenu;} boolean estVide() {return vide;} }
Lorsque la file est pleine, le processus producteur doit attendre que le processus consommateur la vide. Quand il a mis un nombre dans la file, il le signale afin de redmarrer le consommateur qui serait en attente.
class Producteur extends Thread { Produit produit; Producteur(Produit p) {this.produit = p;} public void run() { int ip; while (true) { ... synchronized (produit) { if (!produit.estVide()) { try produit.wait();
356
catch (InterruptedException e); } ip = (int)(Math.random() * 1000); // produit un nb. alatoire produit.ajoute(ip); // signale quil y a qqch prendre produit.notify(); } } }}
Un consommateur prend ce quil y a dans la file de produits et laffiche; lorsquil ny a rien, il se met en attente. Lorsquil a vid la file, il le signale afin de dbloquer le processus producteur sil tait en attente.
class Consommateur extends Thread { Produit produit; Consommateur (Produit p) {this.produit = p;} public void run() { int jp; while (true) { synchronized (produit) { if (produit.estVide()) { try produit.wait(); catch (InterruptedException e); } jp = produit.retire(); produit.notify(); System.out.println(jp); } } }}
La figure 25.1 ci-aprs illustre le fonctionnement de synchronized, wait() et notify() dans le cas o le consommateur trouve la file vide. Cette solution fonctionne mais nest pas entirement satisfaisante du point de vue du design de lapplication. En effet, rien noblige passer par une instruction synchronized pour accder produit. Un processus sauvage dont le dveloppeur ne serait pas bien inform de la nature partage de produit pourrait y accder sans contrle et semer le trouble. Pour obtenir un mcanisme nettement plus sr, il faut se souvenir des principes de la programmation oriente objet et
La synchronisation en Java
consommateur synchronized (produit) synchronized (produit) wait producteur
357
appliquer lencapsulation. Redfinissons ainsi notre classe Produit pour la rendre sre par rapport aux processus :
class Produit { int contenu; boolean vide; Produit() {vide = true;} synchronized void ajoute(int x) { while (!vide) { try wait(); catch (InterruptedException e);} contenu = x; vide = false; notify(); } synchronized int retire() { while (vide) { try wait(); catch (InterruptedException e);} vide = true; notify(); return contenu; } synchronized boolean estVide() {return vide;} }
358
Dsormais, laccs un objet produit de la classe Produit passe obligatoirement par des mthodes synchronises, les mthodes utilisatrices de Produit nont plus se soucier de faire des synchronized. On peut rcrire le producteur beaucoup plus simplement :
class Producteur extends Thread { Produit produit; Producteur(Produit p) {this.produit = p;} public void run() { int ip; while (true) { try {sleep((int)(Math.random() * 1000));} catch (InterruptedException e) {}; ip = (int)(Math.random() * 1000); produit.ajoute(ip); } }}
25.3 .Interblocages
Laccs exclusif aux objets offre des garanties quant lintgrit des donnes et la consistance des traitements. Par contre, il introduit des dpendances entre processus du type : un processus A attend que B ait libr un objet O. Lorsque la chane des dpendances devient cyclique, il y a interblocage des processus. Par exemple, si A a obtenu laccs o1 et attend laccs o2 et B a obtenu laccs o2 et attend laccs o1. Les deux processus sont en attente : A attend sur B et B attend sur A, il y a interblocage. Seule une tude rigoureuse de la dynamique des processus, et en particulier des dpendances possibles, peut prvenir ce genre de problme. Il existe pour cela des techniques formelles comme la modlisation par rseaux de Petri.
Chapitre 26
1.
Par contre, le nombre de balises destines uniquement rgler lapparence des documents (fontes, centrage, bordures, etc.) va sans doute augmenter sous la pression des utilisateurs commerciaux du World-Wide Web.
360
et le lecteur verra apparatre la situation sous forme de dessin. Mieux encore, il pourrait exister une applet AnimePartie.class capable de visualiser une partie coup par coup, davancer, de reculer, etc. Cette fois, le paramtre serait une chane de caractres dcrivant une partie selon lune des notations standard des checs. Lutilisation de cette applet ferait du document un document dynamique et interactif. Les applets Java nous permettent donc de grer des types de contenus qui ne sont pas prvus dans HTML (parties dchecs, molcules chimiques, pices mcaniques, etc.).
361
Parmi les applets de dmonstration fournies par Sun dans le JDK, se trouve une applet de dessin dynamique de graphe. Un graphe est dcrit par un paramtre edges, squence dartes de la forme nomNoeud1nomNoeud2 spares par des virgules. Ci-dessous se trouve lexemple dinclusion dun tel graphe dans un document :
<applet code="Graph.class" width=400 height=400> <param name=edges value="a1-a2,a2-a3,a3-a4,a4-a5,a5-a6,b1-b2,b2b3,b3-b4,b4-b5,b5-b6,c1-c2,c2-c3,c3-c4,c4-c5,c5-c6,x-a1,x-b1,xc1,x-a6,x-b6,x-c6"> </applet>
N.B. Le livre que vous tes en train de lire ntant pas dynamique, nous avons d procder une copie dcran. Les outils fournis par Java pour traiter les paramtres Nous avons dj vu plusieurs reprises lutilisation de la mthode getParameter() de la classe Applet (voir lapplet du serpent, p. 303) qui fournit le String donn comme valeur dun paramtre dans une balise <APPLET>. Dautres mthodes et classes sont galement de premire utilit :
362
les mthodes de conversion de la classe String vers les types numriques que lon trouve dans les classes Float, Integer, Long et Double; la classe StringTokenizer qui analyse un String, unit syntaxique (token) par unit syntaxique. Cette dernire classe dfinit un itrateur qui parcourt la chane en fournissant un mot chaque appel la mthode nextToken().
String partie = getParameter("PARTIE"); StringTokenizer st = new StringTokenizer(partie, " "); while (st.hasMoreTokens()) { String unCoup = st.nextToken(); ... }
Le second paramtre du constructeur de StringTokenizer est une chane qui dtermine la liste des caractres utiliss comme sparateurs de mots, dans notre cas lespace.
Chapitre 27
Scurit en Java
Sun Microsystems a conu Java en y incorporant ds le dpart des critres de scurit. La scurit est un concept qui doit tre trait a priori et non a posteriori. Cette prise en compte de la scurit ds la conception est perceptible dans les diffrents choix qui ont t faits (absence de pointeur, vrification de types, gnration de byte-code, etc.). Ces choix amnent dautres aspects positifs : robustesse et portabilit des programmes, mais ils sont surtout ncessaires pour implanter le niveau de scurit vis. Nous avons dj expliqu pourquoi un tel niveau de scurit est requis. Rappelons quavec la gnralisation des butineurs ayant la capacit dexcuter du Java, il est possible de tlcharger des programmes depuis nimporte quel point du rseau Internet. Vous avez constat que la programmation en Java nest pas si complique et nous esprons que vous avez dj programm quelques applets, peuttre mme en avez-vous ajout une votre page personnelle. Si la scurit de Java nexistait pas, il vous serait possible dcrire une applet qui tablit une liste de tous les fichiers .EXE dun disque et qui la poste x@y.com, ou bien encore de vous procurer un virus connu ou inconnu pour linstaller sur un disque, etc. Sans la scurit de Java, personne ne voudrait prendre le risque de tlcharger et dexcuter des applets. Nous dveloppons ce chapitre sur la scurit pour contribuer, nous lesprons, une meilleure comprhension des mcanismes sous-jacents. Ceux-ci doivent tre publis (et comprhensibles), dune part pour quils soient crdibles et dautre part pour quils soient prouvs : sils sont vraiment srs, alors leurs concepteurs peuvent les publier sans crainte. Cette dmarche, utilise pour Java, a
364
dj permis de dcouvrir quelques faiblesses, non pas dans les principes mais dans le code de la machine virtuelle Java. Larchitecture Java comporte quatre niveaux de scurit : 1. Le langage et le compilateur. 2. Le vrificateur de byte-code. 3. Le chargeur de classes. 4. La protection des fichiers et des accs au rseau.
1.
Ce dernier point est assez difficile liminer. En effet, la nuisance est dans le comportement du programme, qui peut calculer sans interruption, tre bruyant, ouvrir des fentres, lancer des processus. Il existe la fois des programmes utiles et des programmes hostiles ayant un tel comportement. Nanmoins, de tels programmes hostiles ne peuvent que nuire temporairement, leurs auteurs risquant dtre rapidement ensevelis sous une avalanche de courrier lectronique.
Le vrificateur de byte-code
365
la vrification stricte des types nautorise pas la conversion implicite des types. Les droits daccs aux mthodes et aux variables sont vrifis la compilation pour dterminer sils sont en accord avec les spcifications de visibilit (protected, private, etc.). Les entiers ne peuvent pas tre convertis en objets et rciproquement. Le code Java de linterprteur et du compilateur sont disponibles, ainsi que la spcification du langage. Ainsi, chacun peut thoriquement vrifier que le code est bien conforme la spcification.
366
fonction de retour; manipulation des champs dun objet; invocation de mthode; cration dun objet; conversion de type (casting). Les instructions sont ventuellement suivies par des arguments sur leurs oprandes. Lespace mmoire de la machine est rparti en diffrentes zones : une zone mmoire o seront crs les objets; une zone de constantes htrognes (pool); une zone de description pour le byte-code; une zone dactivation pour chaque mthode comprenant une pile et des registres locaux.
Le vrificateur de byte-code
367
Le fichier lu, on vrifie son nombre magique (pour sassurer que la transmission est correcte), ensuite on vrifie le format du fichier (attribut et longueur des attributs). Le fichier doit tre complet, sans ajout ni limination. La structure de la zone de constantes doit tre correcte.
Tester la vraisemblance
La deuxime tape va tester la vraisemblance des structures et des rfrences dans la zone de constantes. Les vrifications suivantes sont effectues : la structure des classes finales nest pas tendue (idem pour les mthodes finales); toutes les classes ont une super-classe; toutes les rfrences des champs et des mthodes ont des noms bien forms et des signatures lgales dans la zone de constantes. Dans cette tape, on ne cherche pas savoir si les noms existent vraiment, mais seulement si la forme des noms est correcte.
Prouver la description
Cette tape est dcisive. Il sagit de vrifier pour chaque mthode que son modle dexcution est correct. Ce modle est le suivant : chaque point du programme, on peut associer un tat de la pile (longueur et type des lments); cet tat est indpendant des possibilits dexcution qui prcdent ce point; les registres locaux ne sont pas accds avant davoir reu une valeur (de type compatible); les mthodes sont invoques avec des arguments corrects; les champs des objets sont modifis avec des valeurs spcifies par leur type; les bytes-codes ont des arguments corrects (par rapport aux registres locaux, la pile et la zone de constantes). Concentrons-nous sur la premire contrainte : elle ncessite de construire un modle dexcution de la classe simulant les diffrentes possibilits, afin de vrifier que chaque chemin mnera bien au mme tat. On va ainsi transformer les bytes-codes en flux de donnes. Les bytes-codes vont tre regroups en squences dinstructions. Chaque instruction doit comporter un dbut et une fin; quitter linstruction au milieu est interdit, se brancher au milieu galement. Chaque instruction va tre vrifie (accs aux registres locaux, rfrences la zone des constantes). chaque instruction va tre associe une prcondition qui mmorise ltat de la pile et lutilisation des registres locaux en termes de types.
368
Les bytes-codes de la machine virtuelle sont conus de manire ce que ltat de la pile soit entirement dtermin par le type des oprandes et le code excuter. Ltat de la pile nest donc pas conditionn par les valeurs (mais seulement par les types). Lanalyse du flux de donnes ne prendra en compte que les types des objets. La premire instruction de la mthode est initialise avec une pile vide, les registres locaux contenant les types indiqus par la signature de la mthode. Cette instruction est marque vrifier. Lalgorithme de lanalyseur est conceptuellement le suivant : 1. Chercher une instruction marque vrifier . Sil ny en a plus, la mthode est vrifie. 2. Simuler leffet de linstruction sur la pile et sur les registres : a) en vrifiant quil ny a pas de dpassement des dimensions de la pile (underflow et overflow) par rapport la taille maximum indique pour la mthode; b) en vrifiant la conformit des types utiliss sur la pile; c) en vrifiant que les registres utiliss soient initialiss et accessibles la mthode (nombre maximum de registres). la fin du point 2, on a dtermin un nouvel tat de la pile et des registres. 3. Dterminer la prochaine instruction excuter, qui peut tre soit : a) la prochaine instruction; b) les branches dune instruction conditionnelle; c) un retour ou une mission dexception. 4. Dterminer ltat de la pile pour les instructions suivantes : a) si la nouvelle instruction est visite pour la premire fois, on initialise cet tat avec celui obtenu en 2); b) sil existe dj un tat, il faut fusionner les deux tats. Les piles doivent tre de taille gale. Les types doivent tre gaux. Dans le cas de conflit entre deux classes, on choisit lanctre commun le plus proche. Pour fusionner les registres, on vrifie la compatibilit des types; en cas dincompatibilit, le registre prend ltat indfini. Si la prcondition de linstruction suivante est modifie, elle est marque comme vrifier; la marque de linstruction examine est efface, on recommence au point 1. Toute anomalie survenant pendant la vrification provoque labandon de la vrification avec un statut ngatif.
Le vrificateur de byte-code
369
Nous prsentons des exemples qui montrent bien le principe de cette vrification (nous restons ici au niveau du compilateur qui utilise des mcanismes similaires). Soit deux classes O1 et O2 :
class O1 { int f1() {return 1;} } class O2 { int f2() {return 2;} }
Le programme suivant (Securite1) tente de construire un tat ambigu lissue de la premire condition : soit o1 est cr, soit o2 est cr. La deuxime condition risque dutiliser une variable non initialise. Le compilateur ne peut accepter cette ambigut et la signale.
// Classe refuse la compilation: class Securite1 { public static void main (String args[]) { int i=1; O1 o1; O2 o2; if (i==1) o1=new O1(); else o2=new O2(); if (i==1) System.out.println(o1.f1()); // variable o1 peut ne pas tre initialise else System.out.println(o2.f2()); // variable o2 peut ne pas tre initialise } }
On peut rcrire ce programme dune autre manire (Securite2). Le compilateur laccepte, car la vrification des conversions de type allant du gnral au particulier est repousse lexcution. Ces conversions doivent donc tre utilises avec prudence car elles peuvent tre source derreurs lexcution.
// Classe accepte la compilation pouvant gnrer une erreur // lexcution class Securite2 { public static void main (String args[]) { int i=1; Object o; if (i==1) o=new O1(); else o=new O2(); if (i==1) System.out.println(((O1)o).f1()); else System.out.println(((O2)o).f2()); } }
370
Pour ceux qui croient encore que lon peut sen passer, voici un dernier exemple de programme montrant que les vrifications statique et dynamique des types sont une affaire dordinateurs.
class O1 { int f1() {return 1;} O1 f(O2 o) {return new O2 f(O1 o) {return new } class O2 { int f2() {return 2;} O1 f(O2 o) {return new O2 f(O1 o) {return new } O1();} O2();}
O1();} O2();}
class Securite { public static void main (String args[]) { int i=1; O2 o2=new O2(); //oui lexpression est bien un O1! O1 o1=o2.f(o2).f(o2.f(o2)).f(o2).f(o2.f(o2).f(o2.f(o2)). f(o2)).f(o2.f(o2).f(o2.f(o2)).f(o2)).f(o2).f(o2.f(o2). f(o2.f(o2)).f(o2).f(o2.f(o2).f(o2.f(o2)).f(o2)). f(o2.f(o2).f(o2.f(o2)).f(o2)).f(o2)).f(o2.f(o2). f(o2.f(o2)).f(o2).f(o2.f(o2).f(o2.f(o2)).f(o2)). f(o2.f(o2).f(o2.f(o2)).f(o2)).f(o2)).f(o2); System.out.println(o1.f1()); } }
Optimiser lexcution
En cas de succs, le vrificateur effectue un dernier passage sur le code pour remplacer certaines instructions par leur version rapide (_quick). Par exemple, les codes new, invokestatic, anewarray, etc., sont remplacs par new_quick, invokestatic_quick, anewarray_quick, etc. partir de ce moment, pour excuter le byte-code, on peut utiliser : un simple interprteur de byte-code : les instructions sont interprtes chaque excution; un interprteur associ un compilateur la vole : les instructions sont compiles (code natif de la machine cliente) lors de leur premire excution et ce code est excut lors des excutions ultrieures; un compilateur de byte-code crant du code natif; et bientt sans doute un processeur Java (projet de Sun Microsystems) qui excutera directement le byte-code.
Le chargeur de classes
371
1.
Le butineur actuel de Netscape quant lui ne prend aucun risque, il interdit lcriture et la lecture locales.
372
On peut ainsi adopter diffrentes politiques comme, par exemple, ne pas autoriser les applets extrieures communiquer lintrieur du mur pare-feu, ou autoriser lapplet communiquer uniquement avec sa source (le serveur do lon a charg la classe), etc. Ajoutons encore que ces mcanismes de scurit doivent tre modifis avec circonspection. Finalement, si la scurit doit tre adapte une situation particulire, la classe SecurityManager peut tre tendue, afin de supporter de nouveaux degrs de protection ou de nouveaux critres de protection.
Chapitre 28
374
La rponse des concepteurs de Java a t la publication dune proposition dAPI dfinissant linteraction entre un programme Java et une base de donnes (relationnelle dans un premier temps). Cette API, nomme JDBC (Java DataBase Connectivity), supporte les fonctionnalits de base de SQL (langage dinterrogation des SGBD relationnels). En ce sens, elle peut tre considre comme une API de bas niveau, simple et robuste ( limage de Java), lide tant de construire par la suite des niveaux suprieurs tels que systmes de transactions, diteurs de schmas, etc. JDBC est base sur les dfinitions de X/Open SQL CLI (Call Level Interface), tout comme ODBC, la solution de Microsoft pour laccs des bases de donnes. JDBC prsente ainsi de nombreuses similitudes avec ODBC et dfinit une interface Java pour les principaux concepts de X/Open CLI. La spcification complte de JDBC est disponible chez Sun [4]. Nous reviendrons au point 28.3 sur les objectifs de JDBC et sur ses relations avec ODBC, SQL et Java.
JDBC API
LAPI JDBC est destine aux dveloppeurs de programmes Java (applets et applications) dsirant interagir avec un SGBD relationnel. Elle dfinit les structures ncessaires la connexion une base de donnes, lenvoi de requtes SQL et la rception de leurs rsultats. Les principales interfaces dfinies dans lAPI JDBC se trouve dans le tableau 28.1 .
Interface
java.sql.CallableStatement java.sql.Connection
Description
Gre linvocation de procdures stockes. Gre les connexions existantes, cre les requtes, gre les transactions. Gre les accs un SGBD travers un protocole. Gre le chargement des drivers et la cration des connexions TCP.
java.sql.Driver
java.sql.DriverManager
375
Description
Reprsente une requte paramtre. Gre laccs aux tuples dun rsultat. Gre les requtes excuter, reoit les rsultats.
DriverManager
Le DriverManager gre la liste des drivers JDBC chargs dans la machine virtuelle Java. Il sert galement mettre en correspondance les URL utiliss par les connexions avec les drivers disposition. Ainsi, le DriverManager dcortique les URL afin den extraire le sous-protocole et le service, puis recherche dans sa liste de drivers celui (ou ceux) capable(s) dtablir la connexion. Dans le cas o plusieurs drivers sont disponibles, le DriverManager peut consulter une proprit Java (sql.drivers) que lutilisateur a la possibilit de configurer; cette proprit regroupe une liste de noms de drivers. Le DriverManager parcourt alors cette liste dans lordre, choisissant le premier driver utilisable. Dans le cas o la proprit sql.drivers nest pas dfinie, cest lordre dans lequel les drivers ont t chargs qui sera considr.
376
Prcisons encore que la proprit sql.drivers est utilise par le DriverManager au moment de son initialisation : il charge alors lensemble des drivers indiqus dans la liste, les plaant ainsi en tte des drivers disponibles.
Connection
Une Connection reprsente un canal de communication (une connexion) entre un programme Java et une base de donnes. La cration et la gestion des Connections sont prises en charge par le DriverManager. Une Connection est cre partir dun URL dcrivant le protocole et le service utiliser. Lors de la cration dune Connection, des arguments tels que le nom de lutilisateur et son mot de passe peuvent tre fournis sous la forme dobjets de la classe java.util.Properties. Une fois cre, une Connection va servir envoyer des requtes au SGBD et rcuprer les rsultats, ces deux tches tant effectues laide des interfaces Statement (requte) et ResultSet (ensemble rsultat). Prcisons encore quune Connection peut servir de multiples squences requte/rsultat et quil nest donc pas ncessaire de crer systmatiquement une nouvelle Connection pour chaque requte. Transactions Linterface Connection est capable de grer des transactions SQL. Par dfaut, une Connection est place en mode de commit (confirmation) automatique : chaque requte est excute dans une transaction SQL spare puis confirme automatiquement. Ce mode peut tre dsactiv (mthode setAutoCommit()) afin de regrouper lexcution de plusieurs requtes en une seule transaction. En mode non automatique, la Connection maintient ouverte une transaction courante, qui peut tre confirme (Connection.commit()) ou annule (Connection.rollback()) au moment voulu. La Connection libre alors cette transaction et en cre immdiatement une nouvelle.
377
Description Requtes SQL paramtres. Procdures stockes paramtres.
Avant de dcrire ces diffrentes interfaces, prcisons quune requte doit tre obtenue auprs dune Connection existante avant de pouvoir tre prpare et excute. Le rsultat dune requte est obtenu auprs de la requte elle-mme.
Statement
Statement est destine aux requtes SQL simples, cest--dire celles dont lexpression SQL est prte lemploi, pouvant tre transmises telles quelles au SGBD. Une fois obtenue auprs dune Connection, une requte peut tre excute, son rsultat prenant la forme dun ResultSet (voir le point ResultSet) dans le cas dun SELECT. Ce rsultat peut alors tre vrifi (valeur NULL, ensemble vide, etc.) et parcouru ligne par ligne. Les ordres DELETE, INSERT, UPDATE quant eux retournent un entier. PreparedStatement (extension de Statement) PreparedStatement permet de crer une requte contenant des paramtres. Une telle requte est destine tre prpare et excute plusieurs fois de suite, avec des valeurs de paramtres diffrentes. Son code SQL contient des caractres ? indiquant lemplacement des paramtres, qui sont ensuite remplacs par des valeurs claires au moment de lenvoi de la requte la Connection associe. La mise jour des paramtres (binding) est ralise en invoquant les mthodes PreparedStatement.set...() adaptes aux types des paramtres. Le binding est effectu avant chaque excution, prparant ainsi la requte. noter quun paramtre, une fois mis jour, peut servir plusieurs excutions successives de la requte, la mthode clearParameters() permettant de vider lensemble des paramtres. CallableStatement (extension de Statement) CallableStatement est destine excuter des procdures stockes dans le SGBD. Les procdures de ce type acceptent gnralement des paramtres en entre (IN) et fournissent dautres paramtres (OUT) en sortie. Lassignation des paramtres IN seffectue laide des mthodes PreparedStatement.set...(). Les paramtres OUT doivent tre dclars (CallableStatement.registerOutParameter()) avant lexcution de la procdure : on invoque une fois cette mthode pour chaque paramtre OUT, en indiquant son type SQL.
378
Aprs lexcution, les paramtres OUT peuvent tre rcuprs laide des mthodes CallableStatement.get...() adaptes leurs types.
ResultSet
Une requte SQL produit diffrents types de rsultats. Dans le cas dune insertion, dune mise jour ou dune suppression, le rsultat retourn par le SGBD est gnralement un nombre entier indiquant uniquement le nombre de tuples ayant t touchs par la modification. Au contraire, dans le cas dune slection (ordre SELECT), le rsultat, fourni sous la forme dun ensemble de tuples gr par un ResultSet, est beaucoup plus intressant. Nous allons donc commencer par dcrire le rsultat dune slection avant de mentionner celui des autres ordres SQL.
java.sql.Statement requete = conn.createStatement(); ResultSet resultat = requete.executeQuery ("SELECT prenom, age FROM AMI WHERE age > 14"); // on sintresse aux personnes de plus de 14 ans while (resultat.next()) { // on rcupre le prnom et lge de chaque tuple int a = resultat.getInt ("age");// accs par le nom de colonne string p = resultat.getString (1);// accs par lindex de colonne System.out.println (p + " est age(e) de " + a + "ans"); }
Cet exemple illustre les deux manires de rfrencer une colonne : laide de son nom (ex. : "age"); laide de son index (ex. : 1 pour la premire colonne).
379
Il existe ainsi deux versions de chaque mthode ResultSet.get...(), lune acceptant une chane de caractres, lautre un entier. La notion de curseur est ralise laide de la mthode getCursorName() qui retourne un curseur associ au ResultSet courant. JDBC ne fournit pour linstant quun support simpliste de la notion de curseur, qui sera certainement toff dans le futur. Une fois encore, labsence de standard dans ce domaine justifie ce choix minimaliste.
JDBC et ODBC
La rponse la question pose ci-dessus, savoir pourquoi ne pas avoir intgr ODBC dans Java, se rsume en quelques mots : ODBC est trs (trop) li au langage C.
380
Ainsi, ODBC se base sur des lments propres au C tels que les types, les pointeurs ou lusage des (void *). Compte tenu des diffrences entre Java et C dans ce domaine (voir annexe A), une intgration dODBC dans Java naurait pu seffectuer que de manire force, mme si elle tait techniquement ralisable. Dautre part, ODBC passe pour tre un systme compliqu, difficile apprendre et mettre en uvre, y compris pour des utilisations simples. Enfin, la paramtrisation dODBC seffectue laide de fichiers de configuration stocks localement, ce qui va lencontre des principes de scurit de Java (du moins en ce qui concerne les applets). Ces diffrents aspects montrent que lintgration Java-ODBC scarte de la philosophie Java en matire de simplicit, duniformit et de robustesse. Ainsi, sans jamais remettre en question les qualits et les avantages du couple C-ODBC (disponibilit sur de nombreuses plates-formes, large diffusion, performance, etc.), les concepteurs de Java ont choisi de raliser dans un premier temps lAPI JDBC que lon peut situer au-dessus de la couche ODBC, celle-ci jouant le rle de sousprotocole et pouvant tre utilise laide de passerelles JDBC-ODBC. Un exemple complet en fin de chapitre, utilise cette passerelle.
JDBC et SQL
Le but de JDBC est de permettre un programme Java de transmettre des ordres SQL une base de donnes et de rcuprer les rsultats ventuels dans des structures Java (objets, tableaux, etc.) afin de les traiter. JDBC supporte les fonctionnalits de base de SQL, telles que dfinies dans la norme SQL2 Entry Level. Ce choix quelque peu restrictif se justifie par le fait quil reprsente le dnominateur commun en matire de SQL entre les principaux SGBD relationnels. Ici encore, lide des concepteurs de JDBC est doffrir rapidement un noyau de bas niveau commun et standardis, des fonctionnalits de plus haut niveau pouvant tre dfinies par la suite sous forme de nouvelles API ou doutils Java invoquant JDBC. cet effet, des mcanismes dextension de JDBC ont t prvus : lments de syntaxe, conversions de types. Les principes suivants ont t retenus : JDBC permet un programme Java de transmettre nimporte quelle requte un SGBD, autorisant ainsi lutilisation des fonctionnalits propres celui-ci. Cette possibilit risque nanmoins de compromettre srieusement la portabilit de ce programme sur un autre SGBD; un label de conformit JDBC Compliant a t dfini par Sun. Un driver JDBC dsirant obtenir ce label devra se soumettre des tests montrant quil supporte au minimum SQL2 Entry Level. Ds que ce label se sera impos comme LA rfrence en matire de driver JDBC,
Utilisation de JDBC
381
les programmes Java pourront utiliser cet ensemble dordres tout en restant portables. plus long terme, le but est de supporter la totalit de la norme SQL2, lorsque celle-ci aura vraiment t adopte et surtout lorsque les principaux SGBD la supporteront de manire complte.
JDBC et Java
JDBC, cest du Java! Cette exclamation reflte bien le souci des concepteurs de JDBC de conserver lesprit Java dans leur API. En effet, limmense succs de ce langage est trs li sa relative simplicit et llgance de bon nombre de ses concepts. Ds lors, JDBC, comme toutes les (futures) API Java, se doit dapparatre comme une extension naturelle du langage et non comme un empltre ajout de force. Influence de Java sur JDBC Les principes de base de Java se retrouvent dans lensemble de lAPI. Ainsi, lutilisation dexpressions fortement types est encourage, afin de maximiser les contrles derreurs la compilation (cet aspect du typage fort pose dailleurs quelques problmes). Nanmoins, la nature dynamique des rsultats de certaines requtes SQL est prise en compte par JDBC. De mme, lAPI est dfinie de manire relativement simple et cohrente, noffrant gnralement que peu dalternatives la ralisation dune tche. Enfin, JDBC, comme dautres librairies Java, utilise abondamment les principes de la programmation oriente objet, comme par exemple lhritage, le polymorphisme ou les interfaces. Un nombre relativement important de mthodes a ainsi t dfini, mthodes spcialises dans une tche prcise et facile comprendre.
382
mme, la possibilit de stocker des donnes de manire locale peut paratre indispensable, tout au moins dans des cas dune certaine complexit. La solution de lapplet reste intressante dans les cas les plus simples (et ils sont nombreux !), lintgration de lapplet dans un document HTML restant son principal avantage.
383
aussi bien par des applets locales (attaque depuis lintrieur) que par du code tlcharg (attaque depuis lextrieur). En effet, le driver est un maillon sensible de la chane de connexion entre un client et un serveur. Les recommandations des concepteurs de JDBC concernent plus particulirement la phase douverture des connexions rseau (TCP/IP). Dans le cas le plus simple dune connexion non partage, les contrles effectus par le SecurityManager suffisent garantir la scurit dune connexion, cest--dire que lobjet Java demandant la connexion est bien autoris accder la machine en question. La diffrence apparat lorsquun driver dsire pouvoir partager une connexion TCP entre plusieurs Connections JDBC (par exemple, lorsque plusieurs processus interrogent la mme base de donnes en parallle). Dans ce cas, cest au driver de vrifier que les diffrents clients (threads, classes) sont tous bien autoriss accder la base de donnes dfinie dans la connexion TCP partage. L encore, lutilisation du SecurityManager est recommande afin de vrifier les droits daccs. Le dveloppeur dun driver doit galement veiller la scurit des accs aux ressources du systme local. Le comportement sera diffrent selon quil sagit daccs uniques ou partags. Pour conclure, prcisons encore que toutes les mthodes dun driver doivent supporter des accs concurrents (multithread, voir chapitre 25).
la chane jdbc indique le protocole, au mme titre que http; le sous-protocole est le mcanisme de connectivit utilis (odbc par exemple); le service (subname en anglais) est une chane de caractres indiquant la machine, le port et la base de donnes utiliss. Exemple de service :
mycpu.unige.ch:9876:mybase
Le mcanisme des URL a t retenu comme format gnrique de description des connexions JDBC, en raison de son statut de standard en matire de nommage des ressources sur le Web. Nanmoins, la syntaxe pourra varier selon les
384
environnements (drivers, sous-protocoles, SGBD). Dans le cas du sous-protocole odbc (en minuscules dans les URL), une syntaxe a dj t spcifie afin de pouvoir inclure des valeurs de paramtres dans le nom du service.
import java.sql.*; class SQLService { // instance variables public static String query; public static Connection con; public static Statement stmt; public static ResultSet results; public static String ExecDML(String sqlText) { /* permet d'executer une commande de manipulation des donnees - insert, delete, update ou de manipulation du schema - create, drop, ...*/ int ResultCode; try {stmt = con.createStatement(); ResultCode = stmt.executeUpdate(sqlText); return ("OK ("+ResultCode+"): "+sqlText); }
385
// recupere le schema du resultat (nom des colonnes, type, ...) ResultSetMetaData resultSchema = results.getMetaData (); nbCol= resultSchema.getColumnCount (); //nbre de colonnes // affiche les entetes des colonnes System.out.println(); for (i=1; i<=nbCol; i++) {System.out.print(resultSchema.getColumnLabel(i)); System.out.print("|"); // sparateur de colonne } System.out.println(); // affiche les donnes ligne par ligne while (pasfini) { for (i=1; i<=nbCol; i++) // pour chaque colonne { System.out.print(results.getString(i)); System.out.print("|"); } System.out.println(""); nbLigne++; pasfini = results.next (); //prochaine ligne } System.out.println(nbLigne+" lignes trouvees par la requete"); } public static void PrintSQLError(SQLException ex) { System.out.println ("**ERREUR SQLException\n"); while (ex != null)
386
La classe SQLService
Lapplication ci-dessous utilise la classe SQLService pour effectuer les manipulations suivantes : cration de la table; insertion des donnes; mise jour des donnes; suppression des donnes; interrogation chaque manipulation pour vrifier leffet; exemple de traitement derreur.
class ExampleWithJDBCOracle { static String DML="DML"; static String SEL="SEL"; public static void doIt(String typereq, String s){ if (typereq.equals("DML")) System.out.println(SQLService.ExecDML(s)); if (typereq.equals("SEL")) System.out.println(SQLService.ExecSelect(s)); } public static void main (String args[]) { try { // Charger le driver jdbc-odbc bridge Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver"); // Connexion au driver //(fournir la source odbc, utilisateur, mot de passe) SQLService.con = DriverManager.getConnection ("jdbc:odbc:sgbdOracle", "javauser", "pwd"); // ici, on est connect, sinon on a gnr une exception // Crer la table BANQUE, on commence par dtruire la table! doIt(DML, "drop table BANQUE"); doIt(DML, "create table "+ "BANQUE(NOM_COMPTE CHAR(20), MONTANT Number)"); doIt(SEL, "Select * from BANQUE"); doIt(DML, "insert into BANQUE values ('PourMoi' , 100)");
387
doIt(DML, "insert into BANQUE values ('PourToi' , 100)"); doIt(DML, "insert into BANQUE values ('PourLui' , 500)"); doIt(DML, "insert into BANQUE values ('PourElle', 300)"); doIt(SEL, "Select * from BANQUE"); doIt(DML, "update BANQUE "+ "set MONTANT= 200 where NOM_COMPTE='PourToi'"); doIt(SEL, "Select * from BANQUE"); doIt(DML, "delete from BANQUE where MONTANT> 250"); doIt(SEL, "Select * from BANQUE"); // Close the statement SQLService.stmt.close(); // Close the connection SQLService.con.close(); // Une nouvelle connection avec une erreur SQLService.con = DriverManager.getConnection ("jdbc:odbc:sgbdOracle", "javatest", "?"); } catch (SQLException e) {SQLService.PrintSQLError(e);} catch (Exception e ) {e.printStackTrace ();} } }
NOM_COMPTE|MONTANT| PourMoi |100.| PourToi |100.| PourLui |500.| PourElle |300.| 4 lignes trouvees par la requete OK: Select * from BANQUE OK (1): update BANQUE set MONTANT= 200 where NOM_COMPTE='PourToi' NOM_COMPTE|MONTANT|
388
PourMoi |100.| PourToi |200.| PourLui |500.| PourElle |300.| 4 lignes trouvees par la requete OK: Select * from BANQUE OK (2): delete from BANQUE where MONTANT> 250 NOM_COMPTE|MONTANT| PourMoi |100.| PourToi |200.| 2 lignes trouvees par la requete OK: Select * from BANQUE **ERREUR SQLException Etat : 28000 Message: [Oracle][ODBC][Ora]ORA-01017: invalid username/password; logon denied Fournis: 1017
En modifiant une seule ligne de ce programme, il est possible de se connecter une autre source ODBC, dans notre cas MicroSoft Access (le nom de lutilisateur et le mot de passe ne sont pas ncessaires) :
SQLService.con = DriverManager.getConnection ("jdbc:odbc:sgbdOffice");
Chapitre 29
390
Dans le package rmi, linterface Remote et la classe Naming sont essentielles tout dveloppement et utilisation dobjets distribus. Les concepts de ce package tant parfois difficiles comprendre, il nous est apparu plus utile den dcrire les principes, puis den expliquer les composants travers un exemple complet.
391
serveur
traitement
Souche
Squelette
Dfinition de l'interface
public interface compteDistant extends java.rmi.Remote { // depot d'argent float depot(float amount) throws java.rmi.RemoteException; // retrait d'argent float retrait(float amount) throws java.rmi.RemoteException; // lecture du solde float litSolde() throws java.rmi.RemoteException; }
Les points cls sont les suivants : le constructeur de l'objet serveur doit appeler le constructeur de la classe dont il hrite; l'objet serveur implante toutes les mthodes de l'interface (le code des mthodes ne tient absolument pas compte du fait que les mthodes vont tre appeles par un objet distant);
public CompteServeur() throws java.rmi.RemoteException { super(); }
392
le lancement du serveur requiert l'installation d'un gestionnaire de scurit et galement l'enregistrement de l'objet serveur sur un rfrentiel d'implantation.
public static void main(String args[]) { //installation d'un gestionnaire de scurit if (System.getSecurityManager()==null) { System.setSecurityManager(new RMISecurityManager()); } System.out.println("security manager install"); try { // cration d'un objet CompteServeur CompteServeur name = new CompteServeur(); // enregistrement de l'objet sur le referentiel d'implantation Naming.rebind("//site:host/gestionCompteDistant", name); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); } }
L'laboration des squelette et souche se fait aprs la compilation du programme serveur avec lutilitaire rmic du JDK :
>javac CompteServeur.java >rmic CompteServeur
rmic construit deux fichiers CompteServeur_stub.class et CompteServeur_Skel.class. Ceux-ci seront tlchargs avec lapplet sur le poste client. Le code complet de l'objet serveur est le suivant :
import java.rmi.* ; import java.rmi.server.UnicastRemoteObject; public class CompteServeur extends UnicastRemoteObject implements compteDistant { float solde = 0; // constructeur public CompteServeur() throws java.rmi.RemoteException { super(); } // depot montant et renvoie le nouveau solde public float depot(float montant) throws java.rmi.RemoteException { solde += montant; return solde; } // renvoie le solde courant public float litSolde() throws java.rmi.RemoteException { return solde; } // retrait montant et renvoie le nouveau solde public float retrait(float montant) throws java.rmi.RemoteException { solde -= montant;
393
return solde; } public static void main(String args[]) { //installation d'un gestionnaire de scurit if (System.getSecurityManager()==null) { System.setSecurityManager(new RMISecurityManager());} try { // cration d'un objet CompteServeur CompteServeur name = new CompteServeur(); // enregistrement de l'objet sur le referentiel d'implantation Naming.rebind("gestionCompteDistant", name); } catch (Exception e) { System.out.println("Exception: " + e.getMessage()); } } //main }
Lapplet dclare un identificateur sur linterface CompteDistant. Elle obtient ensuite une rfrence sur un objet dont elle connat le nom et qui implante cette interface; cest le rle de la mthode Naming.lookup. Lapplet peut ensuite appeler les diffrentes mthodes de cet objet.
import import import import import import java.awt.*; java.awt.event.*; java.rmi.*; java.net.MalformedURLException; java.net.UnknownHostException; java.applet.Applet;
public class AppletClient extends Applet implements ActionListener { // remote interface declaration private CompteDistant accesDistant; private Button Depot, Retrait; private Label Solde; private TextField saisieMontant; private float MontantSolde; //constructeur public AppletClient(){ connexionServeur(); demandeSolde(); creeInterfaceGraphique(); } public void connexionServeur(){ // recherche de nom dans les registres try { accesDistant=(CompteDistant) Naming.lookup ("//site:port/gestionCompteDistant"); } catch (Exception e) { System.out.println("Exeception "+ e.getMessage());
394
public void actionPerformed(ActionEvent e) { String arg = e.getActionCommand(); float solde, montant; try { montant = (new Float(saisieMontant.getText()).floatValue()); } catch (NumberFormatException ex) { montant=0; } if ("Depot".equals(arg)) { try { solde= accesDistant.depot(montant); Solde.setText(" Solde: CHF "+solde); } catch (RemoteException re) { System.out.println("Exception "+ re.getMessage()); } }
395
Le dploiement comporte trois phases : dmarrage du rfrentiel dimplantation (rmiregistry); lancement du programme serveur, linstance de CompteServeur va alors se dclarer auprs de ce rfrentiel; tlchargement et excution de lapplet.
machine utilisateur butineur web http : tlchargement de lapplet RMI : appel de mthode applet Java RMI : fin de mthode http : requte de lurl de lapplet machine serveur serveur www
396
Lexemple que nous avons prsent nillustre quune partie des fonctionnalits de RMI. Une mthode distante accepte des paramtres et peut renvoyer des rsultats qui sont des objets et pas seulement des types simples. Le protocole de srialisation (vu au point 19.15, p. 261) est utilis pour lenvoi et la rception dobjet. On parle alors dobjet mobile, puisquil y a dplacement dobjet de machine en machine.
Chapitre 30
398
putent actuellement le march. partir de la version 4, Netscape Navigator est livr avec lORB (Object Request Broker) VisiBroker. Et il est donc possible pour une applet dutiliser les services de cet ORB pour accder des services CORBA. Pendant une priode, Sun a aussi essay de dvelopper un produit ORB (sous le nom de NEO). Actuellement, la stratgie de Sun est de pousser sa technologie de Enterprise Java Bean chez les dveloppeurs dORB. RMI est lquivalent de CORBA dans le monde Java. Leurs principes et leur fonctionnement sont similaires. Il est conseill de lire le chapitre sur RMI avant de poursuivre celui-ci.
399
publiant certains services sous forme dobjets CORBA et en crant des applets Java accdant ces services; la transparence des appels : une requte sur un objet distant (et donc potentiellement implante dans un langage diffrent) sexprime exactement comme une requte sur un objet local. La transmission et les conversions de reprsentation des paramtres sont entirement prises en charge par les souches et le courtier dobjets, le dveloppeur dapplications ne sen occupant pas; des appels statiques ou dynamiques : lappel statique, le plus simple utiliser (celui propos par le JDK 1.2), consiste appeler un service dun objet distant, objet que le programme appelant connat nommment. Lappel dynamique utilise, quant lui, un rfrentiel dinterfaces pour identifier un objet possdant un service que le programme appelant souhaite obtenir sans pour autant connatre a priori cet objet. La norme CORBA dfinit galement comment plusieurs ORB peuvent communiquer entre eux. Pour le protocole de rseau TCP/IP, cette spcification se nomme IIOP (Internet Inter ORB Protocol). Cette norme rend les objets CORBA disponibles sur le rseau Internet, comme le sont des pages dfinies en HTML.
CLIENT rfrentiel interface souche IDL ORB client interface IMPLANTATION OBJET (serveur) rfrentiel implantation
appel dynamique
Adaptateur objet
400
service de persistance : dfinition dune interface pour grer la persistance des objets; service de contrle de la concurrence : dfinition dune interface pour grer la concurrence et autoriser le verrouillage des objets par les transactions; service transactionnel : interface pour dfinir les mcanismes transactionnels sur les objets; etc. Les commodits de CORBA dfinissent un ensemble de composants pour la gestion et la cration de systmes dinformation. Ils sont bien sr dfinis en IDL. Voici la liste des domaines ayant retenu lattention de lOMG : gestion des documents; gestion des informations; administration des systmes; gestion des tches.
Applications objets Commodits : Documents Informations etc.
Transaction etc.
30.2 IDL
IDL (Interface Definition Language) est le langage pour dfinir les services devant tre rendus par les objets. Les requtes ces objets seront achemines par lORB du client vers le serveur. En retour, les rsultats de ces requtes seront achemins par lORB du serveur vers le client. LORB adapte les paramtres et transmet les requtes, tout en masquant sil y a lieu lhtrognit des systmes. Des clients et des serveurs programms dans des langages diffrents cohabitent ainsi grce CORBA. Cest la dimension interoprable de CORBA. Les services spcifis en IDL doivent tre implants dans le langage cible. Il faut disposer dun traducteur dIDL vers ce langage cible, qui est un langage de spcification purement dclaratif (il nest pas possible dexprimer limplantation dune mthode). On trouve des traducteurs pour C, C++, Smalltalk, COBOL, Ada, Java, etc.
IDL
401
La structure IDL est la suivante : un module contient des interfaces et ces dernires, des oprations. Cela correspond aux notions de packages, interfaces et mthodes de Java. En reprenant lexemple du chapitre sur RMI, on peut dfinir le comportement d'un compte bancaire avec la dclaration IDL suivante :
module LikeCompte { interface Compte { float litSolde(); float retrait (in float x); float depot (in float x); }; };
Sans entrer dans les dtails de la syntaxe dIDL, on peut reconnatre les diffrentes mthodes de linterface CompteDistant du chapitre sur RMI. Idltojava est le compilateur qui permet de transcrire les concepts IDL en Java 1, en utilisant la commande suivante :
idltojava -fno-cpp Compte.idl
Cette commande va crer un dossier LikeCompte dans lequel on trouvera les rsultats de la traduction. Voici les fichiers gnrs : Compte.java : interface implanter; _CompteStub.java : fonctionnalits CORBA pour le client (la souche statique); _CompteImplBase.java : classe abstraite servant de guide pour lobjet implanter; CompteHolder.java et CompteHelper.java : classes de services pour la conversion de type (entre lORB et Java). En examinant Compte.java, on peut constater la traduction nonce plus haut.
package LikeCompte; public interface Compte extends org.omg.CORBA.Object { float litSolde(); float retrait(float x); float depot(float x); }
1.
partir de cette dclaration IDL, nous aurions pu gnrer un programme C++ pour illustrer lhtrognit permise par CORBA. En restant dans Java, les diffrences entre des applications distribues avec RMI ou CORBA sont plus visibles.
402
La figure ci-dessous illustre le principe de dveloppement dobjets rpartis dans des langages diffrents. Jusqu prsent, nous navons dvelopp que la partie client (partie gauche de la figure).
Dfinir les interfaces en IDL compiler IDL vers C++ Souches (squelettes) compiler IDL vers Java Ajouter le code aux squelettes Compiler C++ Souches IDL client Squelettes serveur implantation des objets adaptateur des objets
instancier
rfrentiel dimplantation
La classe CompteImpl
Le Serveur CORBA
403
5
ORB ORB
Le rseau 1+2
ORB rfrentiel dimplantation
3+4
Cette mdiation du service de nommage permet de rendre compltement indpendants client et serveur. Examinons le code source du programme du serveur.
import LikeCompte.*; // Le package contenant nos stubs import org.omg.CosNaming.*; // serveur de noms : le ref. dimplantation import org.omg.CosNaming.NamingContextPackage.*; import org.omg.CORBA.*; // Corba class SetOfCompteServer { public static void main(String args[]) {
404
La classe SetOfCompteServer
Commentons un peu le programme du serveur. Nous importons dabord les diffrents packages ncessaires l'utilisation de CORBA et du rfrentiel dimplantation.
import import import import LikeCompte.*; // Le package contenant nos stubs org.omg.CosNaming.*; // le serveur de noms org.omg.CosNaming.NamingContextPackage.*; org.omg.CORBA.*; // Corba
Ensuite, nous initialisons lORB et crons une rfrence orb qui servira enregistrer nos objets.
ORB orb = ORB.init(args, null);
Les objets que nous publions sont connus des clients par un nom, et associs une rfrence. Pour entretenir cette association entre les noms et les rfrences, nous utilisons le service de nommage de CORBA. Les noms sont spcifis de manire hirarchique. La premire tape consiste chercher la racine du contexte des noms (ncRef). La mthode narrow est utilise en gnral pour typer la rfrence CORBA avec le type utilis dans Java (quivalent dune conversion de type (casting) entre IDL et Java).
org.omg.CORBA.Object nameS =
Le client CORBA
orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(nameS);
405
La deuxime tape consiste associer un nom la rfrence de lobjet et enregistrer cette association dans le rfrentiel dimplantation (PourToi est le nom du compte, le deuxime paramtre tant sa catgorie).
NameComponent nc = new NameComponent("PourToi", " "); NameComponent path[] = {nc}; ncRef.rebind(path, CompteRef);
La fin du programme traite les erreurs et on attend que les clients invoquent les objets activs par le serveur. Aprs avoir compil les diffrentes classes, nous pouvons dmarrer le serveur. Au pralable, il faut dmarrer le rfrentiel dimplantation de CORBA avec la commande suivante :
start tnameserv -ORBInitialPort 1050
Le rfrentiel dimplantation publie le contexte initial de la racine de la hirarchie de nommage (IOR pour Interoperable Object Reference). Le service est accessible sur le port 1050.
Initial Naming Context: IOR:000000000000002849444c3a6f6d672e6f72672f436f734e616d696e672f4e616d696e67436f 6e746578743a312e3000000000010000000000000030000100000000000a6e745f66696e5f323200 045900000018afabcafe0000000276b1268a000000080000000000000000 TransientNameServer: setting port for initial object references to: 1050
Le serveur nest pas trs bavard mais lobjet, au moment de son instanciation, dclare quil est actif :
Objet Compte disponible : PourToi
406
public class AppletClient extends Applet implements ActionListener { private private private private private Compte accesDistant; // la rfrence du compte dans l'ORB Button Depot, Retrait; Label Solde; TextField saisieMontant; float MontantSolde;
public AppletClient(String args[]){ connexionServeur(args); demandeSolde(); creeInterfaceGraphique(); } public void connexionServeur(String args[]){ try {ORB orb = ORB.init(args, null); org.omg.CORBA.Object nameS = orb.resolve_initial_references("NameService"); NamingContext ncRef = NamingContextHelper.narrow(nameS); NameComponent nc = new NameComponent("PourToi", " "); NameComponent path[ ] = {nc}; accesDistant = CompteHelper.narrow(ncRef.resolve(path));
} public void demandeSolde(){ // idem exemple RMI } public void creeInterfaceGraphique(){ // idem exemple RMI } public void actionPerformed(ActionEvent e) { // idem exemple RMI } public static void main(String args[]) { try {Frame f = new Frame("Compte Client"); AppletClient appletClient = new AppletClient(args); appletClient.init(); appletClient.start(); f.add("Center", appletClient);
407
On remarquera que les invocations de mthodes sont effectues comme si lobjet tait local au programme, la dlocalisation du compte est donc entirement transparente pour le dveloppeur. Le lancement du programme doit, comme on sen doute, se faire avec le mme port que pour le rfrentiel dimplantation.
java AppletClient -ORBInitialPort 1050
408
public float retrait(float x) { doIt(DML, "update BANQUE set MONTANT=MONTANT-"+x+ " WHERE NOM_COMPTE='"+nomCompte+"'" ); return SQLService.getMontant(nomCompte);} public float depot(float x) { doIt(DML, "update BANQUE set MONTANT=MONTANT+"+x+ " WHERE NOM_COMPTE='"+nomCompte+"'" ); return SQLService.getMontant(nomCompte);} private static void doIt(String typereq, String s){ if (typereq.equals("DML")) System.out.println(SQLService.ExecDML(s)); if (typereq.equals("SEL")) System.out.println(SQLService.ExecSelect(s)); } // initialisation de la classe static{ try { // Charger le driver jdbc-odbc bridge Class.forName ("sun.jdbc.odbc.JdbcOdbcDriver"); SQLService.con = DriverManager.getConnection ("jdbc:odbc:sgbdOracle", "javatest", "javapass"); // ici, on est connect, sinon on a gnr une exception doIt(SEL, "Select * from BANQUE"); } catch (SQLException e) {SQLService.PrintSQLError(e);} catch (Exception e ) {e.printStackTrace ();} } }
Notre code rutilise la classe SQLService du chapitre concernant JDBC. Pour faciliter et rendre plus lgant le code de notre classe Compte, nous y avons ajout une mthode getMontant() qui nous retourne le montant enregistr dans la base de donnes pour un compte spcifique.
class SQLService { // . . . // nous avons ajout une mthode cette classe par rapport // lexemple du chapitre sur JDBC public static float getMontant(String nc) { try {stmt = con.createStatement(); results = stmt.executeQuery( "SELECT MONTANT FROM BANQUE "+ "WHERE NOM_COMPTE='"+nc+"'" ); if (results.next ()) {return results.getFloat(1); } else System.out.print("** pas de donne pour le compte: "+nc);
409
return 0; } catch (Exception ex) {System.out.print("** Erreur dans la requete pour: "+nc); return 0;}
} // . . .
La connexion la base de donnes se fait lors de la premire instanciation dun objet de cette classe; nous avons accroch le code dans la partie dinitialisation statique de la classe Compte. Laspect le plus surprenant de cette implantation est la disparition complte de la variable charge de mmoriser la valeur du compte. Le solde du compte est toujours manipul dans la base de donnes. Pour finir en beaut ce chapitre et ouvrir une polmique, nous poserons une question concernant lextension possible de cette implantation. Pour implanter un mcanisme transactionnel dans notre applet de manipulation de compte bancaire, quel niveau doit-on le faire : dans limplantation de lobjet compte en utilisant le mcanisme de synchronisation de Java? en utilisant les services transactionnels de CORBA? en utilisant les mcanismes transactionnels de la base de donnes qui mmorise notre objet?
ORB
CompteImpl. java
Transactions ?
Chapitre 31
412
API Java Naming and Directory Interface (JNDI) Java IDL Java Remote Method Invocation (RMI) API Java Message Service API Java Transaction API (JTA) Java Transaction Service (JTS) Java Management API (JMAPI) JDBC Java Mail AP JavaHelp API Java Communications API Tableau 31.1 Fonctions des API Fonction
Interfaces de gestion dannuaires. Interfaces pour le dveloppement avec CORBA. Interfaces pour la programmation distribue. Gestion dun systme de messages. Mcanisme pour la gestion transactionnelle. Services associs la gestion transactionnelle. Interfaces pour la gestion de la gestion... Gestion de la connexion avec les bases de donnes. Interface pour la gestion dune messagerie. Gestion de laide en ligne. Gestion des communications (du bureau).
La lecture de cette liste montre bien quel point Java est en plein dveloppement et les directions vers lesquelles il soriente : rseau, bases de donnes, multimdia, scurit, etc.
Partie V
Annexes
A. B. C. D. E. Du C++ Java Grammaire BNF de Java Les fichiers darchives .jar Rappel sur HTML JavaScript
Annexe A
Du C++ Java
Quelle est la diffrence entre Java et C++? Java est orient objet.
Ce chapitre prsente une revue des diffrences existant entre C++ et Java. Ces diffrences sont nombreuses et il convient den illustrer toutes les subtilits. Nous dbutons par les diffrences lies au dveloppement de projets puis abordons les diffrences entre les langages eux-mmes.
416
Commenons par un programme simple pour illustrer les diffrences dans lorganisation du dveloppement dapplication. Nous prsentons une version C++ puis la version Java quivalente.
// C++ // fichier Temps.h // note pour les programmeurs avertis : on parle des #ifdef plus tard class Temps { private : unsigned heure, minute, seconde; public : Temps() {heure=0; minute=0; seconde=0;} Temps(unsigned h,unsigned m, unsigned s) {heure=h; minute=m; seconde=s;} int tempsValide(); void affiche(); };
Le listing suivant est la dfinition correspondante en Java de la classe Temps. On notera que les deux versions de la classe Temps nutilisent pas les mmes types de donnes : en effet, le type unsigned (dfini en C++) nexiste pas en Java, le type boolean quant lui existe et remplace avantageusement le type int retourn par la mthode tempsValide.
// Java // fichier Temps.java import java.io.*;
417
418
point 3.2, p. 32). Il ny a pas ddition statique de liens dans Java : linterprteur charge, si ncessaire, les diffrentes classes dont lapplication a besoin au cours de son excution. Ldition de liens est donc dynamique. Le C++ requiert une phase ddition de liens statique. Celle-ci a pour but dassembler les diffrents programmes objet issus de la compilation pour fabriquer un programme excutable. En C++, les fichiers den-tte jouent un rle important : par la directive du prprocesseur #include, ils spcifient les modalits de rutilisation dune classe. Ces modalits sont des rfrences externes qui ne doivent tre dclares quune seule fois pour une application (constitue ainsi dun ensemble de fichiers). Ces dclarations multiples ne sont gnralement identifies qu ldition de liens. Une bonne pratique permet dliminer ce problme en utilisant des primitives du prprocesseur. Cette pratique (illustre dans lexemple suivant) est une ncessit lorsquune application est dveloppe par une quipe de programmeurs, sans que lon sache si Pierre ou Paul rutilisera telle ou telle classe.
#ifndef TEMPS_H #define TEMPS_H // en-tete de la classe Temps class Temps { private : unsigned heure, minute, seconde; public : Temps() {heure=0; minute=0; seconde=0;} Temps(unsigned h,unsigned m, unsigned s) {heure=h; minute=m; seconde=s;} int tempsValide(); void affiche(); }; #endif
Lusage des fichiers den-tte et de la squence #ifndef...#endif illustre sur lexemple prcdent nest plus ncessaire en Java (il ny a dailleurs pas de prprocesseur). Cependant, ces fichiers taient frquemment utiliss par les dveloppeurs C++ pour commenter la classe, prciser les modalits dutilisation et/ ou le rle des membres dune classe afin den faciliter la rutilisation.
1.
Le mot objet ici nest pas pris au sens de orient objet . Un programme objet est le rsultat de la compilation dun programme source.
419
En Java, il nest pas toujours facile de se faire une ide prcise de la faon de rutiliser telle ou telle classe. En effet, un fichier unique contient la dfinition complte de la classe, y compris le corps de toutes les mthodes. On ne dispose pas dune vue synthtique permettant dapprhender rapidement lintrt dune classe pour sa rutilisation. Les programmeurs Java doivent donc faire un effort particulier de documentation de leurs programmes, ventuellement dans un fichier spar ou, mieux encore, utiliser les commentaires spciaux pour lutilitaire JavaDoc. JavaDoc gnre ensuite la documentation de vos sources sous forme de documents HTML. Cette pratique est ncessaire pour favoriser la rutilisation, que lon distribue ou non le code source sur Internet ou lintrieur de son quipe de dveloppement.
420
3. On recompile la classe Temps dans les deux environnements. 4. On teste les deux applications : a. la version C++ na pas t reconstruite et sexcute comme avant; b. la version Java produit lerreur suivante lexcution :
java.lang.NoSuchMethodError: Temps: method <init>()V not found
Ce scnario illustre le chargement dynamique par Java des mthodes dont une application a besoin pour son excution. Cependant, dans les deux cas, loubli par le dveloppeur de recompiler lapplication entrane des consquences dommageables : en C++ lutilisateur a toujours lancienne version, en Java lutilisateur a une application qui peut produire des bogues. Tous les problmes didentification des classes clientes recompiler ne sont pas entirement rsolus, mais un pas en avant a t fait relativement au C++ (mme si on utilise le make ). Nous avons vu dans les paragraphes prcdents que la gestion du dveloppement dune application est diffrente pour ces deux langages. Nous allons maintenant aborder les diffrences existant entre les deux langages proprement dits.
421
Taille en bits 8 16 32 64 32 64
Le type caractre
Le type char de Java dfinit un caractre de 16 bits au format Unicode. Les caractres Unicode sont des valeurs entires de 16 bits non signes (cest--dire entre 0 et 65535).
Le type boolen
Contrairement au C++, Java possde un type boolen nomm boolean. Ses valeurs sont true et false pour vrai et faux respectivement. Le type boolean est un type distinct des types numriques : on ne peut pas convertir un type boolean en un type numrique quel quil soit.
La classe String
Java comporte une classe prdfinie String. Un objet de la classe String nest pas quivalent un tableau de char.
422
C++
#include <iostream.h> main() {int c; cout << c <<'\n'; }
La version C++ sexcute normalement et affiche 0, la valeur initiale affecte par le compilateur la variable c. La version Java est refuse la compilation et ne peut donc tre excute.
Dclaration
Le tableau A.3 rcapitule les diffrences sur les dclarations de tableau. En Java, les instructions lgales de cette table ne sont que des dclarations de type, elles ne crent pas le tableau.
Les tableaux
423
En C++, la dclaration dun tableau en initialise les lments : la classe doit avoir
Exemple de dclaration dun tableau
int[] monTableau; int monTableau[]; Temps [] rendezVous[]; // 2 dimensions int monTableau[5]; int[5] monTableau;
un constructeur par dfaut, ce constructeur tant appel automatiquement lors de la dclaration du tableau (si au moins un des lments nest pas initialis explicitement). Dans lexemple suivant, le constructeur Temps() doit tre prsent.
//C++ #include "Temps.h" void main() { Temps intervalle[2]; for (int i=0;i<2;i++) intervalle[i].affiche(); }
En Java, lallocation effective des objets lments du tableau requiert lappel explicite dun constructeur.
//Java import Temps; class demo { public static void main(String argv[]) {Temps intervalle[]=new Temps[2]; for (int i=0;i<2;i++) {intervalle[i]=new Temps(); intervalle[i].affiche();} } }
424
Le tableau A.4 illustre la dclaration et linitialisation avec appel explicite du constructeur dsir.
Dclaration et initialisation de tableaux dobjets Java C++
Temps[] intervalle= { new Temps(),new Temps(12,15,30)}; Temps intervalle[2]= {Temps(),Temps(12,15,30)};
Initialisation des tableaux multidimensionnels Contrairement au C++, en Java il ny a pas de tableaux multidimensionnels mais des tableaux de tableaux. Linitialisation de leurs dimensions se fait ainsi :
// Java int t[][]=new int[3][4]; int t[][]={{0,3,-2,5,-1,4},{0,3,-2,3,-1},{0,3,-2,4},{0,3,3}};
Il nexiste pas de contrainte sur les tailles : ainsi le tableau prcdent est triangulaire. Lattribut length permet dobtenir la longueur dun tableau. Lexemple cidessous montre lintrt dun tel attribut puisquil dcharge le programmeur de la gestion des longueurs de tableaux. De plus, Java contrle les valeurs des indices de tableaux, ce qui facilite grandement la mise au point des programmes.
//Java import java.io.*; class demo { public static void main(String argv[]) { int t[][]={{0,3,-2,5,-1,4},{0,3,-2,3,-1},{0,3,-2,4},{0,3,3}}; for (int i=0;i<t.length;i++) {for (int j=0;j<t[i].length;j++) System.out.print(" "+t[i][j]); System.out.println();} } }
Linstruction for
425
En fin de bloc, sil existe des objets uniquement rfrencs par des variables locales ce bloc, lespace quils occupent sera rcupr ultrieurement par le ramasse-miettes. Le programmeur peut dfinir une mthode appele finalize(). Cette mthode, appele par le ramasse-miettes avant la destruction de linstance concerne, nest utile que pour la libration de ressources autres que la mmoire par exemple un fichier non ferm. Cette mthode joue le rle du destructeur C++.
Le tableau A.6 montre la transformation des boucles for pour passer dun langage lautre.
Java
... for (int i=0;i<5;i++) t[i]=i; ... ... int i; ... for (i=0;i<5;i++) t[i]=i; ...
C++
... {for (int i=0;i<5;i++) t[i]=i;} ... ... for (int i=0;i<5;i++) t[i]=i; ...
426
C++
#include <iostream.h> void main() { int t[5]={0,3,-2,5,-1}; for (int i=0;i<5;i++) {if (t[i]<0) continue; cout << t[i] << endl;} }
En Java, linstruction continue (voir point 5.6, p. 73) peut comporter une tiquette de branchement facultative. Si cette tiquette est absente, linstruction a la mme signification quen C++. Ltiquette de branchement nquivaut pas un goto qui autorise aller nimporte o, mais permet dans le cas de rptitives imbriques de spcifier le niveau dimbrication partir duquel on veut continuer les itrations. Ltiquette est ncessairement dfinie dans un bloc englobant celui dans laquelle linstruction continue se trouve. Ainsi, le programme suivant recherche toutes les occurrences dune suite de nombres dans un tableau numrique deux dimensions. Le programme affiche : le tableau dans lequel se fait la recherche; la suite rechercher; les coordonnes des occurrences (sil y en a) de cette suite dans le tableau.
//Java import java.io.*; class demo { public static void main(String argv[]) {int t[][]={{0,3,-2,5,-1,4},{0,3,-2,3,-1,2},{0,3,-2,4,5,1},{0,3,3,-2,3,-1}}; System.out.println("tableau a parcourir :"); for (int i=0;i<t.length;i++) {for (int j=0;j<t[i].length;j++)
Linstruction continue
System.out.print(" "+t[i][j]); System.out.println(); }; int search[]={3,-2,3}; System.out.println("suite a chercher :"); for (int i=0;i<search.length;i++) System.out.print(" "+search[i]); System.out.println(); for (int i=0;i<t.length;i++) {debutRecherche: for (int k=0;k<t[i].length-search.length;k++) {for (int j=0;j<search.length;j++) if (t[i][k+j]!=search[j]) continue debutRecherche; System.out.println("trouve en "+i+","+k); } } } }
427
Dans cet exemple, linstruction continue permet, en cas dchec de reconnaissance de la suite dans le tableau (mme si on en a trouv une partie), de continuer la recherche lindice k suivant. Un programme C++ quivalent contenant des tiquettes de branchement utilise donc le goto.
//C++ #include <iostream.h> void main() { int t[4][6]={{0,3,-2,5,-1,4}, {0,3,-2,3,-1,2}, {0,3,-2,4,5,-1}, {0,3,3,-2,3,-1}}; cout << "tableau a parcourir :"<< endl; for (int i=0;i<4;i++) {for (int j=0;j<6;j++) cout <<" " << t[i][j] ; cout << endl;} int search[]={3,-2,3}; cout << "suite a chercher :" << endl; for (i=0;i<3;i++) cout <<" " << search[i] ;
428
Linstruction goto
429
Un programme C++ quivalent contenant des tiquettes de branchement utilise donc le goto.
//C++ #include <iostream.h> void main() { int t[4][6]={{0,3,-2,5,-1,4}, {0,3,-2,3,-1,2}, {0,3,-2,4,5,-1}, {0,3,3,-2,3,-1}}; cout << "tableau parcourir :"<< endl; for (int i=0;i<4;i++) {for (int j=0;j<6;j++) cout <<" " << t[i][j] ; cout << endl;} int search[]={3,-2,3}; cout << "suite chercher :" << endl; for (i=0;i<3;i++) cout <<" " << search[i] ; cout << endl; for (i=0;i<4;i++) {for (int k=0;k<6-3;k++) {for (int j=0;j<3;j++) if (t[i][k+j]!=search[j]) goto debutRecherche; cout <<"trouve en " << i <<"," << k << endl; goto sortie; debutRecherche: ; } } sortie: cout <<"C'est fini!" << endl; }
En dfinitive, contrairement au C++, Java permet dviter une programmation avec des branchements non orthodoxes. Dans les deux langages, les branchements intempestifs peuvent toujours tre vits par des variables boolennes qui permettent de sortir de rptitives imbriques.
430
A.15 Laffectation
En Java, toutes les variables dsignant les objets sont des rfrences ( lexception des objets de types numrique, caractre et boolen). C++ utilise les rfrences aux objets notamment pour le passage de paramtres dans les mthodes, fonctions ou procdures. Une rfrence en C++ est une sorte de pointeur pour lequel lutilisateur na pas spcifier les indirections permettant laccs la variable pointe. Les rfrences C++ ne sont cependant pas des pointeurs : en effet, lorsque lon affecte deux pointeurs, ils dsignent le mme objet, ce qui nest pas le cas des rfrences C++. De plus, contrairement aux pointeurs, aucune opration (++, --) nest possible sur les rfrences.
Laffectation
431
Aprs laffectation, les valeurs des attributs sont bien videmment identiques. Lappel de la mthode plusUneHeure() sur la rfrence t augmente lheure dune unit pour lobjet rfrenc par t. Lappel de la mthode affiche() sur les deux rfrences nous montre quelles dsignent le mme objet.
C++
Valeurs initiales : 12:0:0 14:30:0 Apres affectation 14:30:0 14:30:0 Apres plusUneHeure 15:30:0 14:30:0
432
Laffectation de rfrence en C++ est quivalente laffectation de deux objets dsigns par des variables simples : elle substitue le contenu du terme gauche par celui du terme droit. Les rfrences ne dsignent pas le mme objet. Lorsque lon augmente lheure dune unit pour lun, lobjet dsign par lautre rfrence reste inchang.
Rcapitulatif
En C++, il y a trois possibilits de dsignation des objets : un dsignateur simple (une variable); un pointeur; une rfrence. Les rfrences nexistaient pas en C, elles ont t introduites en C++ pour le passage des paramtres. En Java, il nexiste quun seul mode de dsignation des objets : la rfrence. Cette uniformit ne constitue pas un appauvrissement du langage (par rapport au C++) mais simplifie plutt la conception des programmes. Les rfrences de Java ne sont quivalentes ni aux pointeurs ni aux rfrences du C++.
Les variables de classe sont initialises lors du chargement de la classe, dans lordre dapparition dans la dfinition de la classe : une rfrence en avant provo-
La dfinition de classes
433
En Java, lors de la cration dune instance, les variables dinstance sont initialises avant lappel au constructeur. Ainsi, lors de la cration dune instance de la classe ci-dessous, la variable dinstance demo aura la valeur 6.
// Java class UneClasse { int demo=3; UneClasse() {demo=6;} }
En C++, la norme ANSI interdit linitialisation dune variable dinstance (non constante) lors de sa dfinition. Il faut alors initialiser celle-ci laide dun constructeur.
434
C++
class UneClasse { UneClasse() {...} public: int A1, A2; char A3; void m1(); protected: float A4; double A5; void m2(); private: float A6,A7; void m3(); void m4(); };
m1
m2
m3 m4
Cependant en C++, une spcification dun domaine de protection reste valable jusqu spcification dun autre domaine de protection. En Java, cette spcification doit tre mentionne pour chaque attribut et mthode. public et private ont la mme signification dans les deux langages, protected prsente une diffrence : en C++, la mthode ou la variable dinstance est accessible
La dfinition de classes
435
( moins quil y ait un masquage) par nimporte quelle sous-classe. En Java, laccs est tendu aux classes du mme package. En C++, labsence de spcification dun domaine dfinit implicitement le domaine private. En Java, cette absence ne correspond aucun des trois domaines. En effet, la variable ou la mthode est accessible par toutes les classes du mme package, mais non par les sous-classes dclares dans dautres packages. Spcification des variables et des mthodes de classe En Java comme en C++, les variables de classe et les mthodes de classe sont spcifies laide du prfixe static devant leur dclaration.
//Java class UneClasse { static int nombresDInstances=0; // variable de classe static void uneInstanceDePlus() // methode de classe {nombresDInstances++; }; UneClasse() // constructeur {uneInstanceDePlus(); } private String info; //variable d'instance void Information()//methode d'instance {System.out.println("l'instance " + info + " est une des "+ nombresDInstances + " instances de sa classe" ); } };
En C++ et en Java, les mthodes de classe nont accs quaux variables et mthodes de classe. Les mthodes dinstance ont accs aux variables et mthodes de classe et dinstance. En Java, on le rappelle : linitialisation des variables dinstance et de classe peut se faire au moment de leur dclaration, dans la dfinition de la classe. En C++, une variable de classe est accessible depuis la classe ou lune des instances de la classe. Laccs depuis la classe requiert loprateur de rsolution de porte (::). En Java, laccs seffectue partir de linstance ou de la classe de manire uniforme laide de loprateur de slection (.) : la classe est un objet avec des donnes membres et des mthodes. Le tableau A.10 illustre laccs aux variables et mthodes de classe dans les deux langages. En Java, une mthode de classe ne peut tre redfinie dans une sous-classe. Une mthode static est donc implicitement final.
436
Java Dfinition de classe avec variable et mthode de classe
class UneClasse { public int x; public static int n; public static int valeur() {return n;}; UneClasse(){x=3;} }; //accs partir de la // classe int i=UneClasse.n; int j=UneClasse.valeur(); //accs partir d'une //instance UneClasse c=new UneClasse(); i+= c.n; j+= c.valeur();
Modes daccs
Autres qualifications des variables Une variable dinstance ou de classe peut tre constante. Un prfixe (const en C++, final en Java) donne cette spcification. Java permet de qualifier de volatile et transient des variables.
Java Dfinition de constantes
class UneClasse { final int version=3;}
C++
class UneClasse { const int version=3;}
Autres qualifications des mthodes En Java, final quivaut const en C++ pour les variables dinstance ou de classe. En Java, une mthode qualifie de final nest pas une mthode retournant une valeur constante mais une mthode ne pouvant tre redfinie dans une classe drive. Une mthode prfixe par native nest pas implante par la machine virtuelle, mais par du code dpendant de la plate-forme utilise, par exemple du C ou de lassembleur. Ces mthodes nont pas de corps. Elles peuvent tre des mthodes de classe ou dinstance, hritables, masquables ou non.
Constructeurs
437
Une mthode prfixe par synchronized est une mthode qui sexcute via un moniteur qui en contrle les accs (voir point 25.2, p. 354). Le verrou est sur la classe pour une mthode de classe, sinon sur lobjet (mthode dinstance). En Java, une mthode qualifie de abstract ressemble une mthode virtuelle pure en C++, en ce sens quelle na pas de corps et requiert une dfinition explicite dans les sous-classes. Cependant, en Java, de telles mthodes sont dfinies dans une classe ncessairement abstraite elle aussi (voir point A.20, p. 439). final signifie en Java : pour une classe : pas de drivation de sous-classes; pour un attribut : attribut constant; pour une mthode : non redfinissable dans une sous-classe avec les mmes paramtres.
A.17 Constructeurs
Le principe de dfinition des constructeurs en Java est le mme quen C++. Les constructeurs portent le mme nom que la classe. Ils peuvent tre surchargs afin doffrir plusieurs manires dinitialiser des instances.
Construction dobjet par copie Java C++
Temps t=new Temps(12,0,0); Temps t2=t.clone() Temps t(12,0,0); Temps t2=t;
Il existe cependant quelques diffrences. En Java, il nexiste pas de constructeur par copie par dfaut, la mthode clone() de la classe Object le remplace (voir tableau A.12). Lordre dappel des constructeurs des super-classes est le mme pour Java et C++ : le constructeur de la classe de base est toujours excut avant celui de la classe drive. Une diffrence notable a trait aux constructeurs des objets composants. Contrairement au C++, aucun constructeur par dfaut dobjet composant nest appel en Java. Lexemple du tableau A.13 en est une illustration. La classe Cours est compose de deux variables dinstance de la classe Temps. En C++ seulement, le constructeur par dfaut de la classe Temps sera appel. Sil nexiste pas, la classe Temps devra tre redfinie pour en inclure un.
438
Java Modification du constructeur de la classe Temps pour afficher son nom
Temps() {heure=0; minute=0; seconde=0; System.out.println ("Temps()"); } import Temps; class Cours { public Temps debut,fin; public int numero; public Cours(int num) {numero=num;} }; Cours c=new Cours(12);
A.18 Destructeurs
Un destructeur en Java est une mthode spciale (non ncessaire) appele finalize() qui permet la libration de ressources systmes non automatiquement libres par le ramasse-miettes. Cette mthode ne joue pas tout fait le mme rle que les destructeurs en C++. Elle est appele par le ramasse-miettes qui, si ncessaire, libre lespace allou des objets qui ne sont plus rfrencs. En C++, lappel au destructeur de la super-classe seffectue automatiquement aprs le destructeur de la classe de linstance dtruire. En Java, le programmeur doit explicitement terminer le texte de sa mthode finalize() par lappel de celui de sa super-classe, soit super.finalize(). En Java, il nest pas utile (ni ncessaire) de programmer des destructeurs, sauf si la classe a acquis une ressource autre que la mmoire que le ramasse-miettes ne peut rcuprer comme, par exemple, un accs sur un fichier ou sur un socket.
A.19 Hritage
Hritage simple
Seul lhritage simple est permis. Le mot cl extends quivaut aux : du C++.
Classe abstraite
Spcification de lhritage Java
import classeDeBase; class classeDerivee extends classeDeBase { ... // attributs et mthodes de la classe drive }; #include "classeDeBase.h" class classeDerivee : classeDeBase { ... // attributs et mthodes de la classe drive };
439
C++
Modes dhritage
En C++, trois modes dhritage dune classe sont permis : public, protected, private. En Java, il ny en a quun seul (implicite) : public. Ces diffrents modes ont des consquences sur les domaines de protection des membres (variables et mthodes) hrits. Pour les modes dhritage private et protected, le C++ permet de conserver dans la classe drive les domaines de protection des membres de la classe de base. En considrant galement lhritage multiple, on constate que le C++ permet dexprimer de manire fine les relations dhritage entre classes, au dtriment cependant de la simplicit de comprhension pour des schmas de classes consquents.
Mode dhritage prsent dans : C++ C++ C++ et Java Mode dhritage dans la classe drive
private protected public
Protection dun membre de la classe de base private inaccessible inaccessible inaccessible protected
private protected protected
public
private protected public
440
Java Mthode avec liaison dynamique Mthode abstraite pure
void m(...) { // corps de m } abstract void m(...);
Le mot cl abstract doit galement prfixer le nom de la classe si cette classe a au moins une mthode abstraite.
Spcification de mthode abstraite
abstract class UneClasse { abstract void uneMethode(...); // methode abstraite ... }; class UneClasse { virtual void uneMethode(...)=0; // methode virtuelle pure .... };
Java
C++
441
tifs. Cest donc lappartenance ou non dune classe un package qui dcide de ses relations damiti avec dautres classes. En C++, lamiti entre classes ncessite une dfinition explicite dans la classe autorisant les accs ses membres privs. Ce qui entrane de frquentes recompilations au fur et mesure que de nouvelles classes sont ajoutes et quelles doivent accder des membres privs dune classe particulire. En Java, de telles nouvelles classes sont simplement ajouter dans le package, ce qui ne requiert aucune compilation supplmentaire.
C++
442
Java
C++
Annexe B
444
classType = classOrInterfaceType. interfaceType = classOrInterfaceType. arrayType name
simpleName
qualifiedName compilationUnit
= classDeclaration |
"public" | "protected" | "private" | "static" | "abstract" | "final" | "native" | "synchronized" | "transient" | "volatile". identifier
classDeclaration
= < modifier > "class" [ super ] [ interface ] classBody. = "extends" classType. = "implements"
super
interfaces classBody
interfaceType >.
classBodyDeclaration
classMemberDeclaration fieldDeclaration
= < modifier > type variableDeclarator < "," variableDeclarator > ";".
variableDeclarator
= variableDeclaratorId [ "=" variableInitializer ]. = = = identifier < "[" "]" >. expression | arrayInitializer. methodHeader methodBody.
Niveau syntaxique
methodHeader
445
methodDeclarator
= identifier "(" [ formalParameterList ] ") < "[" "]" >. = type formalParameter < "," variableDeclaratorId. formalParameter >.
classTypeList methodBody
staticInitializer
constructorDeclaration
[ ")".
constructorDeclarator
constructorBody
explicitConstructorInvocation
= "this" "(" [ argumentList ] ")" ";" | "super" "(" [ argumentList ] ")" ";". identifier interfaceType
interfaceDeclaration
[ >.
= < modifier > "interface" extendsInterfaces ] interfaceBody. = "extends" interfaceType < ","
extendsInterfaces
interfaceBody
= "{" <
interfaceMemberDeclaration
constantDeclaration
abstractMethodDeclaration arrayInitializer
< ","
block
blockStatement
446
localVariableDeclarationStatement localVariableDeclaration
< ","
statement
= statementWithoutTrailingSubstatement | labeledStatement | ifThenStatement | ifThenElseStatement | whileStatement | forStatement. = statementWithoutTrailingSubstatement | labeledStatementNoShortIf | ifThenElseStatementNoShortIf | whileStatementNoShortIf | forStatementNoShortIf. = block | emptyStatement | expressionStatement | switchStatement | doStatement | breakStatement | continueStatement | returnStatement | synchronizedStatement | throwStatement | tryStatement.
statementNoShortIf
statementWithoutTrailingSubstatement
emptyStatement labeledStatement
identifier ":"
statementExpression ";".
= assignment | preIncrementExpression | preDecrementExpression | postIncrementExpression | postDecrementExpression | methodInvocation | classInstanceCreationExpression. = "if" "(" expression ")" statement.
ifThenStatement
Niveau syntaxique
ifThenElseStatement
447
= "if" "(" expression ")" statementNoShortIf "else" statement. = "if" "(" expression ")" statementNoShortIf "else" statementNoShortIf. = "switch" "(" expression ")" switchBlock.
ifThenElseStatementNoShortIf
switchStatement switchBlock
[ <
= "{" [ switchBlockStatementGroups ] switchLabels ] "}". = switchBlockStatementGroup switchBlockStatementGroup >. = switchLabels < blockStatement >. switchLabel >. ":" | "default" ":". statement.
switchBlockStatementGroups
switchLabel <
whileStatement
expression ")"
whileStatementNoShortIf
= while "(" expression ")" statementNoShortIf. = "do" statement "while" "(" expression ")" ";" .
doStatement forStatement
= "for" "(" [ forInit ] ";" [ expression ] ";" [ forUpdate ] ")" statement. = "for" "(" [ forInit ] ";" [ expression ] ";" [ forUpdate ] ")" statementNoShortIf. = = statementExpressionList | statementExpressionList. statementExpression >. localVariableDeclaration.
forStatementNoShortIf
forInit forUpdate
statementExpressionList
448
breakStatement
= "continue" [ = "return" [
expression ] ";".
= "throw"
= "synchronized" "("
primaryNoNewArray
classInstanceCreationExpression
= "new" classType "(" [ argumentList ] ")". = expression < "," expression >.
argumentList
arrayCreationExpression
= "new" ( primitiveType | classOrInterfaceType ) "[" expression "]" < "[" expression "]" > < "[" "]" >.
fieldAccess
methodInvocation
= name "(" [ argumentList ] ")" | primary "." identifier "(" [ argumentList ] ")" | "super" "." identifier "(" [ argumentList ] ")". = name "[" expression "]" | primaryNoNewArray "[" expression "]". =
arrayAccess
postfixExpression
Niveau syntaxique
primary | name | postIncrementExpression | postDecrementExpression.
postIncrementExpression postDecrementExpression unaryExpression
449
= =
= preIncrementExpression | preDecrementExpression | "+" unaryExpression | "-" unaryExpression | unaryExpressionNotPlusMinus. = "++" unaryExpression. = "--" unaryExpression. =
preIncrementExpression preDecrementExpression
unaryExpressionNotPlusMinus
= "(" primitiveType < "[" "]" > ")" unaryExpression | "(" expression ")" unaryExpressionNotPlusMinus | "(" name "[" "]" < "[" "]" > ")" unaryExpressionNotPlusMinus. = unaryExpression | multiplicativeExpression "*" unaryExpression | multiplicativeExpression "/" unaryExpression | multiplicativeExpression "%" unaryExpression.
multiplicativeExpression
additiveExpression
multiplicativeExpression multiplicativeExpression.
shiftExpression
= additiveExpression | shiftExpression "<<" additiveExpression | shiftExpression ">>" additiveExpression | shiftExpression ">>>" additiveExpression. = shiftExpression | relationalExpression "<"
relationalExpression
shiftExpression
450
| | | | relationalExpression relationalExpression relationalExpression relationalExpression
equalityExpression
relationalExpression relationalExpression.
andExpression
equalityExpression.
exclusiveOrExpression
inclusiveOrExpression
exclusiveOrExpression.
conditionalAndExpression
inclusiveOrExpression.
conditionalOrExpression
expression ":"
= conditionalExpression | assignment.
leftHandSide
assignmentOperator
= "=" | "*=" | "/=" | "%=" | "+=" | "-=" | "<<=" | ">>=" | ">>>=" | "&=" | "^=" | "|=". = assignmentExpression. = expression.
expression
constantExpression
Niveau lexical
451
hexDigit.
unicodeMarker = "u" < "u" >. rawInputCharacter = "any Unicode character". lineTerminator = "LF" | "CR" | "CRLF". inputCharacter = unicodeInputCharacter "but not CR or LF". input = [ inputElements ] [ sub ]. inputElements = inputElement < inputElement >. inputElement = whiteSpace | comment | token. token = identifier | keyword | literal | separator | operator. sub = "the ASCII SUB character, also known as control-Z". whiteSpace = " " | "TAB" | "FF" | lineTerminator. comment = traditionalComment | endOfLineComment |
documentationComment.
traditionalComment = "/*" notStar commentTail. endOfLineComment = "//" < inputCharacter > lineTerminator. documentationComment = "/**" commentTailStar. commentTail = "*" commentTailStar | notStar commentTail. commentTailStar =
nullLiteral).
452
digit".
"abstract" | "default" | "if" | "private" | "throw" | "boolean" | "do" | "implements" | "protected" | "throws" | "break" | "double" | "import" | "public" | "transient" | "byte" | "else" | "instanceof" | "return" | "try" | "case" | "extends" | "int" | "short" | "void" | "catch" | "final" | "interface" | "static" | "volatile" | "char" | "finally" | "long" | "super" | "while" | "class" | "float" | "native" | "switch" | "const" | "for" | "new" | "synchronized" | "continue" | "goto" | "package" | "this".
integerLiteral =
digits = "0..9" < "0..9" >. hexNumeral = "0" ( "x" | "X" ) hexDigit < hexDigit >. hexDigit = "0..9" | "a..f" | "A..F". octalNumeral = "0" "0..7" < "0..7" >.
floatingPointLiteral =
( ( (digits "." [ digits ] | "." digits) [ exponentPart ] | digits exponentPart ) [ "f" | "F" | "d" | "D" ] ) | digits [ exponentPart ] ("f" | "F" | "d" | "D" ) .
exponentPart = ("e" | "E") [ "+" | "-" ] digits. booleanLiteral = "true" | "false". characterLiteral = "'" ( singleCharacter | escapeSequence ) "'". singleCharacter = inputCharacter "but not ' or \". stringLiteral = """ [ stringCharacters ] """. stringCharacters = stringCharacter < stringCharacter >. stringCharacter = inputCharacter "but not double quote or \" |
escapeSequence.
octalEscape ).
escapeSequence =
| "'" | "\" |
Niveau lexical
octalEscape =
453
"\" [ "0..3" ] [ "0..7" ] "0..7".
separator = "(" | ")" | "{" | "}" | "[" | "]" | ";" | "," | ".". operator = "=" | ">" | "<" | "!" | "~" | "?" | ":" | "==" | "<=" |">=" |"!=" | "&&" | "||" | "++" | "--" | "+" | "-" | "*" |"/" | "&" | "|" | "^" | "%" | "<<" | ">>" | ">>>" | "+=" |"-=" | "*=" | "/=" | "&=" | "|=" | "^=" | "%=" | "<<=" | ">>=" | ">>>=" .
Annexe C
456
Linterprtation de la balise <applet> entrane le chargement de la classe Jeu puis son excution. Lexcution de ce code contient une instruction pour instancier un objet de la classe LeMonde. Comme la machine virtuelle de Java fait du chargement dynamique, le chargement de cette classe sera effectu, puis lexcution reprendra. Et ainsi de suite. Finalement les cinq classes seront charges et le jeu continuera sans autres temps morts. En construisant un fichier .jar des classes charges par Jeu, on vite ces interruptions dans lexcution. On utilise loutil jar pour construire ce fichier. Dans notre cas, on peut excuter la commande suivante (la signification des paramtres cvf est explique en fin de chapitre) :
jar cvf Serpent.jar *.class
Loutil montre les classes quil inclut dans larchive ainsi que les gains obtenus grce la compression.
added manifest adding: Appat.class (in=876) (out=579) (deflated 33%) adding: Jeu.class (in=3021) (out=1683) (deflated 44%) adding: LeMonde.class (in=2008) (out=1163) (deflated 42%) adding: PointMobile.class (in=483) (out=336) (deflated 30%) adding: Serpent.class (in=1590) (out=900) (deflated 43%)
Dans un nouveau rpertoire, nous pouvons mettre les fichiers suivants, la page html et larchive .jar :
244 appletcodejar.html 3,797 Serpent.jar
457
Et la premire chose sera de charger larchive Serpent.jar. Ensuite, le butineur cherchera dans les classes charges celle demande dans loption code (dans notre cas Jeu.class), si elle sy trouve. Il commence alors lexcution de celle-ci. Sinon, il la charge en utilisant ventuellement loption codebase. Il existe une autre possibilit pour dclarer une archive. Cette archive peut tre spcifie dans les paramtres de lapplet (la balise <param>) :
<applet code=Jeu.class width=500 height=300> <PARAM NAME=ARCHIVES VALUE="Serpent.jar"> . . . </applet>
Il est possible de spcifier plusieurs archives lors du chargement de lapplet. Il suffit de sparer les noms des fichiers par un signe +.
<applet archives="Serpent.jar+Autres.jar" code=Jeu.class width=500 height=300> . . . </applet>
Lutilisation des archives est intressante dans les cas suivants : vous dsirez diminuer le temps de chargement de vos applets; vous dsirez simplifier la distribution dune application ou dun package; vous dsirez certifier et authentifier votre code. Remarque: lutilisation des archives nest pas toujours une optimisation du temps de chargement. En effet, si votre applet contient beaucoup de classes, gnralement peu dentre elles sont effectivement charges lors dune excution. En utilisant une archive, elles seront toutes charges alors que beaucoup ne seront pas utilises. Il faut dont choisir entre une solution optimiste et une solution pessimiste.
458
>jar Usage: jar {ctxu}[vfm0M] [jar-file] [manifest-file] [-C dir] files ... Options: -c crer une nouvelle archive -t lister le contenu d'une archive -x extraire les fichiers nomms(ou all) de l'archive -u mettre jour une archive existante archive -v generer une sortie longue sur la sortie standard -f spficier le nom de l'archive -m inclure des informations manifestes d'un fichier manifest spcifi -0 stocker seulement; pas de compression ZIP -M ne pas crer de fichier manifest pour les entres -C changer de directoire et inclure les fichiers suivants
Lauthentification et la scurisation du code sont galement possibles, mais le lecteur doit tre bien inform sur les mcanismes de scurit (cl publique, signature, etc.). Nous le renvoyons la documentation de Sun pour cet aspect particulier. Le dernier point souligner est que loutil jar peut tre utilis pour la compression de nimporte quel fichier, et pas seulement des fichiers .class. Vous pouvez aussi lutiliser comme nimporte quel autre outil de compression avec lavantage de la portabilit. Il permet notamment dassocier des images, des sons ou dautres ressources qui pourraient tre ncessaires lapplet, et qui seront donc distribues avec elle.
Annexe D
D.1 SGML
HTML (Hyper Text Markup Language) est issu dun systme beaucoup plus puissant appel SGML (Standard General Markup Language). SGML est un standard international pour la reprsentation de textes sous une forme informatise indpendante du systme et des priphriques daffichage (imprimantes, crans, etc.). Il sagit dun mtalangage qui permet de dfinir dautres langages bass sur les dlimiteurs (markup en anglais). La description obtenue est une DTD (Document Type Definition). HTML est ainsi une DTD de SGML. SGML sera appel dans le futur jouer un rle de plus en plus important pour la gestion des documents lectroniques, car sa description indpendante des plates-formes permet de manipuler facilement le texte et de structurer fortement les documents.
460
D.2 Dlimiteurs
Tags, balises, signets ou bornes sont autant de termes utiliss pour dsigner les dlimiteurs. Ceux-ci ont la forme gnrale suivante :
<Nom_Dlimituer> subit laction du dlimiteur </Nom_Dlimiteur>
Le nom du dlimiteur reprsente une action de structuration ou de mise en forme sur le texte qui le suit, jusqu lindication de la fin de laction </>. Certains dlimiteurs ne ncessitent pas de fin, comme par exemple <HR> qui indique une ligne horizontale. Il existe plusieurs standards HTML : les versions (1.0, 2.0 et maintenant 3.21) ainsi que les dialectes, soutenus par les acteurs du march du logiciel tels que Netscape ou Microsoft. Normalement, tous les butineurs actuels devraient supporter le HTML 2.0. Dans la suite de ce chapitre, nous signalons par lindication (*) les extensions propres au dialecte de Netscape, par ailleurs gnralement comprises par lInternet Explorer de Microsoft. Parmi ces extensions, les suivantes sont prises en compte dans la norme 3.2 : les tables; le dlimiteur APPLET; lcoulement du texte autour des images (ALIGN); les indices et les exposants (SUB, SUP).
Dlimiteurs de structuration
Les dlimiteurs suivants (voir tableau D.1) permettent dindiquer un minimum de structuration pour un document HTML.
Dlimiteur
<HTML>...</HTML> <!...> <HEAD>...</HEAD> <TITLE>...</TITLE> <BODY>...</BODY> <Hi>...<Hi>
Signification Type du document Commentaire En-tte du document (non affich) Titre du document (non affich) Corps du document Titres de niveau : i =1 6 Tableau D.1 HTML, dlimiteurs de structuration
Dlimiteurs
Dlimiteur
<P>...</P> <BR> <HR>
461
Signification Paragraphe Rupture de ligne Ligne horizontale de sparation Tableau D.1 HTML, dlimiteurs de structuration
462
Limage obtenue dans un butineur permet dobserver que les titres, les ruptures de lignes et les fins de paragraphes sont bien respects.
Dlimiteurs de listes
Les dlimiteurs suivants (tableau D.2) permettent de structurer des listes ayant diffrentes prsentations.
Dlimiteur
<UL> <LI> <LI> </UL> <OL> <LI> <LI> </OL> <DL> <DT> <DD> </DL> <UL TYPE=disc | circle | square> (*) <OL TYPE=a | A | i | I | 1 |> (*)
Signification UL - Unnumbered List LI - List Item Liste non numrote OL - Ordered List LI - List Item Liste numrote DL - Definition List DT - Definition Title DD - Definition Description Liste de dfinition Type de mise en vidence (disque, cercle, carr) Type de numrotation
Dlimiteurs
et encore <UL>Listes OUX <LI>bijoux <LI>cailloux <LI>poux <LI>... </UL> et enfin <DL> Ici quelques dfinitions importantes <DT>Classe <DD>Une classe est une description .... <DT>Interface <DD>Une Interface est une description .... </DL> </BODY> </HTML>
463
464
quils sont orients vers des documents de programmation. Exemple dattributs logiques (ex3.html) :
Dlimiteur
<EM>...</EM> <STRONG>...</STRONG> <CITE>...</CITE> <KDB>...</KDB> <SAMP>...</SAMP> <VAR>...</VAR>
Signification Mise en vidence (EMphase). Mise en vidence forte. Citation. Entre au clavier. Exemple. Variable.
Nous obtenons limage de la figure D.3 : le choix dun type de caractres et de son style repose sur linterprteur HTML.
Dlimiteurs
465
Signification Gras. Italique. (TeleType) fonte non proportionnelle (courrier) respecte les retours de ligne. Variable en exposant, au-dessus de la ligne de base. Variable en indice, en dessous de la ligne de base. Spcifie la taille de la fonte par rapport une chelle relative de 1 7 et la couleur en hexadcimal.
Nous obtenons limage de la figure D.4 : le choix dun type de caractres et de son style repose sur les indications du concepteur de la page. Nanmoins, ces aspects esthtiques tant fortement dpendants des butineurs, il est conseill de les utiliser avec parcimonie.
466
Signification Dfinit la rpartition de la zone en colonnes ou en ranges. La rpartition est : absolue (n) en points, en pourcentage (n%), relative (*,n*). Les FRAMESET peuvent tre imbriqus les uns dans les autres. Ce dlimiteur est contenu dans un FRAMESET, il donne un nom une zone et indique lURL pour charger son contenu; les autres paramtres concernent la taille des marges la sparant des autres zones, les ascenseurs de dfilement de la zone et la possibilit de la redimensionner (avec la souris, vous pouvez redimensionner une zone en vous positionnant sur lune de ses marges). Le texte mis entre ces deux dlimiteurs sera excut si le navigateur ne connat pas le concept de FRAME. Cela permet donc de donner aussi accs ces pages quelquun qui ne possde pas de navigateur adapt. Tableau D.5 HTML, dlimiteurs de zones dcran
Dlimiteurs
467
La figure D.5 illustre lexcution avec un butineur connaissant le concept de FRAME, et avec un second qui ne le connat pas. Conserver une quivalence de navigation en programmant une double interprtation des pages HTML peut tre un exercice coteux.
468
Signification Dfinit une ancre lintrieur du document. La partie comprise entre les deux dlimiteurs est la zone rfrence. Lien vers un autre URL (document ou ventuellement intrieur du mme document). La partie comprise entre les deux dlimiteurs dfinit le texte du lien dans le document appelant (gnralement soulign). Lien vers un autre URL (document) afficher dans la sous-fentre dsire.
Exemple : ex6a.html
<HTML> <HEAD><TITLE>liste importante ex6a </TITLE></HEAD> <BODY> <A href="ex6.html">sommaire</A><P> <H1>liens hypertextuels</H1> <H2>liens hypertextuels</H2> item 1<P> item 2<P> <a href="#java">liens sur java</A><P> item n<p> ...<p> <A name="#java"><H2>JAVA</H2></A> ... <A href="http://java.sun.com/">sun et java</A><P> ... </BODY> </HTML>
Dlimiteurs
469
Nous obtenons limage suivante pour le document ex6.html. En cliquant sur ici, on charge le document ex6a.html. En cliquant sur sommaire, on retourne ex6.html. En cliquant sur liens sur java, on avance dans le document jusqu la zone de rfrence. En cliquant sur sun et java, on charge la home page du serveur Sun.
Signification Permet dinsrer une image dans le document en indiquant lURL dsignant limage. ALIGN permet de positionner limage par rapport la ligne de texte courante. ALT permet de donner un texte pour les navigateurs naffichant pas dimage.
470
Dlimiteur
<IMG SRC="URL" WIDTH=".." HEIGHT=".." VSPACE=".." HSPACE=".." ALIGN="right | left" BORDER="number"> <IMG SRC="URL" ISMAP>
<BODY BACKGROUND="image.gif">
Limage suivante (figure D.7) montre le rsultat obtenu. Il est aussi possible de dfinir des ancres avec des images en lieu et place du texte du lien.
Dlimiteurs
471
Signification Dfinit la source de la zone sensible et associe le nom de la dfinition de la carte. Dfinit la carte en lui associant plusieurs rgions dont les coordonnes sont relatives limage associe. Pour chaque zone sensible, on dfinit sa forme et les coordonnes de la zone : rect="x1,y1,x2,y2" circle="ox,oy,rx,ry" poly=" x1,y1, ..., xn,yn" HREF le lien activer NOHREF permet de dfinir des zones insensibles.
<AREA SHAPE="rect | poly | circle" COORDS= x1,y1, ..., xn,yn HREF="URL" NOHREF>
472
carte d'accs<img src="image8.gif" usemap=#demo> <MAP NAME="demo"> <AREA SHAPE="circle" HREF="ex4.html" COORDS=25,25,35,35 > <AREA SHAPE="rect" HREF="ex5.html" COORDS=0,50,50,100 > <AREA SHAPE="rect" HREF="ex6.html" COORDS=50,0,100,50 > <AREA SHAPE="rect" HREF="ex7.html" COORDS=50,50,100,100 > </MAP> </BODY> </HTML>
La carte ci-dessous permet daccder quatre liens dfinis dans les zones.
Signification Dfinit un formulaire, sa mthode dchange et lURL de lapplication destinataire (gnralement une extension .cgi). Entre les deux dlimiteurs, on trouve du texte et les objets de formulaire. Lattribut name sera le nom du paramtre envoy lapplication. Bouton dclenchant lexcution du formulaire (envoi des paramtres). Bouton rinitialisant le formulaire (vide les champs).
Dlimiteurs
Dlimiteur
<INPUT TYPE="text" SIZE=... NAME="nom_champ" VALUE="val initiale"> <INPUT TYPE="password" SIZE=... NAME="nom_champ" VALUE="val initiale"> <INPUT TYPE="radio" NAME="nom_bouton" VALUE="valeur_retourne" CHECKED> <INPUT TYPE="checkbox" NAME="nom_du_groupe" VALUE="valeur_retourne" CHECKED> <SELECT NAME="nom_liste" SIZE=... MULTIPLE> ... </SELECT> <OPTION> text <TEXTAREA NAME="nom_zone" ROWS=n COLS=n >t exte initial </TEXTAREA>
473
Signification Champ permettant lentre de texte sur une ligne de taille dfinie.
Affichage dune case cocher dans un groupe. La concatnation des valeurs des cases est retourne.
Permet dafficher des menus droulants si SIZE est absent, ou bien des listes ascenseurs de la taille SIZE. MULTIPLE indiquant dans ce cas si lon autorise des choix multiples. Entre les deux dlimiteurs, on donne les options afficher. lment de la liste. Ce dlimiteur permet de dfinir une zone de texte multilignes
474
Je m'intresse <INPUT TYPE="radio" NAME="int1" VALUE="java" CHECKED>Java <INPUT TYPE="radio" NAME="int2" VALUE="java-script" >Java script <INPUT TYPE="radio" NAME="int3" VALUE="html" >HTML<p> Je dsire l'information par: <INPUT TYPE="checkbox" NAME="media" VALUE="disk"> disquette <INPUT TYPE="checkbox" NAME="media" VALUE="email" CHECKED>e-mail <INPUT TYPE="checkbox" NAME="media" VALUE="cd"> CD-ROM<p> niveau d'information <SELECT NAME="niveau"> <OPTION> dbutant <OPTION> moyen <OPTION> avanc </SELECT> systme utilis <SELECT NAME="syst" SIZE=4 MULTIPLE> <OPTION> Mac-PowerPC <OPTION> SUN solaris 2.5 <OPTION> PC Linux <OPTION> PC Window 3.xx <OPTION> PC Window 95 <OPTION> PC Window NT <OPTION> dbutant </SELECT><p> Commentaires <TEXTAREA NAME="com" ROWS=3 COLS=40 >placer vos commentaires ici</TEXTAREA> <hr> </FORM> </BODY>
Nous obtenons le formulaire de la figure D.9. On notera lutilisation dune image de fond dcran. Lors de lactivation du bouton Executer, la chane suivante va tre envoye au serveur HTTP qui activera lapplication (cette dernire dcodera la liste des paramtres pour la traiter).
http://xx.xx.xx.xx/HD500/Desktop%20Folder/JAVA/javadoc/ Exemples%20HTML/ application.cgi?nom=Guyot+Jacques&mail=guyot@acm.org&pwd=cach%8E&i nt1=java&media=email&media=cd&%D3niveau%D3=moyen&%D3syst%D3=SUN+so laris+2.5&%D3com%22=placer+vos+commentaires+ici
Dlimiteurs
475
Signification Dfinit une table dont la taille (WIDTH) est spcifie en %. BORDER spcifie la largeur du bord. CELLPADDING spcifie lespacement entre le contenu de la cellule et son bord. CELLSPACING dfinit lespacement entre deux cellules. Les cellules sont dfinies entre les deux dlimiteurs. Associe un titre au tableau qui se place au-dessus ou en dessous de celui-ci.
Dfinit une ligne et les attributs par dfaut pour cette ligne tels que lalignement vertical ou horizontal.
476
Dlimiteur
<TH VALIGN= top | middle | bottom ALIGN= left | center | bottom COLSPAN=n ROWSPAN=n NOWRAP> ... texte de lentte <TD VALIGN= top | middle | bottom ALIGN= left | center | bottom COLSPAN=n ROWSPAN=n NOWRAP> ... texte dune cellule
Dlimiteurs
477
<TR VALIGN= middle ALIGN= left > <TD> a <img src="image7.gif" align=middle><TD> b<TD> c<TD> d </TR> </TABLE> </BODY> </HTML>
La figure D.10 montre la construction de deux tableaux, lun trs simple, lautre un peu plus complexe.
Annexe E
JavaScript
JavaScript1 est un langage dvelopp par les socits Sun Microsystems et Netscape. JavaScript ressemble Java, mais il ne possde ni le typage statique ni la vrification des types. Les expressions et les instructions de contrle sont pratiquement identiques. JavaScript est entirement interprt, il ny a donc pas de phase de compilation comme dans Java. JavaScript est vu comme un complment de HTML; il permet dinclure du code directement dans un document HTML, alors que dans Java, on indique uniquement la source du code excuter. Le tableau E.1 ci-dessous souligne les principales diffrences entre les deux langages.
JavaScript Interprt directement par le client. Bas sur les objets, utilise et tend des objets prexistants, pas de classes ni dhritage. Code incorpor dans le document HTML. Java Compil puis charg depuis le serveur par le client. Langage orient objet, hritage, etc. Code spar mais rfrenc par le document HTML.
1.
480
JavaScript Pas de dclaration des variables. Application limite la taille du document HTML. Performance limite due linterprtation. Dveloppement ne ncessitant quun butineur interprtant JavaScript. Java
Annexe A JavaScript
Dclaration des variables et typage fort. Permet de grer des projets de taille importante. Performance limite par le processeur du poste client (si lon utilise la recompilation du byte-code en code natif). Dveloppement ncessitant le kit de dveloppement avec le compilateur.
Les objets manipuls par JavaScript sont ceux qui existent dans la page HTLM (les boutons, les champs, etc.). Le programme JavaScript est li ces objets afin de traiter les vnements qui en sont mis. Nous pensons quun programmeur Java peut sans peine programmer en JavaScript. Il lui faudra sinformer sur les diffrents gestionnaires dvnements construits autour des composants graphiques de HTML et sur les diffrentes librairies, Math par exemple. Nous donnons ci-dessous (voir figure E.1) un petit exemple de document HTML incluant du JavaScript pour confirmer notre propos : on remarquera labsence des points-virgules; en effet, une ligne est gale une instruction; le programme est structur en deux parties : dans la premire on dcrit la fonction calculF() qui vrifie la validit des caractres en entre, dans la seconde on spcifie le gestionnaire de lvnement onChange() attach au champ nombreATraiter.
<HEAD> <TITLE>Exemple en JavaScript</TITLE> <SCRIPT LANGUAGE="JavaScript"> <!---cach pour les butineurs ne connaissant pas JavaScript function calculF(s) { if (s == "") { alert("Entrez un nombre entier dans le champ SVP") return true } for (var i = 0; i < s.length; i++) { var ch = s.substring(i, i + 1) if (ch < "0" || ch > "9") { alert("Un nombre entier sans decimale") return true } }
Dlimiteurs
var val = parseInt(s, 10) racine=Math.sqrt(val) alert("racine carre de("+val+")="+racine) return false } // fin du code --> </SCRIPT> </HEAD> <BODY> <h1> Calcul de la racine carre</h1> <FORM NAME="ExempleJavaScript"> Entrez un nombre entier puis <RETOUR>: <INPUT NAME="nombreATraiter" onChange="if (calculF(this.value)) {this.focus();this.select();}"> </FORM> </BODY>
481
Glossaire
Adresse lectronique
Nom dutilisateur et de machine permettant une personne de recevoir du courrier lectronique (ex : dupont@moulinsart.be).
Adresse IP
Adresse affecte toute machine connecte lInternet, compose du numro du rseau et de machine (ex : 193.124.56.99). Les plages dadresses sont attribues par une organisation (InterNic Register).
API
(Application Programming Interface) Spcification de linterface de programmation dun systme, ensemble de classes et de mthodes dcrivant ses fonctionnalits.
Applet
Une applet est un petit programme crit en Java devant tre invoqu depuis une page HTML.
Archie
Outil permettant la recherche de fichiers sur un ensemble de sites FTP.
Archive
Ensemble de fichiers regroups et compresss pour la transmission (PC : fichiers .zip; Mac, Unix : fichiers .tar et .gz).
Butineur
Logiciel de navigation sur le Web, permet dinterprter les documents rdigs selon la syntaxe HTML et le code des programmes Java.
484
Glossaire
Byte-code
voir Pseudocode.
Champ
(Field) Variables et mthodes dune classe.
Classe
Unit de base dun programme Java. Linstanciation dune classe cre un objet ayant le comportement dfini dans la classe.
Client
Systme (gnralement un poste de travail) qui utilise les services dun autre systme (un serveur).
Code natif
Code que le processeur de la machine physique peut directement excuter, par opposition au pseudocode qui doit tre interprt par une machine virtuelle.
Compilateur
Logiciel permettant la compilation.
Compilation
Action transformant le code source dun programme Java en pseudocode pour la machine virtuelle Java.
Constructeur
Mthode permettant de crer une instance dune classe.
CORBA
(Common Object Request Broker Architecture) Norme qui dfinit linteroprabilit et la connection entre des objets rpartis.
E-mail
Courrier lectronique (adresse lectronique, logiciel client-serveur pour accder aux messages, SMPT).
Exception
Survenance dun vnement qui signale gnralement une anomalie lexcution. Par extension, code qui traite lanomalie.
FAQ
(Frequently Asked Questions) Document regroupant des questions de base sur un domaine particulier.
485
FTP
(File Transfer Protocol) Protocole de transmission de fichiers entre deux systmes connects Internet.
Garbage collection
voir Ramasse-miettes.
GUI
(Graphical User Interface) Ensemble de rgles et dobjets qui dfinissent la construction des interfaces utilisateur.
Hritage
Concept de la programmation objet qui permet de construire une nouvelle classe en tendant le comportement dune autre, sans en redfinir toutes les mthodes. La nouvelle (sous-) classe hrite le comportement de sa (super-) classe.
HotJava HTML
Le butineur de Sun Microsystems, premier butineur capable dexcuter du code Java. (Hyper Text Markup Language) Langage permettant de dcrire des hyperdocuments (dont le contenu est multimdia et inclut des liens hypertexte). Objet ayant le comportement de la classe dont il est linstance.
Internet
Historiquement dfini comme le protocole de communication TCP/IP, mais devient de plus en plus synonyme de lensemble des services et des machines connects laide de ce protocole.
Interprtation
Action qui, pour chaque pseudocode, excute les oprations ncessaires (simule la machine virtuelle dfinie par le pseudocode).
Intranet
Utilisation des techniques lies lInternet pour une communaut restreinte (gnralement une entreprise).
486
Glossaire
Java
Langage de programmation orient objet qui permet dinvoquer des programmes depuis des documents HTML et dcrire des applications portables.
JavaScript
Langage de programmation orient objet permettant dinsrer des programmes dans des documents HTML (ici le code est inclus dans le document HTML, la diffrence de Java o seule linvocation est dans le document).
JDBC
(Java DataBase Connectivity) Ensemble dinterfaces Java permettant dinteragir avec des systmes de gestion de bases de donnes relationnelles.
JDK
(Java Development Kit) Kit de dveloppement Java, comprenant un compilateur, un interprteur, la Core API, un appletviewer, etc.
Machine virtuelle
La machine virtuelle de Java est linterprteur du pseudocode. Elle en assure la portabilit et la scurit.
Mthode
Unit de comportement dun objet (dfini dans sa classe).
Multiprocessus
Programme dont la description fait appel des activits concurrentes reprsentant chacune un processus.
Multithread
Voir Multiprocessus.
Navigateur
Voir Butineur.
NCSA
(National Center for Supercomputer Applications) Lorganisation qui a dvelopp le premier butineur grand public (Mosaic pour Macintosh et PC).
Objet
Possde diffrentes dfinitions selon le contexte : 1) instance de classe; 2) par extension, la classe elle-mme; 3) par extension,
487
utilis comme adjectif : programmation objet, dveloppement objet, base de donnes objet, etc.
ODMG
(Object Database Management Group) Consortium de vendeurs de systmes de gestion de bases de donnes orientes objet qui proposent des standards en matire de langage dinterrogation et de format des objets.
Package
En Java, regroupement de classes dun mme domaine fonctionnel.
Pointeur
Donne dont la valeur est une adresse (gnralement un entier pointant sur un emplacement mmoire).
Processus
Il faut distinguer entre : processus lourd, activit au sein dun systme dexploitation et processus lger, sous-activit dun processus lourd. Nous faisons toujours rfrence des processus lgers lorsque nous parlons de processus.
Pseudocode
Mthode pour reprsenter le jeu dinstructions dune machine virtuelle ; assure lindpendance vis--vis de la machine physique. Le compilateur Java gnre du pseudocode.
Ramasse-miettes
Programme permettant de rcuprer la mmoire occupe par des instances dobjets qui ne sont plus rfrences et de compacter la mmoire.
RMI
(Remote Method inovation) Modle de distribution dobjets de Java facilitant leur implantation sur des machines diffrentes.
Serveur
Systme qui fournit des services dautres systmes (voir Client).
SGBD
(Systme de Gestion de Bases de Donnes) Logiciel capable de grer une masse dinformations, den faciliter laccs et den garantir la cohrence et la persistance.
SGML
Langage de dfinition pour des langages comme HTML et VRML.
SMTP
(Simple Mail Transfert Protocol) Protocole dfinissant les services de base du courrier lectronique.
Sous-classe
Classe drive partir dune autre classe (super-classe).
Super-classe
Classe tendue par une autre classe (sous-classe).
Surcharge
Concept permettant dassocier plusieurs dfinitions au mme identificateur. En Java, seules les mthodes peuvent tre surcharges (mais pas les oprateurs).
TCP/IP
(Transmission Control Protocol/Internet Protocol) Protocole de transmission entre rseaux. Dfinition dInternet.
Tlcharger
(Download) Transfrer un fichier dun systme un autre (gnralement dun serveur vers un poste utilisateur).
Telnet
Protocole de connexion entre une machine client (en mode mulation de terminal) et une machine serveur.
Thread
Voir Processus.
Unicode
Jeu de caractres dfini sur 16 bits (norme ISO 10646).
489
URL
(Uniform Resource Locator) Chaque document du Web a une identit unique sur lInternet (forme gnrale : protocole:/hte/rpertoire/document.html?param). LURL permet didentifier dautres services Internet, comme FTP par exemple.
Vecteur
(Array) Ensemble dobjets dsigns par un indice entier.
Web
Voir WWW.
WWW
(World-Wide Web) Aussi appel W3 ou Web. La partie hypertextuelle dInternet (Butineur, HTML, HTTP, URL).
Rfrences
[1] [2] [3] [4] [5] [6] [7] [8] [9] Bergstra J. A, Heering J., Klint P. (eds.). Algebraic Specification, Addison Wesley, 1989. Booch. G. Software Components with Ada : Structures, Tools, and Subsystems, Benjamin/Cummings, 1987. CERN : Laboratoire europen pour la physique des particules, Genve. URL : http://www.cern.ch JDBC : A Java API, JavaSoft. URL : http://www.javasoft.com. Jones C. Systematic software development using VDM, Prentice Hall, 1986. Meyer B. Conception et programmation par objets : pour du logiciel de qualit, Interditions, 1991. Meyer B. The many faces of inheritance : A taxonomy of taxonomy, IEEE Computer, Vol. 29, No. 5, mai 1996. Network Wizards (statistiques propos dInternet). URL : http://www.nw.com. ODMG : Object Database Management Group. URL : http://www.odmg.org.
[10] Spivey J. M.. The Z notation : A reference manual : based on the work of J. R. Abrial, Prentice Hall, 1992. [11] Stroustrup B. The Design and Evolution of C++, Addison Wesley, 1994.
492
Rfrences
[12] Thomas P., Robinson H., Emms J. Abstract Data Types : Their Specification Representation and Use, Oxford Applied Mathematics and Computing Science Series, 1988. [13] The Unicode Consortium. URL : http://www.unicode.org [14] The W3 consortium. URL : http://www.w3.org Le lecteur intress par les aspects sociaux lis lintroduction de technologies telles que Java trouvera matire rflexion dans les livres ou documents lectroniques suivants : Terminal : technologies de linformation, culture et socit. Revue trimestrielle publie et diffuse par les ditions lHarmattan. http://terminal.ens-cachan.fr/Terminal/serveurText/index.html Le Monde diplomatique : publie rgulirement des articles sur la mondialisation, les enjeux conomiques, politiques et sociaux de lutilisation des nouvelles techniques. http://www.monde-diplomatique.fr/index.html Paul Virilio : dans Lart du moteur et Cybermonde, la politique du pire, il met en garde la socit contre les logiques sous-jacentes lacclration des techniques et lisolation des individus dans des socits trs ou trop informatises. Pierre Lvy : travers plusieurs livres dont Lintelligence collective, pour une anthropologie du cyberspace, il mne une rflexion sur lhomme, ses outils de cognition et la transformation des socits par la technologie. Philippe Queau : il dcrit dans Le Virtuel les risques et les bnfices des techniques bases sur la simulation. Jean Baudrillard : reconnu comme le thoricien du postmodernisme. Sherry Turkle : dans Life on the screen, elle tablit un rapport entre le postmodernisme, lindividu et les techniques lies Internet.
494
29. Capter la position de la souris 3-168 30. Une applet de brouillon pour dessiner 3-170 31. Gestion du clavier 3-172 32. Affichage, les libells 3-181 33. Affichage, les boutons 3-182 34. Affichage, les botes cocher 3-185 35. Affichage, les botes cocher en mode exclusif 3-187 36. Affichage, les menus droulants (phase de slection) 3-188 37. Affichage, les listes de choix 3-190 38. Affichage, les champs de texte sur une ligne 3-193 39. Affichage, les champs de texte sur plusieurs lignes 3-194 40. Deux barres de dfilement dterminent les angles de vue 3-197 41. Dessiner et afficher les coordonnes dans un champ de texte 3-201 42. Gestion dun champ de texte dans une fentre spare 3-202 43. Applet lance deux fois par une application Java 3-204 44. Cration et utilisation de menus 3-206 45. Une alerte gre dans une fentre spare 3-208 46. Mise en pages glissante 3-211 47. Mise en pages glissante sadaptant la taille du conteneur 3-211 48. Mise en pages par spcification des bords 3-213 49. Mise en pages imbrique 3-214 50. Mise en pages laide dune grille 3-215 51. Contrainte de mise en pages dfinie laide dune mthode 3-218 52. Chargement de trois images 3-223 53. Travelling sur une image 3-225 54. Affichage laide dun double tampon 3-229 55. Le jeu du serpent 4-310 56. Une applet utilisant RMI 395 57. Gestion de compte en banque avec CORBA 407
498
29. Mthodes de la classe Label 3-181 30. Mthodes de la classe Button 3-182 31. Mthode de la classe ActionEvent 3-183 32. Mthodes de la classe Checkbox 3-185 33. Mthodes de la classe Checkbox utilisant la notion de groupe 3-187 34. Mthodes de la classe CheckboxGroup 3-187 35. Mthodes de la classe Choice 3-188 36. Mthodes de la classe List 3-190 37. Mthodes de la classe TextComponent 3-191 38. Mthodes de la classe TextField 3-193 39. Mthodes de la classe TextArea 3-194 40. Mthodes de linterface LayoutManager 3-210 41. Constructeurs de la classe FlowLayout 3-212 42. Constructeurs de la classe BorderLayout 3-212 43. Constructeurs de la classe GridLayout 3-216 44. Constructeurs de la classe CardLayout 3-216 45. Variables dinstance de la classe GridBagConstraints 3-217 46. Mthodes de chargement dune image (classe Applet) 3-222 47. Mthodes de la classe Applet pour jouer un son 3-229 48. Mthodes de linterface AudioClip 3-230 49. Diffrences principales en AWT et Swing 3-233 50. Nouveaux composants introduits dans Swing 3-235 51. Interfaces et implantations des collections 4-328 52. Mthodes de linterface Set 4-329 53. Oprations de linterface List 4-331 54. Oprations du type Map 4-333 55. Table des droits de communication 4-371 56. Interfaces de lAPI JDBC 374 57. Fonctions des interfaces pour les requtes SQL 376 58. Fonctions des API 411 59. Les types numriques en Java 421 60. Test de linitialisation de variables en Java et en C++ 422 61. Dclaration de tableaux 423 62. Initialisation de tableaux dobjets 424 63. Porte des variables dclares dans le for 425 64. Instructions for en Java et en C++ 425 65. Instruction continue en Java et en C++ 426 66. Traces dexcution : gestion des rfrences 431 67. Spcification de la visibilit dans Java et C++ 434 68. Accs aux variables et mthodes de classe 436 69. Spcification dattributs constants 436 70. Clonage en Java 437
499
71. Appel aux constructeurs des composantes 438 72. Modes dhritage en Java et en C++ 439 73. Spcification de lhritage en Java et en C++ 439 74. Mthode virtuelle avec corps 440 75. Spcification de classe abstraite (virtuelle) 440 76. Dclaration des exceptions leves par une mthode 441 77. Propagation dune exception en cours de traitement 442 78. HTML, dlimiteurs de structuration 460 79. HTML, dlimiteurs de listes 462 80. HTML, dlimiteurs dattributs logiques textuels 464 81. HTML, dlimiteurs dattributs typographiques 465 82. HTML, dlimiteurs de zones dcran 466 83. HTML, dlimiteurs dancres et de liens 468 84. HTML, dlimiteurs de manipulation dimages 469 85. HTML, dlimiteurs dimages cliquables 471 86. HTML, dlimiteurs de gestion de formulaires 472 87. HTML, dlimiteurs de gestion de tableaux 475 88. Principales diffrences entre JavaScript et Java 479
Index
! 58 - 53 != 56 $ 43 & 58 && 57 (3 */ 41 ++ 53 .class 97 .java 97 /* 41 /** 42 // 42 < 56 <- 56 = 53 == 56, 325 > 56 >- 56 [ ] 102 ^ 58 _ 43 {} 66 | 58 || 57 ~ 53 2D 141 3D 139
abstract (modificateur dinterface) 01 abstract (modificateur de classe) 101 accept() 246, 267 accs exclusif 107, 355 accessibilit, rgles 343 actif 353 ActionEvent (vnement) 181 ActionListener (vnement) 181 add() 143, 179, 199 AddItem() 190, 191 addLayoutComponent() 210 addMouseMotionListener() 173 addSeparator() 205 AdjustmentEvent (vnement) 195 AdjustmentListener (vnement) 195 adresse Internet 266 IP 5, 11 affectation 87 Affichage 271 algorithmes en Java 73 alignement du texte 180 allocation 60 allowMultipleSelection() 190 AltaVista 36 analyse lexicale 259 syntaxique 259 ancre, dhypertexte 7
502
Index
animation 227 API 373 Java 111 JDBC 374 appendText() 194 applet 11, 31, 33, 119, 203, 381 cration 120 cycle de vie 126 dans une application 202 gestionnaire de contenu 360 intgration 359 invocation 119 paramtrable 361 Applet (classe) 221 application 33, 119, 203, 381 client-serveur 265 arc, dessiner 133 architecture 301 portable 24 argument 80 ArrayIndexOutOfBounds (classe) 106 assignation 53, 86 attente 355 AudioClip (classe) 229 available() 247 avoir, hritage 319
BorderLayout (classe) 212 BorderLayout() 212 boucle 69, 73 bouton 181 de navigation 216 break 68, 71, 72 BufferedInputStream (classe) 242 BufferedReader (classe) 242 BufferedWriter (classe) 242 butineur 8, 11, 33, 119 Button (classe) 181 Button() 182 byte-code 22, 363
balise 9, 359, 459 barre de dfilement 195 de menus 205 base de donnes 29, 373 bean 347 proprit 349 bloc dinstructions 66, 78 imbriqu 51 bote cocher 184 exclusive 186 Boolean (classe) 95 boolen 44, 49
C 16 pointeur 380 type 380 void * 380 C++ 16, 415 #ifndef...#endif 418 #include 418 affectation 430 de rfrence 431 boolean 416 break 428 char 421 class 421 const 436 constante 422 constructeur 437 continue 426 dfinition de classe 432 des attributs 432 des mthodes 433 dsignateur 432 destructeur 425 do 426 enum 421 fonctions membres 415 for 425
503
goto 427 header file 415, 418 hritage 438 int 416 main 417 mthode virtuelle 437 oprateur de rsolution de porte 435 private 434, 435, 439 protected 439 public 434, 439 qualification des attributs 434 rfrence 430 static 435 struct 421 union 421 unsigned 416, 421 variable 422 dinstance 432 de classe 432 virtual 439 while 426 CallableStatement, JDBC 377 Canvas (classe) 197 caractre 46, 50 de contrle 46 CardLayout (classe) 216 CardLayout() 216 cas (instruction switch) 67 cas, traitement 317 case 67 catch 105, 149 cercle, dessiner 132 chane de caractres 47, 59, 135 comparaison 94 champ (membre) 102 champ de texte sur plusieurs lignes 193 sur une ligne 191 Character (classe) 95 chargement du code 22 charWidth() 138
Checkbox (classe) 184 Checkbox() 185, 187 CheckboxGroup (classe) 186 CheckboxGroup() 187 CheckboxMenuItem (classe) 205 chemin, mcanisme dimportation 98 Choice (classe) 187 classe 19, 77, 100, 292 abstraite 89, 91, 101, 316 anonyme 91, 174 comme objet 293 conception 289 enveloppe 95 et concept 301 et modlisation 301 et package 341 finale 89, 101 interne 90 publique 342 spcification 294, 296 clavier, gestion 176 clearParameters() 377 clearRect() 133 client universel 28 client WWW 11 client-serveur 13, 26 ralisation avec java.net 274 tl-discussion avec java.net 278 clipRect() 227 clonage de surface 338 profond 338 clone() 94 Cloneable (interface) 216 code interprt 22 mobile 25, 29 robuste 23 collection (structure de donnes) 331 Color (classe) 134 commentaire 41 commit() 376
504
Index
compatibilit de type 48 compilation 97, 120 Component (classe) 165 comportement 19, 21, 77 composant AWT 233 Swing 233 composant graphique 147, 179 lger 231 concatnation 58 concept, implmenter 301 conception 289, 301 concurrence daccs 354 Connection (interface JDBC) 376 consommateur (processus) 356 constante 48 constructeur 79, 80, 81 Container (classe) 199 conteneurs 199 Swing 232 ContentHandler (classe) 266 ContentHandlerFactory (interface) 269 continuation (instruction) 73 continue (mot-cl) 73 contrainte, mise en pages 216 controlDown() 171 conversion de type 20, 61 copie dobjet 94, 338 copyArea() 133 cosinus 130 couleur du dessin 135 du fond 134 palette 134 countComponent() 199 courrier lectronique 6 createImage() 224 CropImageFilter (classe) 224 curseur, JDBC 379 cycle de dveloppement 32
DatagramPacket (classe) 266 DataInputStream (classe) 243 DataOutputStream (classe) 243 Date (classe) 145 dcalage binaire 59 dclaration dune interface 101 de classe 100 default 68 DELETE (ordre JDBC) 379 dlimiteur APPLET 119, 121 dlimiteur HTML 9, 459 delItem() 190 deselect() 190 destroy() 127 Dialog (classe) 199, 206 Dictionary (classe) 321 Dimension (classe) 129 dispose() 201 distribution des logiciels 14 do 69, 72, 73 do...while 69 document 359 contenu 359 dynamique 27, 360 HTML 119 domaine, importation 98 Double (classe) 95 double prcision 46 draw3DRect() 132 drawArc() 133 drawImage() 222 drawLine() 130 drawOval() 133 drawPolygon() 132 drawRoundRect() 131 drawString() 135
505
chec, jeu 360 echoCharIsSet() 193 effet de bord 53 galit 94 de surface 337 entre objets 337 profonde 337 else 66 encapsulation 289, 333, 343, 357 encodage des caractres 22 ensemble (structure de donnes) 329 entier 45, 49 entre-sortie 241 affichage sur cran (out) 247 exceptions 246 saisie de caractres (in) 247 environnement de dveloppement 31 de programmation 111 EOFException (classe) 246 equals() 94, 326 proprits 337 Error (classe) 106 est un (lien) 319 et (oprateur) 58 vnement adaptateur 174 clavier 176, 197 couteur 172 et Java Beans 348 gestion 172 modle 172 slection dans un menu 206 source 172 souris 173, 197 type 168, 177 vnement (1.0) clavier 170
gestion 168 modle 165 souris 167, 172 Event (classe) 165, 170 exception 105, 299 hirarchie 301 propagation 300 executeQuery() 378 excution conditionnelle 66 itrative 69 Exite 36 expression valuation 53 numrique 54 extends (mot-cl) 85
factorisation 318 false 44 fentre 199, 201 fichier accs direct 257 afficher le contenu 253 byte-code 32 copie 255 entre dun rpertoire 252 fentre de dialogue 260 filtrage des noms 261 filtre 252 rpertoire 250 sparateur de rpertoire 248 source 32 Fichier (classe) 248 fichier dentre 246 constructeurs 246 FichierEcriture (classe) 249 FichierLecture (classe) 249 fil dexcution 353 File (classe) 244, 248 FileDescriptor (classe) 244 FileDialog (classe) 200, 260
506
Index
FileInputStream (classe) 243 FileNameFilter (interface) 252, 253 FileNotFoundException (classe) 246 FileOutputStream (classe) 243 FileReader (classe) 243 FileWriter (classe) 243 fill3DRect() 132 fillArc() 133 fillOval() 133 fillPolygon() 132 fillRoundRect() 131 FilteredImageSource (classe) 224 final (modificateur de classe) 101 finalize() 82 finally 105 first() 216 float 46 Float (classe) 95 flottant 45, 50 FlowLayout() 212 fonction (structure de donnes) 332 fond 197 Font (classe) 136 fonte, Voir police for 70, 72, 73 Frame (classe) 199, 201 FTP (File Transfer Protocol) 4
garbage collector, Voir ramasse-miettes gnrer des exceptions 106 gnricit 322 gestion de la mmoire 20, 364 getAlignment() 181 getAscent() 138 getAudioClip() 229, 230 getBackground() 134 getCodeBase() 222 getColor() 135 getColumns() 193, 195 getComponent() 199
getContent() 267 getCurrent() 187 getCursorName() 379 getDescent() 138 getDirectory() 261 getEchoChar() 193 getFile() 261 getFontMetrics() 138 getGraphics() 169 getHeight() 138 getHours() 154 getImage() 222 getInputStream() 267, 276 getItem() 190 getLabel() 183, 185, 188 getLayout() 199 getLeading() 138 getMessage() 106 getMinutes() 154 getName() 137 getOutputStream() 267, 276 getParameter() 125, 204 getRows() 195 getSeconds() 154 getSelectedIndex() 191 getSelectedIndexes() 191 getSelectedItem() 191 getSelectedItems() 191 getSelectedText() 191 getSelectionEnd() 191 getSelectionStart() 191 getSize() 137 getSource() 224 getState() 185 getStyle() 137 getText() 181, 191 goto 301 graphe 361 Graphics (classe) 131, 222 GridBagConstraints (classe) 216 GridLayout (classe) 214 GUI (Graphical User Interface) 179
507
hachage 330 handleEvent() 168, 170 HashTable (classe) 321 hritage 85, 313, 316 dimplantation 317 et modlisation 319 multiple 21 hirarchie 92 HTML 9, 359 gnration de documents 12 HTTP 11 hypertexte 7, 29
identificateur 42 IEEE 754 22 if 66 image 221 chargement 221 double tampon 227 filtre 224 gestionnaire 222 scintillement 227 zoom 222 ImageFilter (classe) 224 ImageObserver (classe) 222 ImageProducer (interface) 224 implantation 91 import (mot-cl) 99 importation 98 inactif, processus 353 indexation du Web 12 InetAddress (classe) 266, 267 init() 127 initialisation complexe 84 initialiseur statique 102 InputEvent (classe) 176 InputStream (classe) 247, 268 InputStreamReader (classe) 243 INSERT (ordre JDBC) 379 insertText() 194
instance 19, 77 cration 80 instanciation 292 instruction 65 Integer (classe) 95 interblocage, processus 358 interface 21, 91, 100, 295, 320, 322 corps 101 dun module 290 interface de programmation dapplications 111 interface de programmation dapplications, Voir API Internet 3, 12, 23 interprteur Java 32 InterruptedException (classe) 106 InterruptedIOException (classe) 246 intranet 25 introspection 350 invariant 299 io (package) 241 IOException (classe) 106, 246 isBold() 137 isEditable() 191 isItalic() 137 isPlain() 137 item 187 ItemEvent (vnement) 184, 185, 189 ItemListener (classe) 184 itrateur 362 itrateur (structure de donnes) 334
jar (archive) 347 Java Beans 346 Java, BD et Web 27, 29 java.awt (package) 179 java.lang.reflect (package) 350 java.net (package) classes 265 exceptions 269 interfaces 269
508
Index
JavaScript 27, 119 JComponent (classe) 233 JDBC 373, 455 JDK (kit de dveloppement Java) 33 jeu du serpent 303 join() 150
label 71, 72 Label (classe) 180 langage de programmation 15 last() 216 layout() 199 LayoutManager (interface) 210 length() 132 liaison dynamique 86, 314 libell 180 lien entre objets 333 lien hypertextuel 8 List 190 List (classe) 190 list() 246, 247, 253 littral 44 logiciel modulaire 290 Long (classe) 95 look-and-feel 237 Lycos 36
machine virtuelle 22, 24 MacOS 240 main() 35 MalformedURLException (classe) 269 masque de saisie 192 matrice 61, 161 membre 102
menu 204, 205 droulant 187 MenuBar (classe) 204 MenuContainer (interface) 200, 204 MenuItem (classe) 205 message 19, 77 dalerte 206 mtadonne 388 metaDown() 171 Metal 240 mthode 19, 77, 287 abstraite 89 corps 78 dinstance 78 de classe 84, 293 de travail 112 dclaration 102 invocation 80 surcharge 82 middleware 373 MIME (Multipurpose Internet Mail Extensions) 265 mise en pages 209 cartes 216 contrainte 216 glissante 210 grille 214 imbrique 213 quadrillage 216 spcification des bords 212 modle 301, 327 modle-vue-contrleur 236 modlisation 301 modliser 319 modularit 289 module 16, 289, 292 mot de passe 192 Motif 240 mouseDown() 166 mouseDrag() 167 mouseDragged() 173 mouseEnter() 167
509
MouseEvent (vnement) 175 mouseExit() 167 MouseListener (interface) 175 MouseMotion (vnement) 173 MouseMotionAdapter() 175 MouseMotionListener (interface) 173, 175 MouseMove() 165 mouseMoved() 173 mouseUp() 167 multiprocessus 21, 150 MVC (modle-vue-contrleur) 236
binaire 59 de conversion 61 logique 57 prcdence 52 rgle dvaluation 55 relationnel 56 oprateur de slection 435 ou 58 exclusif 58 outil CASE 373 OutputStream (classe) 247 OutputStreamWriter (classe) 243 ovale, dessiner 132
ngation 58 new 20, 60, 80, 89 next() 216, 378 nextToken() 260 NNTP (Network News Transfer Protocol) 5 nom complet, importation 98 nombre premier 74 nombres amicaux 75 notify() 108, 355 null 278
Object (classe) 241 ObjectInputStream (classe) 245 Objective-C 21 ObjectOutputStream (classe) 245 objet 77, 292 copie 94, 338 cration 20, 80, 103 destruction 82 galit 94 rfrence 94 srialisable 245 ODBC 13, 379 openConnection() 268, 270 openStream() 268 oprateur 52
package 99, 341, 342 critre dappartenance 342 java.awt 179 java.lang.reflect 350 java.net 265 paint() 147 pane (surface daffichage) 232 Panel (classe) 179, 199 paramtre 78, 80, 83 fourni lapplet 121 reu dans lapplet 125 Pascal UCSD 22 priphrique 241 persistance 241 pi 80 PipedInputStream (classe) 243 PipedOutputStream (classe) 243 PipedReader (classe) 243 PipedWriter (classe) 243 PL/SQL 13 play() 230 Point (classe) 129 pointeur 20, 363 police de caractres 136 polygone, dessiner 132 polymorphisme 21, 92, 321 portabilit 14, 23
510
Index
porte 51 post-condition 298 pr-condition 297 prfrence daffichage 197 premire applet 35 premire application 34 PreparedStatement, JDBC 377 previous() 216 PrintStream (classe) 243 PrintWriter (classe) 243 private 102, 343, 344 private protected 102 processus 107, 353 producteur 355 producteur-consommateur 356 Produit (classe) 357 programmation distribue sur Internet 286 oriente objet 15, 289 Properties (classe) 247 protected 102, 343, 345 protocole 11 de connexion 373 IP 3 ProtocolException (classe) 269 pseudo-code 22 public (modificateur dinterface) 101 public (modificateur de classe) 101 public (modificateur de mthode) 102 public, accessibilit 343
Rectangle (classe) 114 redfinition de mthodes 314 et accessibilit 345 rfrence, un objet 94 registerOutParameter() 377 relation 301 cardinalit 302 repaint() 147 rpertoire 98 courant 248 de fichier 200 Repertoire (classe) 250 RepertoireEcriture (classe) 251 replaceText() 194 requte SQL 376 rseau de Petri 358 resize() 125 ResultSet (classe) 378 resume() 353 retour de chariot 192 return 79 rutilisation 313 de mthodes 315 RGBImageFilter (classe) 224 rollback() 376 run() 107, 353 Runnable 107, 150 RuntimeException (classe) 106 rupture 72
Q R
Queneau, Raymond 160 ramasse-miettes 21 random() 142 RandomAccessFile (classe) 257 readLine() 278 receive() 266 rechercher linformation sur le Web 36
schma dobjet 292 Scrollbar (classe) 195 section critique 354 scurit 24, 120, 382 SecurityManager, JDBC 383 SELECT (ordre) 378 select() 191 selectAll() 192 send() 266 squence (structure de donnes) 331
511
SequenceInputStream (classe) 243 srialisation 245 Serializable (interface) 246 serpent, jeu du 303 ServerSocket (classe) 267 serveur de donnes 13 serveur HTTP 11, 32, 266 setAlignment() 181 setAutoCommit() 376 setBackground() 134 setCheckboxGroup() 187 setDirectory() 261 setEchoChar() 193 setFile() 261 setFileNameFilter() 261 setFont() 136 setForeground() 135 setLabel() 183, 185, 188 setMenuBar() 205 setState() 185 setText() 181, 192 SGBD relationnel 374 SGML (Standard Generalized Markup Language) 9 shiftDown() 171 show() 216 si alors sinon 58 signature 79 Simula-67 16 site miroir 4 site Web 11 sleep() 150, 353 Smalltalk 16, 344 SMTP (Simple Mail Transfer Protocol) 5 SNMP (Simple Network Management Protocol) 5 Socket (classe) 267, 276 SocketException (classe) 269 SocketImpl (classe) 267 SocketImplFactory (classe) 269
son 221, 229 charger 229 format .au 229 souris 173 coordonnes 175, 200 vnements 173 vnements (1.0) 172 mouvement 173 mouvement (1.0) 166 sous-classe 85, 313 constructeur 88 spcification 296 SQL 380 sql.drivers 375 standards, utilisation dans Java 22 start() 107, 127, 353 Statement, JDBC 377 static 83, 293 stop() 127, 201 StreamTokenizer (classe) 259 String 161, 243 StringBuffer (classe) 243 StringReader (classe) 243 StringTokenizer (classe) 259, 362 stringWidth() 138 StringWriter (classe) 243 structure de contrle 65 super (pseudovariable) 86 super() 88 super-classe 100, 314 super-interface 101 surcharge 82, 315 surface daffichage 232 suspend() 353 Swing (composants) 231 architecture MVC 236 conversion depuis AWT 233 switch 67 synchronisation 21, 107, 354 synchronized 108, 278, 354 syntaxe 22 System (classe) 247
512
Index
tableau 20, 50, 61 cration 103 initialisation 50 TCP/IP 4 Telnet (Terminal Protocol) 5 TextArea (classe) 193, 200 TextArea() 194 TextComponent (classe) 191, 194 TextEvent (vnement) 192 TextField (classe) 192 TextField() 193 then 66 this 79, 80 this() 82, 88 thread 21, 149, 353 Thread (classe) 107, 353 throw 105, 300 toString() 145 traitement dexceptions 105 true 44 try 105, 149 try ... catch 300 typage fort 20 type 48, 101 compos 49 dclaration 100 simple 48, 95 type abstrait 290 et classe 294 spcification 291
UnknownServiceException (classe) 269 UPDATE (ordre JDBC) 379 update() 147, 227 URL 11, 254, 265, 383 affichage dun contenu 271 identification dun contenu 270 tlchargement 267 vrification des liens 272 URLConnection (classe) 268 URLEncoder (classes) 268 URLStreamHandler (classe) 266 URLStreamHandlerFactory (interface) 269
ValiditeURLConnexion (classe) 272 variable denvironnement 247 dinstance 78, 302, 333 de classe 83, 293 dclaration 48 VDM, mthode 327 vecteur 50, 103 initialisation 50 Vector (classe) 95, 321 virus 119, 363 visibilit des variables 83 design 345 et redfinition 345 rgles 98 void 78, 102
UML, diagramme 304 Unicode 22, 43 unit de compilation 97 UnknownHostException (classe) 269
wait() 108 Web 3 while 69, 70, 72, 73 Window (classe) 199 World Wide Web, Voir WWW WWW 3, 7, 23
513
yield() 353
Z, mthode 327
Yahoo 36
514
Index
Le CD-ROM du livre
Le CD-ROM qui accompagne de ce livre contient les lments suivants :
Les sources
Les fichiers sources de toutes les applets et applications du livre (sauf lapplet n 26, base sur louvrage Cent mille milliards de pomes de Raymond Queneau, pour des raisons de droits dauteur).
La syntaxe commente
Toute la syntaxe de Java, en format BNF et en diagrammes syntaxiques. Chaque lment syntaxique est comment. Les rgles sont connectes entre elles par des liens hypertextes.
Les concepts
Les concepts du langage Java et de son environnement de programmation expliqus et prsents dans des exemples.
516
Le CD-ROM du livre
517
downloads/index.html index.html.
ou
http://www.ultraedit.com/downloads/