CJava

301
Du C/C++ à Java TM Mise à jour du 11/02/2000 (version 1.1.1) Emmanuel PUYBARET http://www.eteks.com

description

c'est du java pour les debutants.

Transcript of CJava

Page 1: CJava

Du C/C++ à JavaT M

Mise à jour du 11/02/2000 (version 1.1.1)

Emmanuel PUYBARET

http://www.eteks.com

Page 2: CJava

Copyrights

Tous les développements (texte, images et programmes) de ce manuel sont protégés par les droitsd'auteur et ne doivent pas être reproduits par n'importe quel moyen et sur n'importe quel support que cesoit, publiés dans d'autres travaux ou traduits dans d'autres langues sans l'autorisation écrite d'eTeks.

Le manuel Du C/C++ à Java est fourni tel quel, sans aucune garantie d'aucune sorte, ni expresse niimplicite. Il pourrait notamment comporter des inexactitudes et des erreurs de frappes.Ce manuel peut être modifié à tout moment en vue de corrections ou d'améliorations.

Le manuscrit correspondant au manuel a été déposé à la Société Des Gens de Lettre.

Marques déposées

Sun, Sun Microsystems, le logo Sun et Java sont des marques déposées ou des marques de services deSun Microsystems, Inc, aux Etats Unis et autres pays. Copyright © 1992-1995 Sun Microsystems, Inc.Tous droits réservés.

eTeks est indépendant de Sun Microsystems, Inc.

eTeks est une marque déposée par Emmanuel PUYBARET.

Les autres marques citées dans ce manuel sont des marques déposées ou des marques commercialesdétenues par leurs propriétaires respectifs.

Page 3: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 1

Table des Matières

Copyrights

Avant propos

Démarrer en Java

Récupérer le JDK (Java Development Kit) Introduction Où trouver le JDK

Installation Description de l'environnement et des commandes

Principe de fonctionnement Description des principales commandes

javac java appletviewer

Votre première applet : le classique "Hello world !" Applet HelloWorld

Les notions de base

Objets, classes et héritage Références Les mots-clés de Java

Les mots-clés du C/C++ absent en Java Types de base Structure d'un programme Les packages

import Définir un package

Création et utilisation des classes

Déclaration des classes et des interfaces Identifiants Les classes Les interfaces

Déclaration des variables Syntaxe Initialisations static Initialisations d'instance

Déclaration des méthodes Syntaxe Surcharge des méthodes Constructeur

Création d'objets : opérateur new Outrepasser une méthode

Application Banque Utilisation de classes abstact

Destruction des objets Comment ça marche ?

Application ListeChainee

Page 4: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 2

Objets, tableaux et chaînes de caractères

La classe Object La classe Class Les tableaux Les chaînes de caractères La classe String La classe StringBuffer La classe System

Les instructions et les opérateurs

Les blocs if ... else, switch while, do ... while, for Les expressions

Utilisation de this et de super Les opérateurs

Opérateurs arithmétiques L'opérateur instanceof Opérateurs du C/C++ absent en Java

Les conversions (ou casts) Conversions entre types de base avec gain de précision Conversions entre types de base avec perte de précision Conversions de références d'une classe dans une autre

Priorité des opérateurs

Les exceptions

throw, try, catch,... Syntaxe

Application EssaiException Application InstantiationAvecNom

Avantages des exceptions La classe Throwable Les exceptions Runtime Les classes d'erreurs Les autres exceptions

Les threads

Définition d'un thread Le partage du temps entre threads

La création d'un thread Applet Chrono

Les états d'un thread La synchronisation des threads

Utilisation de synchronized Applet AfficheurDeCalcul

Synchronisation avec wait () et notify () La classe Thread

Les classes internes

Les classes internes Syntaxe Utilisation

Les classes anonymes

Page 5: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 3

Autres nouveautés Java 1.1 Initialisations d'instance Initialisation de tableaux Utilisation du mot-clé class Variables locales et paramètres final

Conventions d'éciture et portage

Conventions d'écriture Portage de programmes écrits en C/C++

Conception des classes Remplacement des définitions de type typedef Remplacement des instructions de précompilation #define Remplacement des instructions de précompilation #ifdef, #else, #endif Remplacement des énumérations enum Remplacement des unions union

Application TestExpression Passage des valeurs par adresse Allocation dynamique Utilisation des chaînes de caractères Arithmétique des pointeurs Transformation des pointeurs sur fonctions Remplacement de l'héritage multiple Autres problèmes propres au C++

La bibliothèque Java 1.0

Les packages de la bibliothèque Java 1.0 Classes de base : le package java.lang Gestion de données et utilitaires : le package java.util Les entrées-sorties : le package java.io Les accès réseau : le package java.net Gestion des applets : le package java.applet Interface utilisateur : le package java.awt Manipulation d'images : le package java.awt.image Liaison avec l'interface utilisateur du système : le package java.awt.peer

Hiérarchie des classes Java 1.0

Les classes de bases

Gestion des objets La classe java.lang.Object L'interface java.lang.Cloneable La classe java.lang.Class La classe java.lang.ClassLoader La classe java.lang.Compiler La classe java.lang.Throwable

Les classes d'emballage La classe java.lang.Boolean La classe java.lang.Character La classe java.lang.Number La classe java.lang.Integer La classe java.lang.Long La classe java.lang.Float La classe java.lang.Double La classe java.lang.String La classe java.lang.StringBuffer

Calcul mathématique : la classe java.lang.Math Gestion des threads

Page 6: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 4

L'interface java.lang.Runnable La classe java.lang.Thread La classe java.lang.ThreadGroup

Gestion du système La classe java.lang.System La classe java.lang.Runtime La classe java.lang.Process La classe java.lang.SecurityManager

Les outils Java

Gestion de collections de données L'interface java.util.Enumeration

Application EssaiEnumeration La classe java.util.Vector La classe java.util.Stack La classe java.util.Dictionary La classe java.util.Hashtable La classe java.util.Properties La classe java.util.BitSet

Gestion des dates La classe java.util.Date

Génération de nombres aléatoires La classe java.util.Random

Autres classes d'outils La classe java.util.StringTokenizer L'interface java.util.Observer La classe java.util.Observable

Applet ObservateurCalcul

La gestion des fichiers et des flux de données

Gestion des entrées-sorties Mode d'accès aux données Gestion de l'accès aux données avec les exceptions

Manipulation des fichiers L'interface java.io.FilenameFilter La classe java.io.File La classe java.io.FileDescriptor

Gestion des flux de données Accès à un flux de données en lecture

Application LectureFichier Application NumerotationLigne La classe java.io.InputStream La classe java.io.FileInputStream La classe java.io.PipedInputStream La classe java.io.ByteArrayInputStream La classe java.io.StringBufferInputStream La classe java.io.SequenceInputStream La classe java.io.FilterInputStream La classe java.io.BufferedInputStream L'interface java.io.DataInput La classe java.io.DataInputStream La classe java.io.LineNumberInputStream La classe java.io.PushBackInputStream La classe java.io.StreamTokenizer

Accès à un flux de données en écriture Application ConcatenationFichiers La classe java.io.OutputStream

Page 7: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 5

La classe java.io.FileOutputStream La classe java.io.PipedOutputStream La classe java.io.ByteArrayOutputStream La classe java.io.FilterOutputStream La classe java.io.BufferedOutputStream L'interface java.io.DataOutput La classe java.io.DataOutputStream La classe java.io.PrintStream

Gestion de l'accès aléatoire aux fichiers La classe java.io.RandomAccessFile

Les accès au réseau

Accès via une URL La classe java.net.URL

Application TestProtocole La classe java.net.URLConnection

Applet HelloFromNet La classe java.net.URLEncoder L'interface java.net.URLStreamHandlerFactory La classe java.net.URLStreamHandler L'interface java.net.ContentHandlerFactory La classe java.net.ContentHandler

L'architecture client-serveur Principe Exemples d'utilisation Protocoles

Accès via les sockets La classe java.net.InetAddress La classe java.net.Socket La classe java.net.ServerSocket Le client serveur d'écho

Application EchoServer Applet EchoClient

Le paper board Internet Application PaperBoardServer Applet PaperBoard Client

La classe java.net.SocketImpl L'interface java.net.SocketImplFactory

Accès via les datagrammes La classe java.net.DatagramPacket La classe java.net.DatagramSocket

Les applications et les applets

Les applications Java Les applets

Caractéristiques La classe java.applet.Applet

L'intégration des applets dans les navigateurs L'interface java.awt.AppletContext L'interface java.applet.AppletStub

Applet PlayApplet L'interface java.applet.AudioClip

Applet Piano Transformer une applet en application

Les composants de l'interface utilisateur

Page 8: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 6

Les composants Java La classe java.awt.Component Les composants prédéfinis

La classe java.awt.Button La classe java.awt.Checkbox La classe java.awt.CheckboxGroup La classe java.awt.Choice La classe java.awt.List

Applet Unicode La classe java.awt.Label La classe java.awt.TextComponent La classe java.awt.TextField

Applet CalculetteSimple La classe java.awt.TextArea La classe java.awt.Scrollbar

Comment ça marche ? Le peer d'un composant La classe java.awt.Toolkit

Les containers et la disposition des composants

Les containers L'architecture container/composant

Applet TraitementTexte La classe java.awt.Container La classe java.awt.Panel La classe java.awt.Window La classe java.awt.Frame

Transformer une applet en application isolée La classe java.awt.Dialog

Applet MessageBoxApplet La classe java.awt.FileDialog

La disposition des composants : les layouts L'interface java.awt.LayoutManager La classe java.awt.FlowLayout La classe java.awt.BorderLayout

Applet BorderBuilder La classe java.awt.GridLayout La classe java.awt.GridBagLayout La classe java.awt.GridBagConstraints La classe java.awt.CardLayout

Les menus Applet ShowMenu L'interface java.awt.MenuContainer La classe java.awt.MenuComponent La classe java.awt.MenuBar La classe java.awt.MenuItem La classe java.awt.Menu La classe java.awt.CheckboxMenuItem

La gestion de l'interface utilisateur

La gestion événementielle Les événements

Applet MiseAJourHorloge La classe java.awt.Event

La classe Graphics : tout pour dessiner La classe java.awt.Graphics Applet DrawIt

Page 9: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 7

Les polices de caractères La classe java.awt.Font La classe java.awt.FontMetrics

Applet ListePolices La couleur

La classe java.awt.Color Applet Nuancier

Les classes manipulant des dimensions La classe java.awt.Dimension La classe java.awt.Insets La classe java.awt.Point La classe java.awt.Polygon La classe java.awt.Rectangle

La création de nouveaux composants La classe java.awt.Canvas

Applet BoutonsNavigation

Les images

La génération d'images Applet MultiImages La classe java.awt.Image

Le chargement des images Applet ImageSimple La classe java.awt.MediaTracker L'interface java.awt.image.ImageObserver

Applet ChargementImage La création d'images

La classe java.awt.image.MemoryImageSource Applet ImageTableau

La classe java.awt.image.ColorModel La classe java.awt.image.DirectColorModel La classe java.awt.image.IndexColorModel

Applet ImageNoirEtBlanc La classe java.awt.image.PixelGrabber

Transformer des images avec un filtre La classe java.awt.image.FilteredImageSource La classe java.awt.image.ImageFilter La classe java.awt.image.CropImageFilter La classe java.awt.image.RGBImageFilter

Applet NegatifImage Comment ça marche ?

Applet Compteur L'interface java.awt.image.ImageProducer L'interface java.awt.image.ImageConsumer

Gestion d'animations Enchaînement d'images téléchargées

Applet AnimationFleche Utilisation du double buffering

Applet ScrollText Horloge avec image de fond

Applet Horloge

Plus loin avec Java...

Les évolutions du langage Java 1.1 Java 2

Conclusion

Page 10: CJava

vendredi 11 février 2000 Table des matières Du C/C++ à Java Page: 8

Principales applets Java de ce manuel (les plus intéressantes sont en gras)

Compteur de temps HelloWorld Liste des caractères accentués Unicode Compteurs multiples Chronomètre Afficheur synchronisé de calculs Observateur de calculs Lecture d'un fichier sur Internet Paper board Internet partagé Contrôleur d'applet Son d'un piano Afficheur de composants Java Opération simple entre deux nombres Descripteur du comportement d'une applet Couper/Copier/Coller/Effacer dans un traitement de texte Boite de message Utilisation de la classe BorderLayout Générateur d'interface GridBagBuilder Test de menus Mini-éditeur graphique Liste des polices de caractères disponibles Nuancier Barre de navigation avec boutons images Filtrage en négatif Compteur Image animée Défilement de texte Horloge des étoiles

Les autres applets accessibles sur le site http://www.eteks.com

Interpréteur de fonctions

Démineur Java

Historique du manuel

Page 11: CJava

vendredi 11 février 2000 Du C/C++ a Java : Avant propos Page: 1

Avant propos

Du C/C++ à Java décrit la version 2 du langage Java. Les similitudes et les différencesavec les langages C et C++ sont exposées point par point, en proposant si nécessaire dessolutions concrètes aux concepts du C/C++ qui sont traités différemment en Java(pointeurs, traitement d'erreur,...). La bibliothèque Java de la version 1.0 est décrite dans sonensemble classe par classe (classes de base, d'outils, d'entrées- sorties, d'accès réseau et degestion de l'interface graphique AWT).

Du C/C++ à Java s'adresse tout d'abord aux développeurs connaissant les langages C ouC++, mais aussi aux personnes ayant pratiqué d'autres langages structurés ou orientés objet(PASCAL, SmallTalk, Visual Basic,...). Les remarques sur le C/C++ et sur les pièges àéviter en Java sont mises en valeur pour les retrouver facilement et permettre une lecturerapide.

Du C/C++ à Java peut être utilisé comme cours de programmation des applets et desapplications Java, et comme manuel de référence rapide du langage et de la bibliothèqueJava. De nombreux exemples simples et originaux vous guident pas à pas du classiqueHelloWorld jusqu'à la programmation d'applets évoluées que vous pouvez tester "endirect" dans le site http://www.eteks.com.

Niveau : Initiés/Expérimentés

Des développements futurs traiteront plus en détail des ajouts effectués dans labibliothèque Java 1.1 et Java 2.

Page 12: CJava

vendredi 11 février 2000 Du C/C++ a Java : Avant propos Page: 2

Comment utiliser ce manuel ?Suivant le but que vous recherchez et votre méthode d'apprentissage personnelle, vouspouvez aborder ce manuel de différentes manières :

Si vous voulez apprendre Java par l'exemple :Vous pouvez lire le premier chapitre pour connaître les principes généraux dulangage, puis explorer directement les différents exemples d'applets fournies sur lesite.Quand vous commencerez à cerner la structure d'un programme Java, vous pourrezlire le chapitre sur les applets et piocher dans les cinq premiers chapitres pourcompléter vos connaissances sur le noyau de langage. Si vous voulez apprendre Java sans affronter dans un premier temps les points lesplus difficiles :Lisez rapidement les cinq premiers chapitres présentant le noyau du langage, puispassez directement au chapitre sur les applets et suivants pour réaliser vos premièresapplets. Quand vous serez plus à l'aise avec Java, vous pourrez alors revenir sur leschapitres traitant des exceptions et des threads. Vous voulez faire une revue rapide des différences entre Java et le C/C++ :Lisez surtout les neuf premiers chapitres sur le noyau du langage : comme indiquéci-après, ces chapitres comportent de nombreuses remarques résumant cesdifférences. Pour terminer, le chapitre abordant le portage de programmes C/C++ enJava vous donnera un complément d'information. Vous cherchez une référence des classes de Java 1.0 :Soit vous utilisez la table des matières pour une recherche thématique, soit vousutilisez la hiérarchie des classes pour une recherche alphabétique et hiérarchisée. Vous voulez tout connaître sur Java !Lisez tous les chapitres du premier au dernier, puis si vous avez encore soif deconnaissances, soyez patient, la suite arrive...

Ce cours comporte 20 chapitres et représente plus de 2 Mo de données (fichiers HTML,images et applets).Pour éviter toute incompréhension, tous les exemples de code Java ont été vérifiés et sontsans erreur de compilation.

Ce symbole vous signale des points importants ou des pièges à éviter.

Ces symboles vous signalent les différences entre le C/C++ ou le C++, et Java (utilisationdifférente, absence ou ajout dans le langage,...).

Page 13: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 1

Démarrer en Java

Récupérer le JDKInstallation

Description de l'environnement et des commandesVotre première applet : le classique "Hello world !"

Récupérer le JDK (Java Development Kit)

Introduction

Bonne nouvelle : jusqu'à nouvel ordre, vous pouvez développer en Java sans débourser un Kopeck (oupresque : il vous faut quand même un ordinateur si possible équipé d'un modem...).

Java est un langage de programmation développé par Sun Microsystems. Il n'a que quelques années devie (les premières versions datent de 1995), et pourtant il a réussi à intéresser et intriguer beaucoup dedéveloppeurs à travers le monde. Et pourquoi donc ?

La réponse est vaste et forcément sujet à polémiques. En voici les principaux avantages :

C'est un langage orienté objet dérivé du C, mais plus simple que le C++. Il est multi-plateforme : tous vos programmes tourneront sans modification sur toutes lesplateformes où existe Java. Il est doté en standard d'une riche bibliothèque de classes, comprenant la gestion des interfacesgraphiques (fenêtres, boites de dialogue, contrôles, menus, graphisme), la programmationmulti-threads (multitâches), la gestion des exceptions, les accès aux fichiers et au réseau(notamment Internet),...

Les deux derniers points ont contribué à utiliser d'abord ce langage pour développer des applets, quisont des applications qui peuvent être téléchargées via Internet et exécutées dans un navigateur surn'importe quelle plateforme. Ainsi, une page statique HTML peut s'enrichir de programmes qui luidonneront un comportement dynamique. Cet avantage permet de visualiser directement dans ce manuelle résultat des programmes.

Où trouver le JDK

Venons-en aux faits. Le JDK est disponible gratuitement sur le site Java de Sunhttp://www.javasoft.com/. Actuellement, vous cherchez sur ce site un lien products . Ce lien vousamène sur une page décrivant tout ce que Sun met à la disposition des développeurs pour développer enJava (et il y en a beaucoup).

Java est disponible sous 3 versions : Java 1.0, Java 1.1 et Java 2 (la version 2 est uniquement disponiblepour Windows, Solaris et Linux pour le moment).Il est conseillé de débuter par la version 1.0 en téléchargeant le Java Development Kit - JDK 1.0 (en fait laversion 1.0.2), disponible sous Windows 95/98/NT, MacOS et Solaris sur le site de Javasoft. Si votresystème de développement n'est pas un de ceux-ci, ce site fournit des liens vers ces autres systèmestierces (third party ports ).En commençant par la version 1.0, vous pourrez :

Apprendre Java et utiliser sa bibliothèque de base, sans être noyé par la quantité de fonctionnalitéssupplémentaires des versions suivantes (212 classes dans Java 1.0, 504 dans Java 1.1, 1592 dansJava 2). Bénéficier d'une documentation complète en utilisant le manuel Du C/C++ à Java (langage etbibliothèque).

Page 14: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 2

Faire fonctionner vos applets sur presque tous les navigateurs (notamment Netscape Navigator etMicrosoft Internet Explorer dès leur version 3).

Les versions Java 1.0 et 1.1 pour MacOS développées par Apple (dénommées MRJ 1.5 et MRJ 2.2respectivement) sont disponibles sur le site http://devworld.apple.com/java/.

Sur son site, Sun fournit aussi des documentations en anglais accompagnant le JDK. Voici la liste desplus intéressantes, qui ont aidé à rédiger ce manuel :

Les spécifications du langage au format Acrobat Reader, pour ceux qui recherchent desrenseignements détaillés sur le langage et les bibliothèques des classes de base de Java 1.0 (plus de800 pages).Le fichier est accessible via Java Language Specification 1.0 ; les personnes ne disposant pas encored'Adobe Acrobat Reader peuvent se procurer gratuitement cette application sur le site d'Adobe :http://www.adobe.com/. L'ensemble des classes Java et leur interface de programmation sous forme de fichiers HTML àvisualiser avec un navigateur (très utile pour avoir une référence complète des classes).Cet ensemble de fichiers est rassemblé sous forme de fichier .tar , .zip ou .hqx et est accessiblevia API Documentation . Les personnes ne disposant pas d'application pour extraire les fichiers d'unfichier .zip ou .tar , peuvent se procurer sur toute plateforme (Windows, MacOS ou UNIX) desfreewares faisant parfaitement l'affaire. Les moteurs de recherche vous donneront des liens poursatisfaire votre bonheur.Un tutorial de Java très complet, se dénommant The Java Tutorial - Object-Oriented Programming for theInternet , est disponible sous forme de fichiers HTML rassemblés dans un fichier tutorial.zip . Voir aussi les liens utiles sur http://www.eteks.com...

Bon courage pour télécharger ces fichiers et à tout à l'heure... Voici une petite applet indiquant depuiscombien de temps cette page est chargée : déjà secondes !

Le kit de développement fourni par Sun est très sommaire (généralement un ensemble de commandessimples), il vous faudra en plus au moins un éditeur de texte (n'importe lequel, peut importe). Denombreux éditeurs de logiciels fournissent des environnements de développement complet (éditeur,debugger intégré,...), mais là, il faudra dégainer la carte bleue !

Installation

Une fois que vous avez (au moins) téléchargé le JDK, vous pouvez vous mettre au travail.

Sous MacOS, vous récupérez un fichier auto-extractible, qui vous installe directement les applicationsnécessaires. Sous Windows 95/NT, vous récupérez un programme d'installation qui vous installe toutes les commandessans difficultés. Sous UNIX, désolé, pas de machine UNIX sous la main... Il faudra lire attentivement la documentationd'installation mais si vous connaissez bien UNIX, ce sera un jeu d'enfant !

Description de l'environnement et des commandes

Ce chapitre décrit les principales commandes (ou applications pour MacOS) qui vous permettront deprogrammer en Java. Mais tout d'abord il faut comprendre comment marche un programme Java pourutiliser correctement ces commandes.

Principe de fonctionnement

Rapidement résumé, Java est langage qui doit être compilé et interprété. Compilé et interprété ? En faitdans une première phase, vous compilez un programme (un ou plusieurs fichiers source .java ) enfichiers .class et le compilateur génère un fichier .class pour chacune des classes définies dans le(s)fichier(s) .java . L'ensemble des fichiers .class est ensuite interprété par la Machine Virtuelle Java (JavaVirtual Machine ) pour exécuter le programme. Voici une illustration de ce principe :

Page 15: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 3

Figure 1. Cycle de développement d'une applet

Il est possible de développer soit des applications isolées (standalone applications ), fonctionnant avecl'interpréteur comme un programme habituel, soit des "applets" ; ce sont des programmes qui sonttéléchargés sur Internet puis exécutés automatiquement quand ils sont intégrés à l'intérieur de pagesHTML. Dans ce dernier cas, l'ensemble des fichiers .class est utilisé avec un fichier HTML qui faitappel à une des classes (voir aussi la Description des principales commandes).Bien que les principes de programmation soient très proches, ce manuel donne surtout des exemplesd'applets car elles peuvent être ainsi intégrées dans le texte pour vous montrer le résultat d'unprogramme "en direct".

Pourquoi ne pas interpréter directement le programme Java ?

1. Les fichiers .class contiennent du bytecode, une sorte de code machine Java (comparable au codemachine d'un microprocesseur), qui sera exécuté beaucoup plus rapidement par l'interpréteur que sice dernier devait travailler avec les fichiers sources .java .

2. Seuls les fichiers .class sont nécessaires à l'exécution d'un programme Java. Comme ils contiennentdu code machine, ils ne peuvent être lus par des tiers, protégeant ainsi le code source.

3. Etant compilés, les fichiers .class sont de taille plus petite que le code source Java ; ceci est unargument important pour transférer les programmes sur Internet.

4. Chaque fichier .class décrivant une classe d'objet, une même classe peut être utilisé par différentsprogrammes, sans que cette classe ne soit dupliquée dans chacun des programmes.

Pourquoi ne pas compiler directement un exécutable ?

Sur ce point, la réponse est plus évidente. En effet, un exécutable contient du code qui n'estexécutable que sur la machine pour lequel il est destiné et le seul moyen de rendre unlangage multi-plateforme sans avoir à recompiler le source (comme en C/C++), c'estd'utiliser un interpréteur.L'autre avantage de l'interpréteur est qu'il peut être incorporé par exemple, à un navigateur cequi lui permet d'exécuter des programmes Java à l'intérieur de pages HTML.

Limites du système :

A vu d'œil, ce système a l'air d'être parfait : Vous écrivez des programmes, les compilez et lerésultat de la compilation fonctionnera en l'état sur toutes les machines ! Forcément, il doit yavoir un os quelque part...Le plus gros problème d'un programme Java est son manque de rapidité d'exécution :L'interpréteur prend forcément un certain temps pour interpréter le code des fichiers .class ,ce qui rend vos programmes moins rapides que de vrais exécutables.Mais Java est encore jeune : Sun Microsystems et d'autres éditeurs de logiciels tententd'optimiser les Machines Virtuelles Java. L'un des axes d'optimisation est actuellement ledéveloppement de compilateurs JIT (Just In Time ) ou juste à temps : Quand une classe estchargée, elle est traduite dans le code machine de la plateforme où elle est exécutée(traduction à la volée du micro-code Java vers par exemple, le code machine PowerPC ou

Page 16: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 4

Intel). Cette opération ralentit le départ de l'application, mais ensuite l'exécution duprogramme est beaucoup plus rapide !

Contrairement au C/C++, le compilateur Java ne génère pas de fichier exécutable. Il crée pour chacunedes classes d'un fichier Java un fichier .class qui sera interprété par la Machine Virtuelle Java.

Description des principales commandes

L'utilisation des commandes varie forcément suivant l'environnement de développement :

Sous Windows 95/98/NT, ouvrir une fenêtre de commandes ; puis, utiliser les commandesdécrites ci-après, en les tapant directement. Pour éviter d'avoir à décrire le chemin d'accès completaux commandes, il vous est vivement conseillé de modifier la variable d'environnement PATHpour que soit pris en compte le répertoire d'installation des commandes Java. Sous UNIX, utiliser la ligne de commandes comme sous Windows. Sous MacOS, soit vous effectuez sur l'icône de la commande un drag-and-drop (ou glisser-déposerpour les francophiles purs) des fichiers à passer en paramètres, soit vous utilisez le premier item dumenu File pour choisir le fichier en question (Java Runner ouvre directement une boite de dialoguevous demandant de choisir la classe à exécuter).

Toutes les options de chacune de ces commandes peuvent être obtenues en exécutant la commande sansparamètre.

javac, le compilateur (Icône Java Compiler ou javac sous MacOS) :

javac permet de compiler un ou plusieurs fichiers Java passé en paramètres. Le compilateurgénère pour chaque classe ClasseI définie dans le(s) fichier(s) Java compilé(s), un fichierayant pour nom le nom de classe et l'extension .class (ClasseI.class) .

En cas d'erreurs dans vos programmes, le compilateur javac vous donne généralement desinformations assez précises sur le contexte de l'erreur. C'est pourquoi n'hésitez pas àcompiler vos classes en cours de développement quand vous hésitez sur la bonne syntaxe àutiliser : javac vous donnera peut-être la solution !

Principales options à spécifier avant la liste des fichiers Java à compiler (boite de dialogueFile | Properties sous MacOS) :

-O : optimisation (Dans certains cas, les méthodes final sont compilées inline ,c'est-à-dire que l'appel à une méthode est remplacé par le code de cette méthode). -classpath dir : dir spécifie un ou plusieurs répertoires d'accès aux classesimportées (séparés par ; sous Windows, et : sous UNIX). -d dir : dir spécifie le répertoire de destination des fichiers de classes .class .

La variable d'environnement CLASSPATH est utilisée comme équivalent de l'option-classpath .

Exemple : javac Cube.java

Si vous compilez certains programmes Java respectant la version 1.0 avec le compilateur de la version1.1 ou 2, vous pouvez avoir des warnings vous indiquant que certaines méthodes que vous utilisez nesont pas recommandés (deprecated ), mais ceci n'empêchera pas le programme de fonctionnercorrectement.

Note aux utilisateurs de systèmes dont les fichiers ne font pas la différence entre les minuscules etmajuscules (Windows et MacOS) : Vous devez créer et utiliser des fichiers utilisant les combinaisonsmajuscules/minuscules correctes ; par exemple, si vous créez une classe Cube3D, le nom de fichier doitêtre Cube3D.java et pas cube3d.java ou Cube3d.java.

Page 17: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 5

Java, l'interpréteur (Icône Java Runner ou JBindery sous MacOS) :

Cette commande est utilisée pour exécuter des applications isolées. Dans ce cas, le fichier.class passé en paramètre doit définir une méthode main () qui sera le point d'entrée del'application. Toutes les valeurs qui suivent le nom de la classe sont passées en paramètres àla méthode main ().

Principales options de la ligne de commande à spécifier avant le nom de la classe (vousretrouverez ces options dans la boite de dialogue de JBindery sous MacOS ) :

-classpath dir : dir spécifie un ou plusieurs répertoires d'accès aux classesimportées (séparés par ; sous Windows, et : sous UNIX). -Dpropriete=valeur : modifie la propriété du système avec la valeur donnée (voiraussi la classe System). -version : écrit la version de la Machine Virtuelle que vous utilisez.

La variable d'environnement CLASSPATH est utilisée comme équivalent de l'option-classpath .

Exemple : java ClasseExec

appletviewer, l'interpréteur d'applets (Icône Applet Viewer ou Applet Runner sous MacOS) :

cette commande est utilisée pour exécuter des applets. Dans ce cas, le fichier .html passé enargument doit définir au moins une balise (tag ) APPLET respectant la syntaxe suivante :

<APPLET CODE=ClasseApplet WIDTH=largeur HEIGHT=hauteur CODEBASE="repertoire"ALT="Ca marche pas" NAME="NomApplet" ALIGN=alignement ARCHIVE="fichier.jar"></APPLET>.

L'argument de CODE, ClasseApplet, doit correspondre à un fichier .class qui est la classede l'applet. Vous verrez dans le premier exemple comment définir une classe utilisablecomme point d'entrée d'une applet. WIDTH et HEIGHT définisse la largeur et la hauteur de la zone où sera affichée l'applet. CODEBASE (optionnel) permet de définir le chemin d'accès aux classes utilisées parl'applet. Par défaut le chemin d'accès est le répertoire d'où provient le fichier HTML.Le chemin spécifié par CODEBASE peut être relatif au répertoire courant du fichierHTML, ou être une URL désignant un chemin sur un serveur différent. ALT (optionnel) définit la chaîne de caractères à afficher quand l'applet ne peut êtreexécutée (si par exemple, un navigateur n'autorise pas Java, il écrira cette chaîne). NAME (optionnel) définit un nom pour l'applet (utilisé quand vous recherchez une appletpar son nom). ALIGN (optionnel) permet de définir l'alignement horizontal de l'applet dans la pageHTML (LEFT, RIGHT ou MIDDLE). ARCHIVE (optionnel) est un attribut apparu à partir de Java 1.1 pour définir le fichier JARqui rassemble les classes, les images et autres fichiers qu'utilise l'applet.

appletviewer crée pour chaque balise APPLET, une fenêtre de taille (WIDTH,HEIGHT), où seraexécutée l'applet correspondant à la classe de CODE.Entre <APPLET ...> et </APPLET> peuvent figurer la description d'un certain nombre deparamètres à passer à l'applet, sous la forme <PARAM NAME="appletAttributei"VALUE="valuei">. Tout le reste du fichier HTML est ignoré.Vous pouvez aussi exécuter les applets d'un fichier HTML avec un navigateur intégrant uninterpréteur Java. Ceci vous est même vivement conseillé afin de pouvoir vérifier comments'intègre vos applets au milieu du texte dans lequel elles sont utilisées.

Page 18: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 6

Tout le code HTML compris entre les balises <APPLET ...> et </APPLET> (sauf bien sûr les balises<PARAM ...>) est affichée par les navigateurs qui ne sont pas dotés de Java ou sur lesquels Java n'estpas autorisé. Ceci est très pratique pour offrir une alternative aux applets sur un site Internet.Si vous consultez les source des fichiers du site http://www.eteks.com, vous verrez que justementchaque applet du site a pour alternative l'affichage d'une image qui est la capture d'écran de l'applet.

De nombreux exemples d'Applet avec leur programme Java, sont fournis avec le JDK.Essayez-les pour vous rendre compte des possibilités du langage.

Si une applet définit la méthode main (), elle peut être aussi utilisée comme une applicationavec l'interpréteur Java.

Exemple : appletviewer index.html

Sur la plupart des Machines Virtuelles Java, tant que vous ne quittez pas l'interpréteur (java ,appletviewer ou navigateur), les classes déjà chargées restent en mémoire, et NE sont PAS rechargéesquand vous relancez un même programme Java.Ceci implique qu'en phase de mise au point de vos programmes, il faut quitter l'interpréteur ou lenavigateur à chaque fois que vous changez une des classes de votre programme, sinon vous aurezl'impression que vos modifications n'ont pas été prises en compte !...

Votre première applet : le classique "Hello world !"

Comme vous devez l'avoir compris maintenant, il faut écrire écrire au moins deux fichiers différentspour pouvoir créer et exécuter une applet : Un fichier source Java et un fichier .html .

Voici le programme source Java. Donnez lui le nom HelloWorld.java (le nom de la classe public dufichier) :

import java.applet.Applet;import java.awt.Graphics; public class HelloWorld extends Applet{ public void paint (Graphics g) { g.drawString("Hello world !", 50, 20); } public static void main (String [ ] args) { System.out.println ("Hello World !"); }}

Les instructions utilisées dans ce programme seront décrites ultérieurement.Vous pouvez le compiler de la manière suivante : javac HelloWorld.javaVoici le source HMTL. Donnez lui le nom que vous voulez (MonPremierProgrammeJava.html si ça vouschante !) :

<HTML><HEAD><TITLE> Un programme simple </TITLE></HEAD><BODY> voici le résultat que vous devriez voir apparaître :<APPLET CODE="HelloWorld.class" WIDTH=150 HEIGHT=25></APPLET></BODY></HTML>

Page 19: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 7

Vous pouvez exécuter l'applet de la manière suivante : appletviewer MonPremierProgrammeEnJava.htmlvoici le résultat que vous devriez voir apparaître :

Comme HelloWorld définit aussi une méthode main (), qui est le point d'entrée d'une application Java, ilest donc possible de l'exécuter directement grâce à la commande : java HelloWorld

N'oubliez pas d'autoriser l'utilisation de Java dans votre navigateur, si vous voulez l'essayer pourinterpréter vos applets et visualiser le résultat des applets de ce manuel.

Pour les débutants, qui n'ont que de faibles notions de programmation (ou qui ne savent pas commentmodifier le PATH sous Windows), voici une procédure plus détaillée pour réaliser cette applet :

Windows 95/98/NT MacOS

Ouvrez un nouveau document avec notepad.exe .Recopiez le programme source Java HelloWorlddécrit ci-dessus dans ce document (en faisantattention aux majuscules / minuscules). Enregistrez ce document dans un fichierHelloWorld.java (Attention toujours auxmajuscules / minuscules, c'est important) :Enregistrez-le dans le même répertoire que leprogramme javac.exe ; javac.exe doit se trouverdans un répertoire du style c:\jdk...\bin.Vérifiez qu'à l'enregistrement notepad n'a pasajouté une extension .txt au fichier ; si c'est lecas, renommez-le pour que ce soit exactementHelloWorld.java ouvrez un autre document avec notepad.exe . Recopiez le source HTML de HelloWorlddécrit à ci-dessus dans ce document. Enregistrez ce document dans un fichierHelloWorld.html dans le même répertoire quecelui où vous avez mis HelloWorld.java . Ouvrez une fenêtre de commandes MS/DOS. Avec la commande CD , allez dans le répertoirede javac.exe (cd c:\jdk...\bin). Tapez ensuite javac HelloWorld.java pourcompiler le programme. S'il y une erreur, c'est que vous n'avez pasrecopié exactement le programme HelloWorld àl'identique.Corrigez-le, enregistrez-le, et refaites javacHelloWorld.java, jusqu'à ce qu'il n'y ait plusd'erreur. Tapez finalement appletviewerHelloWorld.html. Normalement une fenêtres'ouvre affichant le texte "Hello world !",comme le montre l'applet ci-dessus. C'est tout.Pour faire d'autres programmes, c'est toujours lamême procédure : Reprenez un programme Javaet créez un fichier HTML appelant l'appletgrâce à la balise <APPLET ...>, compilez-le avecjavac et exécutez-le avec appletviewer suivi dunom du fichier HTML.

Ouvrez un nouveau document avecSimpleText . Recopiez le programme source JavaHelloWorld décrit ci-dessus dans ce document(en faisant attention aux majuscules /minuscules). enregistrez ce document dans un fichierHelloWorld.java (Attention toujours auxmajuscules / minuscules, c'est important).Le dossier où vous enregistrez vosprogrammes importent peu. Ouvrez un autre document avec SimpleText . Recopiez le source HTML de HelloWorlddécrit à ci-dessus dans ce document. Enregistrez ce document dans un fichierHelloWorld.html dans le même dossier quecelui où vous avez mis HelloWorld.java . Faites ensuite un drag-and-drop du fichierHelloWorld.java sur l'icône Java Compiler (sivous utilisez le JDK de Sun) ou l'icône javac(si vous utilisez MRJ 2.x), pour compiler leprogramme. S'il y une erreur, c'est que vous n'avez pasrecopié exactement le programme HelloWorldà l'identique.Corrigez-le, enregistrez-le, et refaites laprocédure précédente, jusqu'à ce qu'il n'y aitplus d'erreur. Faites ensuite un drag-and-drop du fichierHelloWorld.html sur l'icône Applet Viewer (sivous utilisez le JDK de Sun) ou l'icône AppletRunner (si vous utilisez MRJ 2.x).Normalement une fenêtre s'ouvre affichant letexte "Hello world !", comme le montrel'applet ci-dessus. C'est tout.Pour faire d'autres programmes, c'est toujoursla même procédure : reprenez un programmeJava et créez un fichier HTML appelantl'applet grâce à la balise <APPLET ...>,compilez-le et exécutez-le avec Applet Viewerou Applet Runner .

Page 20: CJava

vendredi 11 février 2000 Du C/C++ à Java : Démarrer en Java Page: 8

Enregistrer vos programmes dans le répertoire où setrouve javac.exe n'est pas la solution idéale pourorganiser le rangement de vos programmes, mais vousévite d'avoir à changer la variable d'environnementPATH.

Une fois que vous commencez à comprendre comment marche un programme Java, vous pouvez enmodifier un existant ou en créer de complètement nouveaux, et vous pourrez considérer que vous savezprogrammer en Java. Bonne chance...

Page 21: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 1

Les notions de base

Objets, classes et héritageRéférences

Les mots-clés de JavaTypes de base

Structure d'un programmeLes packages

Objets, classes et héritage

Qu'entend on par langage objet, ou plus exactement langage orienté objet ? Le propos qui suit, n'est quela nième réponse, qui complétera une littérature déjà vaste sur le sujet. Cette explication rapide vouspermettra de vous rappeler le vocabulaire couramment utilisé en programmation orientée objet.L'exemple donné décrit un cas typique de programmation (gestion de compte en banque), plus parlantque des cas qui peuvent paraître plus abstraits (les catégories de voitures, les espèces animales, etc...).Le meilleur moyen d'expliquer la programmation objet passe en effet par l'exemple, car elle essaye des'appuyer sur l'habitude qu'a l'homme, de classer les objets du monde qui l'entourent en catégories,sous-catégories, et ainsi de suite...

Il faut faire la différence entre la programmation objet et un langage objet : Un langage objet tel que Java,Small Talk ou C++, est le moyen le plus aisé et le plus rapide de "programmer objet", mais laprogrammation objet est plus un style de programmation que peut respecter un programme écrit en C ouen PASCAL (plus difficilement tout de même !).

Mettons-nous donc à la place d'une banque : elle a des comptes à gérer, le votre, le mien et des milliersd'autres. Tous ces comptes ont en commun un certain nombre de caractéristiques communes que vousretrouvez sur votre relevé : un numéro et un solde, au minimum (même pas forcément une identité pourcertains comptes).Le banquier va donc créer un modèle de relevé avec les cases Numéro et Solde. L'imprimeur va en tirerdes centaines d'exemplaires pour que le banquier puisse les remplir avec les informations de ses clients.Le banquier gère aussi des comptes qui comportent d'autres informations dont il veut garder la trace. Iln'a pas besoin de créer un modèle entièrement nouveau : à partir de son premier modèle, il crée d'autresmodèles de relevés : un pour les comptes de dépôts où il ajoute n cases Opération, un autre pour lescomptes d'épargne où il ajoute une case Taux d'intérêts :

Figure 2. Des objets "relevés de compte"

Notre banquier décide de s'informatiser, et engage un informaticien expert dans la technologie magiquedont il entend parler dans tous les journaux : "les technologies objets".Celui-ci lui explique sa démarche : "Pour un informaticien, chaque relevé que vous imprimez est unobjet , chaque modèle que vous avez créé est une classe , et le premier modèle que vous avez créé estune classe dont les modèles suivant ont hérité . Les cases Numéro, Solde, Opération, Taux d'Intérêt sontdes variables qui permettent de mémoriser l'état courant d'un compte et le solde se calcule grâce à uneméthode ".Mais le banquier, pas dupe, lui répond : "Je ne veux pas vous acheter un dictionnaire !... Tout ça ne sontque de nouveaux mots. Quelle est la vraie différence avec d'autres technologies classiques et éprouvées?".Aïe, aïe, expliquer la différence sans terme trop technique et fumeux ?!? "Une classe est une entité quiforme un tout : chaque objet qui est une instance (désolé encore un nouveau mot !) d'une classe

Page 22: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 2

comporte un ensemble de variables qui décrivent son état ET un ensemble de méthodes qui permettentde le modifier : on appelle ceci l'encapsulation . L'héritage vous permet de créer de nouvelles classesdérivées d'anciennes dont elle garde ou modifie les caractéristiques, sans que vous ayez à retoucher vosanciennes classes. Convaincu ?" (Espérons-le...)

Les liens d'héritage définis entre les différentes classes d'un modèle définissent un graphe d'héritage ouune hiérarchie de classes :

Figure 3. Graphe d'héritage

CompteDepot est une classe dérivée de Compte. Compte est la "super classe" de CompteEpargne etCompteDepot, et CompteEpargne est la super classe de PEL. L'application Banque décrite au chapitresuivant s'inspire du modèle décrit ici.

La différence principale entre une structure C et une classe est évidente : on ne peut pas déclarer desméthodes (ou des fonctions) à l'intérieur du corps d'une structure C. A l'opposé, Java ne permet pas dedéclarer de méthodes en dehors du corps d'une classe.Une classe peut comporter uniquement des variables sans méthodes ; elle peut aussi n'avoir que desméthodes sans déclarer de variable.

L'héritage est différent de la composition : en C, vous pouvez créer une structure Compte et unestructure CompteEpargne, utilisant la première :

typedef struct{ int numero; float solde;} Compte; typedef struct{ Compte compte; float tauxInterets;} CompteEpargne; ...CompteEpargne unCompte;unCompte.compte.numero = 1;/* Pour accéder au numero vous passez par le champ *//* compte de CompteEpargne */

En Java, vous pouvez utilisez la composition comme en C. Par contre, grâce à l'héritage, toutes lesvariables (champs) et méthodes héritées sont accessibles directement comme si elles avaient étédéclarées par la classe dérivée elle-même.De toute façon, ne confondez pas l'héritage et la composition : Bien que l'héritage soit unecaractéristique d'un langage objet, il ne faut pas se précipiter pour l'utiliser. Vous utiliserez sûrementbien plus souvent la composition (en créant des classes qui sont l'assemblage de différents composants)et à part pour les classes d'applets, la plupart de vos premières classes n'hériteront pas d'autres classes.Pour vous en convaincre, vous n'avez qu'à étudier la hiérarchie des classes de la bibliothèque Java, etvous verrez que la plupart des classes n'héritent pas les unes des autres.L'héritage sert le plus souvent quand on veut modifier le comportement par défaut de classes existantes(par exemple, modifier le comportement de la classe Applet), ou quand vous avez besoin d'ajouter desfonctionnalités à une classe existante et que vous ne voulez pas modifier celle-ci parce qu'elle est déjà

Page 23: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 3

utilisée (par exemple, le compteur de temps dérive d'un afficheur digital statique).

Références

La notion de référence est fondamentale en Java. La différence avec la notion de pointeur en C estfaible, mais essentielle :Les variables en Java sont soit d'un type de base (byte, short, int, long, float, double, char ouboolean), soit des références désignant des objets. Comme les pointeurs en C, ces références sontcomparables à des adresses mémoires permettant de désigner un objet alloué dynamiquement. Un mêmeobjet peut être référencé par plusieurs variables à un moment donné.Par contre, la comparaison s'arrête ici : en effet, en C un pointeur peut désigner un type de base (int*par exemple), ou un autre pointeur (char** par exemple). Java lui, ne permet pas de déclarer une variablequi serait une référence sur un type de base ou une référence sur une autre référence. Tout objet nepeut être créé que dynamiquement grâce à l'opérateur new : ClasseObjet unObjet; ne crée aucun objeten Java mais une référence sur un objet de classe ClasseObjet.

La notion de pointeur du C est remplacée par la notion de référence en Java, différente de celle duC++. Les variables qui sont des références ne peuvent désigner que des objets alloués dynamiquement.

En C/C++, on utilise souvent une convention d'écriture pour les noms de variables permettant dedistinguer les variables qui sont des pointeurs et celles qui n'en sont pas,... comme par exemple :

struct Point{ int x, y;}; struct Point point1, // point1 n'est pas un pointeur *ptrPoint2; // ptrPoint2 est un pointeur sur Pointint entier, // entier est d'un type de base *ptrEntier; // ptrEntier est un pointeur sur int

Comme en Java il n'est possible de déclarer que des références comparables à ptrPoint2 ou desvariables d'un type de base comparables à entier, il n'est pas utile d'utiliser un qualificatif dans le nomdes variables qui permet de rappeler qu'une variable est une référence. En général, on écrit directementpoint2.

Il ne faut pas voir la notion de référence comme une limitation de Java par rapport au C, mais plutôtcomme une simplification de la programmation : La seule chose réellement perdue est l'arithmétique depointeurs du C, par contre le gain en sécurité d'accès à la mémoire est important, car une référence nepeut avoir pour valeur que null ou l'adresse valide d'un objet.

Les opérateurs * et & n'existent pas en Java. Le seul opérateur d'accès aux variables et aux méthodesd'un objet est le point (.), et les opérateurs -> et :: du C++ sont absents. Tout ceci simplifiegrandement la manipulation des adresses.

La création d'objet et leur manipulation sont décrites au chapitre traitant de la création des classes.

Les mots-clés de Java

Page 24: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 4

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

goto et const sont des mots-clés qui sont réservés mais non utilisés par Java ; ils permettentnotamment au compilateur de vérifier qu'en cas de portage d'un programme écrit en C vers Java, desmots-clés du C n'ont pas été oubliés...

null est une valeur utilisée pour les références inconnues et qui ne désignent aucun objet. Il ne s'écritpas en majuscules comme en C.

Les mots-clés du C/C++ absent en Java

auto extern register typedef

#define friend sizeof union

delete inline struct unsigned

enum operator template virtual

Types de base

Page 25: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 5

TYPE DESCRIPTIONVALEUR PAR

DEFAUT

byte Entier signé occupant 8 bits (valeurs de -128 à 127) 0

short Entier signé occupant 16 bits (valeurs de -32768 à 32767) 0

int Entier signé occupant 32 bits (valeurs de -2147483648 à21474836487).

Le type int occupe toujours la même taille en Java : 32 bits.

0

long Entier signé occupant 64 bits (valeurs de -9223372036854775808 à9223372036854775807)

Le type long occupe 64 bits en Java contrairement à 32 bitsen C.

0L

float Nombre à virgule flottante occupant 32 bits (IEEE 754) 0.0f

double Nombre à virgule flottante occupant 64 bits (IEEE 754) 0.0d

char Caractère Unicode occupant 16 bits (valeurs littérales de '\u0000' à'\uffff' avec 4 chiffres hexadécimaux obligatoires après \u).Les 128 premiers caractères sont les codes ASCII et se notentcomme en C, entre '' ('a', '1',...). Voici la liste des caractèrescompris entre '\u0080' et '\u00ff', qui contient notamment lescaractères accentués français :

Méfiez-vous car la plupart des éditeurs de texte ne génèrent pas àla compilation la bonne valeur Unicode pour ces caractères.Utilisez alors les valeurs hexadécimales ('\u00e9' au lieu de 'é'par exemple).

Le type char occupe 16 bits en Java contrairement à 8 bitsen C. Utilisez byte pour un 8 bits. Les valeurs littérales descaractères spéciaux sont les mêmes : '\n' pour un saut deligne, '\t' pour une tabulation, '\'' pour le caractère ','\"' pour le caractère ", '\\' pour le caractère \,...

'\u0000'

boolean Booléen dont la valeur est true ou false

Le type boolean n'existe pas en C. En Java, il est obligatoiredans certaines expressions (if (...) par exemple).

false

Les variables de type float et double peuvent prendre aussi des valeurs correspondant à l'infini positifou négatif, ou représentant une valeur non significative. Voir les classes Float et Double.Les valeurs littérales entières (byte, short, int et long) peuvent se noter de trois façons :

Comme une suite de chiffres décimaux : 3443, -123,... Comme une suite de chiffres hexadécimaux (base 16) précédée de 0x : 0xFF, 0X12ab,... Comme une suite de chiffres octaux (base 8) précédée de 0 : 0123, 056,...

Le modifieur unsigned du C n'existe pas en Java, où tous les types entiers sont signés. Comme en C,les entiers peuvent prendre pour valeur des littéraux notés sous forme décimale (i=10) , hexadécimale(i=0x0A) ou octale (i=012).

Chacun des types de base Java occupe toujours la même place mémoire quelque soit la plate-formed'exécution. La taille d'un entier de type int est toujours de 32 bits (ou 4 octets).

Page 26: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 6

Les opérateurs qui s'appliquent à chacun des types de bases sont étudiés au chapitre sur les instructionset les opérateurs.

Une valeur littérale d'un nombre à virgule flottante sans l'extension f ou d, comme par exemple 10.2est considérée de type double.

Structure d'un programme

La structure d'un programme Java est plus simple qu'en C.Chaque fichier qui le compose, se divise en trois parties (optionnelles) :

/* Début du fichier NouvelleClasse.java */ /* 1. Une éventuelle déclaration de package */package nomDuPackage; /* 2. Zéro ou plusieurs import */import nomDeClasse; // Importer une classe sans packageimport nomDuPackage.nomDeClasse; // Importer une classe d'un packageimport nomDuPackage.*; // Importer toutes les classes d'un package /* 3. Déclarations des classes et des interfaces du fichier */public class NouvelleClasse // Une seule classe ou interface déclarée public,{ // et par convention qui porte le même nom que le fichier // Corps de NouvelleClasse} class NouvelleClasse2{ // Corps de NouvelleClasse2} interface NouvelleInterface{ // Corps de NouvelleInterface} // ... /* Fin du fichier NouvelleClasse.java */

Les packages sont comparables à des sous-répertoires et sont traités au paragraphe suivant.

Les classes d'un même package peuvent s'utiliser mutuellement sans avoir à utiliser une clause import :Si, par exemple, vous créez deux fichiers Classe1.java et Classe2.java déclarant respectivement lesclasses Classe1 et Classe2, vous pouvez utiliser directement Classe2 dans le fichier Classe1.java.

Page 27: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 7

Les commentaires s'écrivent de la même manière en Java qu'en C++ :

Tout ce qui suit // est ignoré jusqu'à la fin de la ligne. Tout ce qui est compris entre /* et */ est ignoré. Ces commentaires peuvent incorporer descommentaires écrits avec la syntaxe précédente //, mais pas d'autres commentaires avec lasyntaxe /* */.Il est conseillé d'utiliser d'abord les commentaires avec // pour permettre d'imbriquer ce type decommentaire, dans ceux utilisant /* */ au cas où vous ayez de besoin de commenter tout unbloc. Par exemple :

class Classe1{ /* Bloc inutilisé int x = 1; // x sert à ... */ // ... }

Il existe un troisième type de commentaire utilisant la syntaxe précédente : Les commentairesjavadoc . javadoc est une commande qui utilise tous les commentaires compris entre /** et */ etrespectant une syntaxe spéciale pour générer automatiquement une documentation des classes.Toute la documentation des classes fournie par Javasoft est créée grâce à cet outil.

L'équivalent de #include est import.Java ne requiert pas de déclaration externe via un fichier header .h ; les fichiers .java ou .class sontsuffisants au compilateur pour résoudre les références aux types externes. Le mot-clé extern estinutile en Java.

Java est un langage "pur" objet et ne permet de définir au niveau global qu'UNIQUEMENT desclasses ou des interfaces : Pas de constantes, ni de macros (#define du C), pas de variables globalesqu'elles soient statiques ou non, pas de types autres que des classes (typedef est inutile), et toutes lesfonctions ne peuvent être déclarées que comme méthodes appartenant à une classe.C'est la raison pour laquelle vous verrez que tous les exemples donnés déclarent des classes qui sontsouvent inutiles pour expliciter tel ou tel problème, mais obligatoires pour que l'exemple puisse êtrecompilé.

Les packages

import

Aussitôt que vous utilisez une classe fournie avec le Java Development Kit ou par d'autres sources, vousdevez indiquer à votre programme où la trouver. Pour cela, il faut utiliser la clause import pour chacune(ou chaque groupe) des classes dont vous voulez vous servir dans un fichier .java . Ces clauses seplacent en début de fichier avant la déclaration de la première classe ou interface du fichier :

import nomDeClasse; // importer une classe sans packageimport nomDuPackage.nomDeClasse; // importer une classe d'un packageimport nomDuPackage.*; // importer toutes les classes d'un package

import est suivi soit directement d'un nom de classe, soit d'un nom de package, suivi lui-même d'un nomde classe ou d'un astérisque (*). L'astérisque permet d'importer les classes d'un package à la demande,c'est-à-dire que quand le compilateur recherchera une classe Classe1 qu'il ne connait pas encore, ilcherchera notamment dans les packages suivis d'un astérisque si Classe1 existe.La classe nomDeClasse peut correspondre soit à un fichier source nomDeClasse.java, soit à un fichiercompilé nomDeClasse.class, dans lequel est définie la classe public à importer.Un package représente une arborescence indiquant au compilateur quel chemin il faut emprunter pourretrouver la classe. Par exemple, si le package est java.util, il va effectuer sa recherche dans lerépertoire java/util (ou java\util sous Windows). Mais où est ce répertoire java/util ? Vous netrouverez sûrement pas sur votre disque dur de répertoire java à la racine, et non plus dans le répertoirecourant où vous écrivez vos programmes... Comme la plupart des langages, le compilateur Java utiliseune variable système d'environnement indiquant l'ensemble des chemins prédéfinis à utiliser avec unpackage pour construire le chemin complet d'accès aux classes : Sous UNIX et Windows, cette variable

Page 28: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 8

s'appelle CLASSPATH. Vous pouvez aussi utiliser l'option -classpath avec les commandes javac et java ,pour spécifier ce chemin.Vous pouvez modifier cette variable pour y ajouter le chemin d'accès à d'autres bibliothèques Java ou àvos propres packages, que vous créerez (les environnements de développement plus completspermettent d'ajouter ces chemins plus simplement).Le chemin correspondant à un package est donc un chemin relatif construit à partir du répertoire courantde compilation ou aux chemins cités dans la variable d'environnement CLASSPATH.

import est optionnel dans deux cas :

Quand vous voulez utiliser dans un fichier UneClasse.java des classes définies dans des fichierssitués dans le même répertoire que celui où se trouve UneClasse.java (toutes les classes publicou non d'un même package / répertoire peuvent s'invoquer entre elles). Quand vous utilisez une classe du package java.lang : Toutes les classes de ce package de base,sont importées automatiquement à chaque compilation.

Si un package nomDuPackage comporte des sous-packages (par exemple nomDuPackage.sousPackage), laclause import nomDuPackage.* n'importe pas ces sous packages. Il faut explicitement importer chacund'eux (avec par exemple import nomDuPackage.sousPackage.*).

Les packages peuvent servir aussi à donner un nom complet d'accès à une classe quand il y a risque deconflit pour retrouver une classe : Par exemple, à chaque fois que vous avez besoin de la classe String,vous pouvez utiliser String seul, mais, si dans un de vos fichiers .java vous définissez une autre classeString (ce qui n'est pas très conseillé !), vous pourrez accéder dans le même fichier à votre nouvelleclasse String et à la classe String du package java.lang en écrivant pour cette dernièrejava.lang.String, à chaque fois qu'il y a risque de confusion.Cette caractéristique est particulièrement appréciable le jour vous serez amené à utiliser des packages desources différentes qui ont défini certaines classes avec le même nom.

import permet d'importer les classes définies dans d'autres répertoires, mais n'est pas obligatoire pourimporter entre elles les classes définies dans un même répertoire, et notamment le répertoire courantde développement.

Toutes les classes que vous importez explicitement ou implicitement (parce qu'elles sont du mêmepackage ou qu'elles sont du package java.lang), sont chargées dynamiquement une à une à l'exécutiond'un programme Java, la première fois qu'elles sont utilisées.Comme il est décrit au premier chapitre, les liens ne sont donc pas statiques comme en C, où le linkrassemble dans un fichier exécutable tous les composants dont un programme a besoin pourfonctionner. Chaque classe est mémorisée dans un fichier .class qui peut être comparé à une (petite)librairie dynamique (ou DLL Dynamic Link Library ).

Définir un package

import permet d'importer n'importe quelle classe d'une bibliothèque, mais rien ne vous empêche decréer votre propre bibliothèque, pour y rassembler par exemple un ensemble de classes utilisées commeoutils dans un ou plusieurs projets. Ceci se fait très simplement grâce à la clause package. Si cette clauseest utilisée, elle doit être définie en tête d'un fichier .java , comme suit :

package nomDuPackage;

Comme expliqué précédemment, le nom de package doit correspondre au chemin d'accès à la classe quiutilise la clause package.En général, une société qui s'appelle nomSociete utilise com.nomsociete comme base pour le nom despackages des produits Java qu'elle livre, par exemple com.nomsociete.produitxxx pour le produitproduitxxx . Les classes de ce package devront être enregistrées dans le sous-répertoirecom/nomsociete/produitxxx.Si dans ce sous-répertoire, vous créez une classe public Outil1 dans le fichier Outil1.java, chacunedes classes désirant utiliser la classe Outil1, devra inclure la clause importcom.nomsociete.produitXXX.Outil1; et le fichier Outil1.java devra définir la clause packagecom.nomsociete.produitxxx;.

Page 29: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les notions de base Page: 9

La figure symbolisant les contrôles d'accès à des classes représente aussi un exemple simple d'utilisationdes packages.

Page 30: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 1

Création et utilisation des classes

Déclaration des classes et des interfacesDéclaration des variablesDéclaration des méthodes

Création d'objets : opérateur newOutrepasser une méthode

Destruction des objets

Déclaration des classes et des interfaces

Les seuls types que le programmeur peut définir en Java sont des classes ou des interfaces. Donc, lesmots-clé struct, union et enum n'existent pas en Java. De plus, les template n'existent pas.

Identifiants

Les identifiants que vous créez en Java (classes, interfaces, variables, méthodes,...) peuvent êtren'importe quelle suite illimitée de lettres ou de chiffres Unicode, de caractères _ ou $. Seul le premiercaractère ne doit pas être un chiffre. Il doit bien sûr être différent des mots-clés Java.Par conséquent, il est possible d'utiliser des caractères accentuées pour une meilleure lisibilité de vosprogrammes.

Les identifiants sont codés comme en C/C++, mais en Java vous pouvez utilisez en plus toutes leslettres et tous les chiffres Unicode et le caractère $. Comme en C, le compilateur fait la nuance entreles minuscules et les majuscules.

Vous pouvez créer des identifiants avec des lettres accentuées, ce qui n'est pas conseillé car la plupartdes éditeurs de texte et des systèmes fonctionnant en ligne de commande (comme MS/DOS ouUNIX) n'utilisent pas Unicode pour les lettres accentuées (qui ne sont pas ASCII).

Les classes

La déclaration d'une classe peut prendre une des formes suivantes :

// Déclararation d'une classe simpleModifieurDeClasse class NomDeClasse{ // Corps de NomDeClasse : // Déclaration des variables, des méthodes, des constructeurs // et/ou initialisations static} // Déclaration d'une classe dérivant d'une super classeModifieurDeClasse class NomDeClasseDerivee extends NomDeSuperClasse{ // Corps de NomDeClasseDerivee : // Déclaration des variables, des méthodes, des constructeurs // et/ou initialisations static} // Déclaration d'une classe implémentant une interfaceModifieurDeClasse class NomDeClasse2 implements NomInterface //, NomInterface2, ...{ // Corps de NomDeClasse2 : // Déclaration des variables, des méthodes, des constructeurs // et/ou initialisations static // et implémentation des méthodes de nomInterface }

Page 31: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 2

// Déclaration d'une classe dérivant d'une super classe et implémentant une interfaceModifieurDeClasse class NomDeClasse3 extends NomDeSuperClasse implements NomInterface //, NomInterface2, ...{ // Corps de NomDeClasse3 : // Déclaration des variables, des méthodes, des constructeurs // et/ou initialisations static // et implémentation des méthodes de nomInterface }

Une classe simple dérive implicitement de la classe Object (class nomDeClasse est équivalent à classnomDeClasse extends Object). Java ne permet pas l'héritage multiple (une seule classe peut suivre laclause extends), mais une classe peut implémenter plusieurs interfaces.Le corps d'une classe est une suite quelconque de déclaration de variables, de méthodes, deconstructeurs et/ou d'initialisations static.A partir de Java 1.1, le corps d'une classe peut aussi déclarer des classes internes, des interfaces interneset des initialisations d'instance.

ModifieurDeClasse est optionnel et peut prendre une ou plusieurs des valeurs suivantes :

public : Une seule classe ou interface peut être déclarée public par fichier source .java . Parconvention, le fichier porte le nom de la classe déclarée public. Si d'autres classes (non public)sont déclarées dans un fichier Classe1.java, elles ne peuvent être utilisés que dans les fichiers quiappartiennent au même package que Classe1.java. final : Une classe déclarée final ne peut être dérivée et ne peut donc jamais suivre la clauseextends. Cette clause peut être utile quand vous considérez qu'une classe ne doit pas ou n'a pasbesoin d'être dérivée. abstract : Il est impossible de créer une instance d'une classe déclarée abstract. Cette catégoriede classe peut comporter une ou plusieurs méthodes déclarées abstract. Par contre, si une classecomporte une méthode abstract, elle doit être être déclarée abstract.A quoi sert une classe abstract si on ne peut créer aucun objet de cette classe ? Ce type de classeest utilisé pour fournir des méthodes et des variables communes à toutes les classes qui endérivent. L'intérêt des classes abstract est démontrée plus loin dans ce chapitre.Une classe ne peut être déclarée abstract et final (elle ne servirait à rien puisqu'il seraitimpossible de créer des classes dérivées de celle-ci).

figure 4. Symbolisation des contrôles d'accès aux classes

Contrairement au C++, le point-virgule en fin de déclaration d'une classe est optionnel.

En Java, on utilise la clause extends pour préciser la super classe d'une classe dérivée, à la place desdeux points qui suivent la déclaration d'une classe en C++.

L'héritage se fait systématiquement de manière public en Java. Il n'existe pas d'équivalence à ladéclaration C++ : class Classe2 : private Classe1 { /* ... */ }.

Une classe abstraite doit être déclarée abstract en Java et peut contenir aucune ou plusieurs méthodesabstract (équivalent des méthodes virtuelles pures du C++).Les modifieurs de classe public et final n'ont pas d'équivalent en C++.

En Java une classe et tout ce qu'elle contient devant être déclarée entièrement dans un seul fichier, iln'est pas possible comme en C++ de répartir les méthodes d'une même classe sur plusieurs fichiers.

Page 32: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 3

Les interfaces

Une interface est une catégorie un peu spéciale de classe abstract, dont le corps ne contient que ladéclaration de constantes et de méthodes abstract :

// Déclararation d'une interface simpleModifieurInterface interface NomInterface{ // Corps de NomInterface : // Déclaration des constantes et des méthodes non implémentées} // Déclaration d'une interface dérivant d'une super interfaceModifieurInterface interface NomInterfaceDerivee extends NomSuperInterface{ // Corps de NomInterfaceDerivee : // Déclaration des constantes et des méthodes non implémentées}

A partir de Java 1.1, le corps d'une interface peut aussi déclarer des classes internes et des interfacesinternes.II est impossible de créer une instance d'une interface. Une ou plusieurs interfaces peuvent suivre laclause extends.Une classe non abstract, qui implémente une interface Interface1 doit implémenter le code dechacune des méthodes de Interface1. L'implémentation d'une méthode est l'ensemble des instructionsque doit exécuter une méthode.ModifieurInterface est optionnel et peut prendre une ou plusieurs des valeurs suivantes :

public : Une seule interface ou classe peut être déclarée public par fichier source. Par convention,le fichier porte le nom de l'interface déclarée public. Si d'autres interfaces (non public) sontdéclarées dans un fichier Interface1.java, elles ne peuvent être utilisés que dans les fichiers quiappartiennent au même package que Interface1.java. Une interface ne peut porter le même nomqu'une classe. abstract : Toute interface est implicitement abstract. Ce modifieur est permis mais pasobligatoire.

A quoi sert une interface et quelle est la différence avec une classe abstract ?Tout d'abord, vous noterez qu'une classe ne peut hériter que d'une super classe, mais par contre peutimplémenter plusieurs interfaces. Ensuite, une classe abstract peut déclarer des variables et le code decertaines méthodes.

Soit une classe Classe1 qui implémente toutes les méthodes d'une interface Interface1. Cetteclasse peut déclarer d'autres méthodes, ce qui compte c'est que chaque instance de cette classegarantit qu'au moins toutes les méthodes d'Interface1 existent et peuvent être appelées, commedans l'exemple suivant :

interface CouleurDominante{ // Déclaration d'une méthode QuelleCouleurDominante ()} class Classe1 extends SuperClasse1 implements CouleurDominante{ // Corps de la méthode QuelleCouleurDominante () // Autres méthodes éventuelles} class Classe2 extends SuperClasse2 implements CouleurDominante{ // Corps de la méthode QuelleCouleurDominante () // Autres méthodes éventuelles} class ClasseAyantBesoinDeLaCouleurDominante

Page 33: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 4

{ CouleurDominante objetColore; // On peut affecter à objetColore une référence // à un objet de classe Classe1 ou Classe2 // et ainsi obtenir la couleur dominante d'un objet coloré en invoquant // la méthode QuelleCouleurDominante () sur la variable objetColore}

Une interface peut être utilisée pour masquer l'implémentation d'une classe. Ce concept est utilisédans plusieurs packages Java dont java.awt.peer : Ce package déclare un ensemble d'interfaces quioffrent les mêmes méthodes sur chaque Machine Virtuelle Java mais qui sont implémentéesdifféremment pour que l'interface utilisateur du système (bouton, fenêtre,...) soit utilisée. Une interface vide (comme l'interface Cloneable) permet de créer une catégorie de classes : chaqueclasse implémentant ce type d'interface appartient à telle ou telle catégorie. Pour tester si la classed'un objet appartient à une catégorie, il suffit d'utiliser l'opérateur instanceof avec le nom del'interface. Une interface peut servir aussi pour déclarer un ensemble de constantes, qui seront utilisées dansdes classes sans lien d'héritage entre elles, comme dans l'exemple suivant :

interface ConstantesCommunes{ // Déclaration des constantes A, B et C} class Classe1 extends SuperClasse1 implements ConstantesCommunes{ // Les constantes A, B et C sont utilisables dans la classe Classe1} class Classe2 extends SuperClasse2 implements ConstantesCommunes{ // Les constantes A, B et C sont utilisables dans la classe Classe2}

Une classe qui implémente une interface InterfaceDerivee dérivée d'une autre interface Interface1doit implémenter les méthodes des deux interfaces InterfaceDerivee et Interface1.

Java ne permet pas l'héritage multiple. Mais l'utilisation des interfaces peut compenser cet absence, carune classe peut implémenter plusieurs interfaces. Voir aussi le chapitre sur le portage.

Si vous avez quelque mal au départ à comprendre le concept d'interface et leur utilité, considérez lessimplement comme des classes abstract, déclarant des constantes et des méthodes abstract. Vous enpercevrez leur intérêt au fur et à mesure que vous serez amené à vous en servir.

Déclaration des variables

Le corps d'une classe est un ensemble de déclarations de variables et de méthodes implémentées ounon, déclarées dans n'importe quel ordre.

Syntaxe

Les déclarations de variables se font comme en C/C++ :

class Classe1{ // Déclaration de variables TypeVariable variable1; TypeVariable variable2, variable3; ModifieurDeVariable TypeVariable variable4; TypeVariable variable5 = valeurOuExpression ; // Initialisation d'une variable TypeVariable tableau1 [ ]; // Création d'une référence sur un tableau // Allocation d'un tableau de taille n initialisé avec les n valeu TypeVariable tableau2 [ ] = {valeur1, valeur2, /*..., */ valeurn}; // ...}

Page 34: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 5

TypeVariable est soit un type de base, soit le nom d'une classe, soit le nom d'une interface. Dans cedernier cas, la variable est une référence sur un objet.Les tableaux sont cités ici en exemple de variable et sont traités dans la partie sur les tableaux.

ModifieurDeVariable est optionnel et peut être un ou plusieurs des mots-clés suivants :

public, protected ou private : Une variable public est accessible partout où est accessible la classe Classe1 dans laquelleelle est déclarée. Une variable protected est accessible par les autres classes du même package que Classe1,et par les classes dérivées de Classe1. Une variable private n'est accessible qu'à l'intérieur du corps de Classe1.

static : Si une variable est static, elle est créée en un unique exemplaire quelque soit le nombred'instance de Classe1 : c'est une variable de classe. L'accès à cette variable se fait grâce àl'opérateur point (.) en indiquant le nom de la classe ou une référence à un objet(Classe1.variable ou objetClasse1.variable).A l'opposé, si une variable n'est pas static, chaque nouvelle instance objetClasse1 de Classe1créera une variable pour objetClasse1 : c'est une variable d'instance. L'accès à cette variable se faitgrâce à l'opérateur point (.) , de la manière objetClasse1.variable. final : Une variable final n'est pas modifiable une fois initialisée : en fait, c'est une constante quipeut prendre une valeur initiale différente d'un objet à l'autre d'une même classe. Si cette variableprend toujours la même valeur d'initialisation, il vaut mieux optimiser votre code en y ajoutantstatic pour en faire une constante de classe.Les variables déclarées dans le corps d'une interface sont des constantes implicitement public,final et static, et doivent être initialisées avec une expression constante. transient : Une variable transient sert à indiquer aux méthodes gérant la persistance qu'elle nefait pas partie de la persistance de l'objet. Cette fonctionnalité n'a été mise en œuvre qu'à partir deJava 1.1, et sert à éviter de sauvegarder des variables ne servant qu'à des calculs intermédiaires(indices par exemple). volatile : Une variable volatile permet d'être sûr que deux threads (tâches) auront accès demanière ordonnée à cette variable (modifieur implémenté uniquement à partir de Java 1.1). Voiraussi le chapitre sur les threads. Une variable volatile ne peut être aussi final.

figure 5. Symbolisation des contrôles d'accès aux variables

Le contrôle d'accès à une variable est soit public, soit protected, soit private, soit par défaut, si aucunde ces modifieurs n'est précisé, amical (friendly en anglais) : la variable est alors accessible uniquementpar les autres classes du même package. Les liens de la figure précédente indique les endroits où il estpossible d'utiliser une variable. Comme vous pouvez le voir, l'utilisation d'une variable se faitdirectement par son nom à l'intérieur d'une classe et de ses classes dérivées, sans besoin d'utiliserl'opérateur point (.).

Page 35: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 6

L'initialisation d'une variable se comporte exactement comme l'affectation. Si la variable est static, alorsl'initialisation est effectuée au chargement de la classe.Les variables non initialisées prennent obligatoirement une valeur par défaut (voir le tableau sur les typesde base). Si cette variable est une référence à un objet, la valeur par défaut est null.

Une classe Classe1 peut déclarer une variable qui est une référence à une classe Classe2 déclaréeaprès Classe1 (pas besoin de déclarer les types avant de les utiliser comme en C).

En Java, le modifieur final est utilisé pour déclarer une constante (pas de #define, ni de const).

Contrairement au C/C++, Java permet d'initialiser à la déclaration les variables de classe ainsi que lesvariables d'instance.

Les variables d'instance et de classe sont toutes initialisées à une valeur par défaut. En C++, il estobligatoire d'initialiser les variables de classe à part ; en Java, soit ces variables prennent une valeur pardéfaut, soit elles sont initialisées à leur déclaration, soit elles sont initialisées dans un blocd'initialisation static.

L'accès aux variables static se fait grâce à l'opérateur point (.) et pas l'opérateur ::, comme en C++.De plus, si vous voulez donner une valeur par défaut aux variables static, vous le faites directement àla déclaration de la variable, comme par exemple static int var = 2;.

Le contrôle d'accès aux variables (et aux méthodes) se fait pour chacune d'elles individuellement, etpas en bloc comme en C++ (avec par exemple public :).

Les variables (et les méthodes) d'une classe Classe1 dont le contrôle d'accès est protected sontaccessibles par les classes dérivées de Classe1 comme en C++, mais aussi par les classes du mêmepackage que Classe1.

En Java, les variables (et les méthodes) d'une classe Classe1 ont un contrôle d'accès par défaut qui estamical (friendly ), c'est à dire qu'elles sont accessibles uniquement par les autres classes du mêmepackage que Classe1. En C++, cette notion n'existe pas et par défaut le contrôle d'accès est private.

Le contrôle d'accès par défaut de Java est très pratique car il donne accès à toutes les variables ettoutes les méthodes des classes d'un même package. Mais attention, si après avoir développé certainesclasses, vous pensez qu'elles peuvent vous être utiles pour d'autres programmes et qu'ainsi vous lesmettez dans un nouveau package outils, il vous faudra ajouter les contrôles d'accès public pouraccéder en dehors du package outils aux méthodes et variables dont vous avez besoin.Donc, prenez l'habitude de préciser dès le départ les contrôles d'accès des variables et des méthodes.

Initialisations static

Le corps d'une classe peut comporter un ou plusieurs blocs d'initialisation static. Ces blocs sontexécutés au chargement d'une classe, et permettent d'exécuter des opérations sur les variables static. Ilssont exécutés dans l'ordre de déclaration et peuvent ne manipuler que les variables static déclaréesavant le bloc.

class Classe1{ // Déclaration de variables static static int variable1 = 10; static int variable2; static { // Bloc static variable2 = variable1 * 2; } // ...}

Page 36: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 7

Sur une même Machine Virtuelle Java, vous pouvez très bien exécuter différentes applets ouapplications l'une après l'autre ou en même temps grâce au multi-threading. Par contre, chaque classeClasseX n'existe qu'en un seul exemplaire pour une Machine Virtuelle, même si ClasseX est utiliséepar différentes applets.Ceci implique que les variables static de ces classes sont uniques pour une Machine Virtuelle, etpartagées entre les différentes applets. Donc, attention aux effets de bord ! Si vous modifiez la valeurd'une variable static dans une applet, elle sera modifiée pour toutes les applets amenées à utilisercette variable.Ceci est à opposer au C, où les variables static sont uniques pour chaque contexte d'exécution d'unprogramme.

Initialisations d'instance

A partir de Java 1.1, le corps d'une classe peut comporter un ou plusieurs blocs d'initialisation d'instance.Comme pour les constructeurs, ces blocs sont exécutés à la création d'un nouvel objet dans l'ordre dedéclaration.

class Classe1{ // Déclaration d'une variable comptant le nombre d'instances créées static int nombreInstances = 0; // Déclaration d'une variable d'instance int variable1; { // Bloc d'instance variable1 = 10; nombreInstances++; } // ...}

Déclaration des méthodes

Syntaxe

Les déclarations des méthodes en Java ont une syntaxe très proche de celles du C/C++ :

class Classe1{ // Déclarations de méthodes TypeRetour methode1 (TypeParam1 param1Name /*,... , TypeParamN paramNName*/) { // Corps de methode1 () } ModifieurDeMethode TypeRetour methode2 (TypeParam1 param1Name /* ... */) { // Corps de methode2 () } ModifieurDeMethode TypeRetour methode3 (/* ... */) throws TypeThrowable /*, TypeThrowable2 */ { // Corps de methode3 () } // Déclaration d'une méthode abstract // Dans ce cas, Classe1 doit être aussi abstract abstract ModifieurDeMethode TypeRetour method // Déclaration d'une méthode native native ModifieurDeMethode TypeRetour methode4 (/* ... */); // ...}

TypeRetour peut être :

soit un type (de base, une classe ou une interface) : dans ce cas, la méthode doit utiliser

Page 37: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 8

l'instruction return suivie d'une valeur du type TypeRetour , pour renvoyer une valeur. Le typepeut être une référence à un tableau en utilisant [ ] (par exemple, int [ ] methode ()). soit void quand la méthode ne renvoie pas de valeur.

TypeThrowable doit être une classe dérivée de la classe Throwable. Les exceptions qui sont déclenchéesvia l'instruction throw doivent avoir leur classe déclarée après la clause throws. Voir le chapitre traitantdes exceptions.

ModifieurDeMethode est optionnel et peut être un ou plusieurs des mots-clés suivants :

public, protected ou private : Une méthode public est accessible partout où est accessible la classe Classe1 dans laquelleelle est déclarée. Ce sont les méthodes public que l'utilisateur d'une classe peut appeler. Une méthode protected est accessible par les autres classes du même package que Classe1,et par les classes dérivées de Classe1. Une méthode private n'est accessible qu'à l'intérieur du corps de Classe1. Les méthodesprivate sont typiquement des routines internes de calcul pour lesquels il n'y a pas de raisonde donner un accès à l'utilisateur d'une classe.

static : Si une méthode est static, c'est une méthode de classe qui ne peut utiliser que lesvariables et les méthodes de Classe1, qui sont déclarées static. L'appel à cette méthode se faitgrâce à l'opérateur point (.) en indiquant le nom de la classe ou une référence à un objet(Classe1.methode () ou objetClasse1.methode ()).A l'opposé, si une méthode n'est pas static, c'est une méthode d'instance, accessible pour chaqueinstance objetClasse1 de Classe1 grâce à l'opérateur point (.) , de la manièreobjetClasse1.methode ().Les méthodes déclarées dans le corps d'une interface ne peuvent être static. final : Une méthode final ne peut pas être outrepassée par les classes dérivant de Classe1. abstract : Une méthode abstract permet de déclarer une méthode d'instance sans en donnerl'implémentation, et ne peut apparaître qu'au sein d'une classe abstract. Toute classe non abstractdérivée de cette classe, doit implémenter cette méthode, en l'outrepassant.Les méthodes déclarées dans le corps d'une interface sont implicitement abstract et public. native : Une méthode native est implémentée dans une bibliothèque annexe propre à laplateforme de développement qui peut être développée en C ou en C++ par exemple. Ceci permetde faire appel à certaines fonctionnalités propres à la plateforme ciblée, qui ne seraient pasdisponibles en Java. Mais une méthode native n'est pas portable... synchronized : Une méthode synchronized permet d'obtenir un verrou sur l'objet sur lequel elleest appelée (ou sur la classe si la méthode est aussi static). Ce verrou empêche qu'en cas deprogrammation multi-threads (multitâches), différents threads aient accès de manière simultanée àun même objet. Voir aussi la synchronisation des threads.

Le contrôle d'accès à une méthode est soit public, soit protected, soit private. Leur utilisation est lamême que pour les variables.Dans la plupart des cas, il est conseillé de ne rendre public que les méthodes et les constantes(variables final static), dont a besoin l'utilisateur d'une classe. Les autres variables sont déclaréesprivate voir friendly ou protected et sont rendues accessibles si besoin est, par des méthodes publicpermettant de les interroger et de les modifier (get... () et set... ()). Ceci permet de cacher auxutilisateurs d'une classe ses variables et de vérifier éventuellement les conditions pour modifier unevariable.Ce style de programmation est largement utilisé dans la bibliothèque Java.

Pour les méthodes non abstract et non native, le corps de la méthode est un bloc, comportant unesuite d'instructions.A l'intérieur de la déclaration d'une classe Classe1, l'appel à toute méthode methode () de Classe1 ou deses super classes, peut se faire directement sans l'opérateur point (.) ; l'utilisation de cet opérateur n'estobligatoire que pour accéder aux méthodes des autres classes, comme dans l'exemple suivant :

class Classe1{ static public int Factorielle (int i) {

Page 38: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 9

if (i == 0) return 1; else return i * Factorielle (i - 1); // Factorielle () est directement accessible à l'intérieur de Classe1 }} class Classe2{ // Pour accéder à la méthode Factorielle () de Classe1 // vous devez utilisez l'opérateur point. int factorielle10 = Classe1.Factorielle (10);}

Java ne permet pas l'utilisation des listes d'arguments variables qui existent en C (défini avec ...). Cetteabsence peut être partiellement détournée grâce à l'utilisation de la surcharge des méthodes.

En Java, chaque paramètre doit être déclarer avec son type et un nom. En C++, quand un paramètreest requis mais n'est pas utilisé dans une méthode, il n'est pas obligatoire de spécifier un nom, commepour le deuxième paramètre de l'exemple void methode1 (int a, float).

A l'opposé du C++, il est possible de donner le même nom à une variable et à une méthode (à éviterpour ne pas nuire à la lisibilité du programme).

Contrairement au C/C++, dans une classe Classe1, vous pouvez utiliser toutes les variables et lesméthodes de Classe1 dans le corps de ses méthodes qu'elles soient déclarées avant ou après dansClasse1, comme dans l'exemple suivant :

class Classe1{ void methode1 () { x = 1; // x est déclaré après methode2 (); // methode2 () est déclarée après } void methode2 () { } int x;}

Java ne permet pas de déclarer de variables ou de fonctions globales. Mais, si vous tenez absolument àgarder le style de programmation procédurale du C, vous pouvez créer et utiliser des variables et desméthodes static, dans ce but.

La notion de fonction "amie" du C++ (friend) n'existe pas en Java : aucune méthode ne peut êtredéclarée en dehors d'une classe.

Contrairement au C++, toutes les méthodes d'instance non private sont virtuelles en Java. Donc lemot-clé virtual est inutile, ce qui peut éviter certains bugs difficiles à déceler en C++.

Les méthodes abstract sont l'équivalent des méthodes virtuelles pures du C++ (qui se déclarent enfaisant suivre la déclaration de la méthode de = 0).

Java introduit le mot-clé final. Ce modifieur empêche d'outrepasser une méthode dans les classesdérivées. Cette notion est absente du C++.

Toutes les méthodes Java sont déclarées et implémentées à l'intérieur de la classe dont elles dépendent.Mais, cela n'a pas pour conséquence de créer comme en C++ toutes les méthodes de Java inline !Avec l'option d'optimisation (-O), le compilateur lui-même évalue les méthodes final qui peuvent êtretraitées inline (remplacement de l'appel à la méthode par le code implémentant la méthode) : Donc, ilest important d'utiliser ce modifieur quand cela est nécessaire (pour les méthodes d'accès aux variablespar exemple).

La surcharge des opérateurs n'existe pas en Java. Seule la classe String autorise l'opérateur + pour laconcaténation.

Java ne permet pas de donner aux paramètres des valeurs par défaut comme en C++ (void f (int x,int y = 0, int z = 0); ). Vous êtes obligés de surcharger une méthode pour obtenir les mêmeseffets, en créant une méthode avec moins de paramètres qui rappellera la méthode avec les valeurs pardéfaut.

Page 39: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 10

L'appel aux méthodes static se fait grâce à l'opérateur point (.) et pas l'opérateur ::, comme en C++.

Une méthode reçoit la valeur de chacun des paramètres qui lui sont passés, et ces paramètres secomportent comme des variables locales :

1. Si un paramètre param est une référence sur un objet objet1, alors vous pouvez modifier lecontenu de objet1 ; par contre, si vous affectez à param une référence sur un autre objet, cettemodification n'aura d'effet qu'à l'intérieur du corps de la méthode. Si vous voulez mimer lepassage par valeur, vous pouvez utiliser la méthode clone () de la classe Object pour créer unecopie de l'objet objet1.

2. Si un paramètre est d'un type base, la modification de sa valeur n'a de portée qu'à l'intérieur ducorps de la méthode. Si vous voulez prendre en compte en dehors de la méthode la modificationdu paramètre, vous serez obligé de créer un objet dont la classe comporte une variablemémorisant cette valeur. Vous pourrez alors modifier la valeur comme indiqué en 1.(Voir aussi le chapitre traitant du portage de programmes C/C++ en Java).

Surcharge des méthodes

Une méthode methodeSurchargee (), est surchargée (overloaded ) quand elle est déclarée plusieurs foisdans une même classe ou ses classes dérivées, avec la même nom mais des paramètres de typesdifférents, ou de même type mais dans un ordre différent, comme dans l'exemple suivant :

class Classe1{ void methodeSurchargee (int entier) { // Corps de methodeSurchargee () } void methodeSurchargee (float nombre) { // Corps de methodeSurchargee () }} class Classe2 extends Classe1{ // Classe2 hérite de Classe1 donc elle déclare // implicitement toutes les méthodes de Classe1 void methodeSurchargee (float nombre, short param) { // Corps de methodeSurchargee () }}

Il est autorisé de surcharger une méthode en utilisant des paramètres de types différents pour chaqueméthode. Les valeurs de retours peuvent être aussi différentes, mais il est interdit de créer deuxméthodes avec les mêmes paramètres et un type de valeur de retour différent (par exemple, intmethode () et float methode ()).

En Java, une classe hérite de toutes les méthodes de la super classe dont elle dérive, même si ellesurcharge une ou plusieurs des méthodes de sa super classe. Dans l'exemple précédent, contrairementau C++, les méthodes que l'on peut invoquer sur un objet de classe Classe2 sont les 3 méthodesmethodeSurchargee (int entier), methodeSurchargee (float nombre) et methodeSurchargee (floatnombre, short param). En C++, le fait de surcharger la méthode methodeSurchargee () dans Classe2,interdit d'appeler directement sur un objet de classe Classe2 les méthodes surchargées de Classe1.

Constructeur

Chaque variable d'une classe peut être initialisée à une valeur par défaut à sa déclaration. Mais si vousvoulez initialiser certaines de ces variables avec une valeur donnée à la création d'un nouvel objet, ilvous faut déclarer une méthode spéciale appelée un constructeur.

Page 40: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 11

Un constructeur est appelée automatiquement à la création d'un objet, et les instructions du corps d'unconstructeur sont généralement destinées à initialiser les variables de l'objet nouvellement créé avec lesvaleurs récupérées en paramètre. Il a une syntaxe un peu différente de celle des méthodes :

class Classe1{ // Déclaration du constructeur sans paramètre remplaçant le constructeur par défaut public Classe1 () { // Corps du constructeur } ModifieurDeConstruceur Classe1 (TypeParam1 param1Name /* ... */) { // Corps du constructeur } ModifieurDeConstruceur Classe1 (/* ... */) throws TypeThrowable /*, TypeThrowable2 */ { // Corps du constructeur }}

Un constructeur porte le même nom que la classe où il est déclaré, et n'a pas de type de retour. Al'usage vous verrez que c'est une des méthodes qui est le plus souvent surchargée.Toute classe qui ne déclare pas de constructeur a un constructeur public par défaut sans paramètre quine fait rien. Aussitôt qu'un constructeur est déclaré avec ou sans paramètre, le constructeur par défautn'existe plus. Si vous avez déclarer dans une classe Classe1 un constructeur avec un ou plusieursparamètres, ceci oblige à préciser les valeurs de ces paramètres à la création d'un objet de la classeClasse1.

TypeThrowable est une classe dérivée de la classe Throwable. Les exceptions qui sont déclenchées vial'instruction throw doivent avoir leur classe déclarée après la clause throws. Voir le chapitre traitant desexceptions.

ModifieurDeConstruceur est optionnel et peut être un des mots-clés suivants : public, protected ouprivate. Ils sont utilisés de la même manière que pour les déclarations de méthodes.

Voici par exemple, une classe Classe1 n'utilisant pas de constructeur transformée pour qu'elle utilise unconstructeur :

class Classe1{ int var1 = 10; int var2;}

class Classe1{ int var1; int var2; public Classe1 (int valeur) { // Initialisation de var1 avec valeur var1 = valeur; }}

Le constructeur Classe1 (int valeur) sera appelé avec la valeur donnée par l'instruction de créationd'un objet de classe Classe1. Ce constructeur permet ainsi de créer un objet de classe Classe1 dont lavariable var1 est initialisée avec une valeur différente pour chaque nouvel objet.Mais quel est l'intérêt d'un constructeur puisqu'il est toujours possible de modifier une variable d'unobjet après sa création ?Un constructeur permet d'initialiser certaines variables d'un objet dès sa création, ce qui permet degarantir la cohérence d'un objet. En effet, même si vous précisez aux utilisateurs d'une classe qu'ilsdoivent modifier telle ou telle variable d'un nouvel objet avant d'effectuer certaines opérations surcelui-ci, rien ne garantit qu'ils le feront effectivement, ce qui peut être source de bugs.Un constructeur permet justement d'éviter ce genre de problème car toutes les variables d'un objetseront correctement initialisées au moment de sa création, ce qui garantit que les utilisateurs d'une classepourront effectuer n'importe quelle opération sur un objet juste après sa création.

Page 41: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 12

La plupart des classes de la bibliothèque Java utilisant un ou plusieurs constructeurs, vous serez souventamener à les utiliser en créant des objets et ceci vous permettra de comprendre comment en déclarervous-même dans vos propres classes.

Le corps d'un constructeur peut éventuellement commencé par une des deux instructions suivantes :

this (argument1 /*, argument2, ...*/); super (argument1 /*, argument2, ...*/);

La première instruction permet d'invoquer un autre constructeur de la même classe : il est souvent utilisépar un constructeur pour passer des valeurs pas défaut aux paramètres d'un autre constructeur.La seconde instruction permet d'appeler un constructeur de la super classe pour lui repasser des valeursnécessaires à l'initialisation de la partie de l'objet dépendant de la super classe, comme dans l'exemplesuivant :

class Classe1{ int variable; Classe1 (int var) { variable = var; }} class Classe2 extends Classe1{ int variable2; Classe2 (int var) { // Appel du constructeur de Classe1 avec la valeur 3 super (3); variable = var; } Classe2 () { // Appel du premier constructeur avec la valeur 2 this (2); }}

Si aucune des instructions précédentes n'est citée, Java considère qu'il y a implicitement un appel super();. Ceci implique que la super classe doit avoir un constructeur sans paramètre (déclaré explicitementou fourni par Java par défaut), et que par enchaînement, la création de tout nouvel objet de classeinvoquera le constructeur de sa classe et tous les constructeurs de des super classes.Donc si comme dans l'exemple précédent vous créez une classe Classe2 qui dérive d'une classe Classe1n'ayant pas de constructeur par défaut ou sans paramètre, vous serez obliger de déclarer au moins unconstructeur dans Classe2 qui rappelle un constructeur de la classe Classe1 avec l'instruction super(...);.

A partir de Java 1.1, le corps d'une classe peut comporter aussi un ou plusieurs blocs d'initialisationd'instance, qui sont comparables au constructeur par défaut. A la création d'un objet, un objet d'uneclasse Classe1 est initialisé dans l'ordre suivant :

Si Classe1 hérite d'une super classe Classe0, appel d'un constructeur de Classe0 soit par un appelexplicite à super (...), ou implicitement si Classe0 possède une constructeur par défaut. Exécution d'éventuels blocs d'initialisation d'instance déclarés dans Classe1. Exécution du constructeur de Classe1.

Page 42: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 13

Java introduit le mot-clé super : il permet de passer des valeurs d'un constructeur d'une classe auconstructeur de sa super classe grâce à l'appel super (arguments). En C++, il faut donner lesparamètres à passer au(x) constructeur(s) des supers classes à la suite de la déclaration d'unconstructeur.

Contrairement au C++, les constructeurs d'une même classe peuvent s'appeler entre eux en Java grâceà this (...). Cette fonctionnalité est très pratique pour remplacer l'absence de valeur par défaut desparamètres des constructeurs.

Java ne permet de passer les objets en paramètre que par référence. Le constructeur par recopie duC++, appelé pour construire les objets passés par valeur, n'est pas utile.

Création d'objets : opérateur new

La création d'objet (on dit aussi l'instanciation d'une classe) se fait grâce à l'opérateur new suivi d'un nomde classe et des arguments envoyés au constructeur :

new Classe1 (/* argument1, argument2, ...*/)

Un nouvel objet de classe Classe1 est créé, l'espace mémoire nécessaire pour les variables d'instance estalloué, ces variables sont ensuite initialisées puis finalement le constructeur correspondant aux types desarguments est appelé.La valeur renvoyée par l'opérateur peut être affectée à une référence de classe Classe1 ou de superclasse de Classe1 (voir les casts).Si Classe1 n'a pas encore été utilisée, l'interpréteur charge la classe, alloue l'espace mémoire nécessairepour mémoriser les variables static de la classe et exécutent les initialisations static.

A partir de Java 1.1, il est possible de créer des objets ayant une classe anonyme.

La méthode newInstance () de la classe Class permet aussi de créer un nouvel objet. Cette méthode estéquivalente à utiliser new sans argument, et donc si vous voulez utiliser newInstance () pour créer unobjet de classe Classe1, Classe1 doit avoir un constructeur sans paramètre (celui fourni par défaut oudéclaré dans la classe), sinon une exception NoSuchMethodError est déclenchée. Voir aussi l'applicationInstantiationAvecNom .A partir de Java 1.1, les méthodes newInstance () des classes java.lang.reflect.Constructor etjava.lang.reflect.Array permettent de créer un objet de n'importe quelle classe ayant un constructeuravec ou sans paramètres.

Une exception OutOfMemoryError peut être éventuellement déclenchée en cas de mémoire insuffisantepour allouer l'espace mémoire nécessaire au nouvel objet.

Page 43: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 14

La seule manière de créer des objets en Java se fait grâce à l'opérateur new. Vous ne pouvez pas commeen C++, créer des objets sur la pile d'exécution. Maintenant que vous connaissez comment créer une classe, un constructeur et un objet en Java,comparons un programme simple C avec un programme Java :

#include <stdlib.h>/* Déclaration du type Classe1 */typedef struct{ int var1; int var2;} Classe1; /* Fonction renvoyant la somme des *//* deux champs de objet */int division (Classe1 *objet){ return objet->var1 / objet->var2;} void main () { /* Allocation puis initialisation */ /* d'une instance de Classe1 */ Classe1 *objet1 = (Classe1 *) calloc (1, sizeof (Classe1)); objet1->var1 = 10; objet1->var2 = 20; int quotient = division (objet1);}

// Déclaration de la classe Classe1class Classe1{ int var1; int var2; // Constructeur de Classe1 // permettant d'initialiser // les variables var1 et var2 public Classe1 (int valeur1, int valeur2) { var1 = valeur1; var2 = valeur2; } // Méthode renvoyant la somme des // deux variables d'un objet de public int division () { return var1 / var2; } public static void main (String [] args) { // Création d'une instance de // Classe1 directement initialisée Classe1 objet1 = new Classe1 (10, 20); int quotient = objet1.division (); }}

Outrepasser une méthode

Une méthode methodeOutrepassee (), est outrepassée (overridden) si elle est déclarée dans une superclasse et une classe dérivée, avec le même nom, le même nombre de paramètres, et le même type pourchacun des paramètres.Les exemples qui suivent montrent l'intérêt de ce concept :

L'application suivante décrit une gestion de comptes en banque simplifiée et correspond au graphed'héritage décrit au chapitre précédent (sans la classe PEL). Recopiez la dans un fichier Banque.java , quevous compilez avec l'instruction javac Banque.java pour ensuite l'exécuter avec java ou Java Runner ,grâce à l'instruction java Banque :

class Compte{ private int numero; protected float soldeInitial; // Variable protected accessible // par les classes dérivées // Constructeur Compte (int nouveauNumero, float sommeDeposee) { // Mise à jour des variables de la classe numero = nouveauNumero; soldeInitial = sommeDeposee; } int numeroCompte ()

Page 44: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 15

{ return numero; } float calculerSolde () { return soldeInitial; }} // La classe CompteDepot dérive de la classe Compteclass CompteDepot extends Compte{ // Création d'un tableau de 1000 float pour les opérations private float operations [] = new float [1000]; private int nbreOperations; // Initialisée à 0 // Constructeur CompteDepot (int nouveauNumero) { // Appel du constructeur de la super classe super (nouveauNumero, 0); } void ajouterOperation (float debitCredit) { // Mémorisation de l'opération et augmentation de nbreOperation operations [nbreOperations++] = debitCredit; } float calculerSolde () // outrepasse la méthode de la classe Compte { float solde = soldeInitial; // Somme de toutes les opérations for (int i = 0; i < nbreOperations; i++) solde += operations [i]; return solde; }} // La classe CompteEpargne dérive de la classe Compteclass CompteEpargne extends Compte{ private float tauxInteretPourcentage; // Constructeur (tauxInteret en %) CompteEpargne (int nouveauNumero, float depot, float tauxInteret) { super (nouveauNumero, depot); tauxInteretPourcentage = tauxInteret; } float calculerSolde () // outrepasse la méthode de la classe Compte { return soldeInitial * (1f + tauxInteretPourcentage / 100f); }} // Classe d'exemplepublic class Banque{ // Méthode lancée à l'appel de l'instruction java Banque public static void main (String [ ] args) { // Création de 3 comptes de classe différente Compte compte101 = new Compte (105, 201.1f); CompteDepot compte105 = new CompteDepot (101); compte105.ajouterOperation (200); compte105.ajouterOperation (-50.5f); CompteEpargne compte1003 = new CompteEpargne (1003, 500, 5.2f); // Appel de la méthode editerSoldeCompte () sur chacun // des comptes. Cette méthode prend en paramètre une // référence de classe Compte : Les objets désignés par // compte105 et compte1003 sont d'une classe qui dérive // de la classe Compte, c'est pourquoi ils peuvent être

Page 45: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 16

// acceptés en paramètre comme des objets de classe Compte editerSoldeCompte (compte101); editerSoldeCompte (compte105); editerSoldeCompte (compte1003); } // Méthode éditant le numéro et le solde d'un compte static void editerSoldeCompte (Compte compte) { // Récupération du numéro et du solde du compte // La méthode calculerSolde () qui est appelée // est celle de la classe de l'objet désigné // par la variable compte int numero = compte.numeroCompte (); float solde = compte.calculerSolde (); System.out.println ( "Compte : " + numero + " Solde = " + solde); }}

Le résultat de ce programme donne ceci :

Compte : 105 Solde = 201.1Compte : 101 Solde = 149.5Compte : 1003 Solde = 526.0

La méthode editerSoldeCompte () reçoit en paramètre la variable compte. compte est une référencedésignant une instance de la classe Compte, ou d'une des classes dérivées de Compte, ici CompteDepot ouCompteEpargne.Que se passe-t-il à l'appel de la méthode calculerSolde () sur cette référence ?La Machine Virtuelle connait à l'exécution la classe de l'objet désigné par la référence compte : en plus,des variables d'instance qui sont allouées à la création d'une nouvelle instance des classes Compte,CompteDepot ou CompteEpargne, une variable cachée qui représente la classe du nouvel objet lui estajoutée. A l'appel compte.calculerSolde (), consulte cette variable pour connaître la classe de l'objetdésigné par compte. Une fois qu'il a cette classe il appelle l'implémentation de la méthode calculerSolde() de cette classe ce qui fait que la méthode calculerSolde () de la classe Compte ne seraeffectivement appelée que si l'objet désigné par compte est de classe Compte.

Globalement en Java, la manière d'appeler une méthode d'instance quelle qu'elle soit, respecte ceschéma : c'est la ligature dynamique (la bonne méthode à appeler n'est pas déterminée statiquement à lacompilation, mais dynamiquement à l'exécution en fonction de la classe de l'objet désigné). A premièrevue, son intérêt paraît pourtant limité aux méthodes outrepassées, mais souvenez-vous que toute classequi n'est pas final peut être appelée à être dérivée un jour, et que ses méthodes seront peut-êtreoutrepassées dans la classe dérivée. Il faut donc "préparer le terrain" pour ces méthodes...

Une méthode outrepassant une autre ne peut avoir un contrôle d'accès plus restrictif que la méthodeoutrepassée (pas possible d'avoir un accès protected ou private si la méthode outrepassée est public).L'ordre de priorité des contrôles d'accès est du plus restrictif au moins restrictif : private, friendly ,protected et public.

La notion de méthode outrepassée est fondamentale et contribue pour une grande part à la puissanced'un langage objet. Elle est très souvent utilisée en Java, car il vous faut souvent outrepasser lesméthodes des classes de la bibliothèque Java pour modifier leur comportement par défaut. On parlesouvent aussi de polymorphisme.

En Java, toutes les méthodes d'instance utilisent la ligature dynamique. Contrairement au C++, toutesles méthodes sont virtual.

Page 46: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 17

Faites très attention à bien respecter l'orthographe du nom et des types des paramètres des méthodes quevous outrepassez. Si la nouvelle méthode créée a un nom différent, elle n'outrepassera plus celle de lasuper classe, le compilateur ne vous dira rien et finalement la méthode appelée pourra être celle de lasuper classe au lieu de celle que vous avez déclaré.Par contre, les noms des paramètres n'ont pas d'importance, et peuvent être différents de ceux de laméthode outrepassée. Seules les méthodes sont outrepassées et pas les variables, comme le montre l'exemple suivant :

class Classe1{ final static int cste1 = 0;} class Classe2 extends Classe1{ // Déclaration d'une variable (constante) qui cache celle de Classe1 final static int cste1 = 1; void methode1 () { Classe2 objet2 = new Classe2 (); // création d'un objet de classe Classe2 int var = objet2.cste1; // var vaut 1 Classe1 objet1 = objet2; // cast de Classe2 vers Classe1 var = objet1.cste1; // var vaut 0 pourtant objet1 est une référence // sur un objet de classe Classe2 ! }}

Dans cet exemple, Classe2 a besoin de donner une valeur différente à cste1 pour les objets de cetteclasse : si on redéclare cette constante dans Classe2 avec une valeur différente, on pourrait s'attendre àce que objet1.cste1 vaille 1 puisque objet1 désigne un objet de classe Classe2. En fait, objet1.cste1renvoie la valeur de cste1 de la classe Classe1 (pas de ligature dynamique sur les variables)... Si vousvoulez que var vaille 1 dans les deux cas de cet exemple, vous devez créer une méthode dans chaqueclasse qui renvoie la valeur de cste1, comme par exemple :

class Classe1{ public int valeur1 () { return 0; }} class Classe2 extends Classe1{ public int valeur1 () // valeur1 () outrepasse la méthode de Classe1 { return 1; } void methode1 () { Classe2 objet2 = new Classe2 (); // création d'un objet de classe Classe2 int var = objet2.valeur1 (); // var vaut 1 Classe1 objet1 = objet2; // cast de Classe2 vers Classe1 var = objet1.valeur1 (); // var vaut 1 car c'est la methode // valeur1 () qui est appelée (objet1 // est une référence sur un objet de // classe Classe2) }}

Utilisation de classes abstract

Les classes abstract sont une catégorie spéciale de classe : il est impossible de créer une instance d'uneclasse abstract classeAbstract, mais par contre il est possible de déclarer une variable var1 qui est uneréférence de classe classeAbstract. var1 peut être égale à null ou désigner un objet d'une des classesdérivées de la classe classeAbstract à la condition suivante : Si la classe classeAbstract déclare une ouplusieurs méthodes d'instance abstract, la classe dérivée doit outrepasser ces méthodes et donner leur

Page 47: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 18

implémentation. Si cette classe ne donne pas l'implémentation de toutes les méthodes abstract, elle estelle-même abstract.Rappelez-vous qu'en fait, pour créer une instance d'une classe Classe1, il faut que toutes les méthodesde cette classe soient implémentées pour pouvoir les appeler, que ces méthodes soient déclarées dansClasse1 ou héritées des super classes de Classe1. Si une super classe déclare des méthodes abstract ilfaut donc que ces méthodes soient implémentées.De même, une interface est une sorte de classe abstract dont toutes les méthodes sont implicitementabstract. C'est pourquoi toute classe qui implémente une interface, doit implémenter toutes lesméthodes de l'interface pour ne pas être abstract.L'exemple suivant vous montre l'intérêt de l'utilisation d'une classe abstract :

abstract class Vehicule{ abstract int nombreDeRoues ();} class Velo extends Vehicule{ int nombreDeRoues () // outrepasse nombreDeRoues () de la classe Vehicule { return 2; }} class Voiture extends Vehicule{ int nombreDeRoues () // outrepasse nombreDeRoues () de la classe Vehicule { return 4; }} class VoitureAvecRemorque extends Voiture{ int nombreDeRoues () // outrepasse nombreDeRoues () de la classe Voiture { // super.nombreDeRoues () fait appel à la méthode outrepassée return 2 + super.nombreDeRoues (); }} class Classe1{ // Création de deux objets avec l'opérateur new Velo unVelo = new Velo (); Voiture uneVoiture = new Voiture (); // Déclaration d'une référence sur la super classe Vehicule // Comme la classe Vehicule est abstract, il est impossible de créer un // objet de cette classe, mais on peut affecter à cette référence // de classe Vehicule, un objet d'une classe dérivée de Vehicule Vehicule unVehicule; void methode () { int a = unVelo.nombreDeRoues (); // a est égal à 2 int b = uneVoiture.nombreDeRoues (); // b est égal à 4 unVehicule = unVelo; // cast de Voiture vers Vehicule int c = unVehicule.nombreDeRoues (); // c est égal à 2 unVehicule = uneVoiture; // cast de Voiture vers Vehicule int d = unVehicule.nombreDeRoues (); // d est égal à 4 }}

Dans cet exemple, unVehicule est une référence permettant de désigner un objet de classe Vehicule outoute autre classe dérivée de Vehicule. Quand nombreDeRoues () est invoquée sur la référenceunVehicule, l'interpréteur va consulter la classe réelle d'appartenance de l'objet référencé par unVehicule; une fois, qu'il a déterminé cette classe, il va appeler la méthode nombreDeRoues () de cette classe.

Page 48: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 19

Le mot-clé super permet aussi d'invoquer la méthode methode1 () outrepassée d'une super classeClasse1, par super.methode1 (). Il correspond à la notation Classe1::methode1 () du C++.Par contre, si Classe1 hérite elle-même d'une super classe Classe0, implémentant elle aussi methode1 (),vous ne pourrez pas appeler directement methode1 () de Classe0, comme vous le feriez en C++ grâce àClasse0::methode1 (). Mais ceci n'est pas souvent utilisé... Java ne permet pas d'utiliser des pointeurs sur fonctions. Dans certains cas, l'utilisation des méthodesoutrepassées est une alternative à cette absence. Voici un programme C et un programme Java mis enparallèle pour illustrer ce propos (l'exemple utilise une interface mais il est aussi possible d'utiliser uneclasse abstract) :

/* Déclaration d'un type pointeur sur *//* fonction prenant en paramètre un int */typedef void (* methodeX) (int i); /* Déclaration de deux fonctions du *//* même type que methodeX () */ void methodeX_1 (int i){ /* Corps de methodeX_1 () */ } void methodeX_2 (int i){ /* Corps de methodeX_2 () */ } /* Méthode appelant la méthode *//* de type methodeX */void appelMethodeX (methodeX methode, int i){ methode (i);} void appelMethodeXClasse1 (){ /* Appel de methodeX_1 () */ appelMethodeX (methodeX_1, 5);} void appelMethodeXClasse2 (){ /* Appel de methodeX_2 () */ appelMethodeX (methodeX_2, 10);}

// Déclaration d'une interface déclarant// une méthode prenant en paramètre un intinterface MethodeX{ void methodeX (int i);} // Déclaration de deux classes implémentant// la méthode methodeX () de cette interfaceclass Classe1 implements MethodeX{ public void methodeX (int i) { /* Corps de methodeX () */ }} class Classe2 implements MethodeX{ public void methodeX (int i) { /* Corps de methodeX () */ }} // Déclaration d'une classe utilisant// methodeX () de différentes classesclass ClasseUtilisantMethodeX{ // Méthode appelant la méthode methodeX () // d'une classe implémentant MethodeX void appelMethodeX (MethodeX objet, int i) { objet.methodeX (i); } void appelMethodeXClasse1 () { // Appel de methodeX () de Classe1 // La référence désignant l'objet créé // avec new Classe1 () peut être // casté en MethodeX car // Classe1 implémente MethodeX appelMethodeX (new Classe1 (), 5); } void appelMethodeXClasse2 () { // Appel de methodeX () de Classe2 appelMethodeX (new Classe2 (), 10); }}

Destruction des objets

Java gère de manière automatique pour le programmeur l'allocation dynamique de mémoire. La mémoirenécessaire à la mémorisation de tout nouvel objet est allouée dynamiquement à sa création, et la mémoirequ'il occupe est automatiquement libérée quand celui-ci n'est plus référencé par aucune variable duprogramme. Cette libération est réalisée grâce au Garbage Collector (littéralement Ramasseur d'Ordure)fourni avec la Machine Virtuelle Java.Cette fonctionnalité très pratique de Java simplifie énormément la programmation, d'autant plus qu'elleimplique que la notion de destructeur (méthode appelée à la destruction d'un objet en C++, très souvent

Page 49: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 20

utilisée pour libérer la mémoire utilisée par un objet) est beaucoup moins utile en Java.Toutefois, Java fournit une méthode à outrepasser dans vos classes si vous avez besoin d'effectuercertains traitements spécifiques à la destruction d'un objet : void finalize (). Cette méthode estinvoquée juste avant que le Garbage Collector ne récupère la mémoire occupée par l'objet.Normalement, vous ne l'utiliserez que rarement mais elle peut être utile pour libérer certaines ressourcesdont Java ne géreraient pas directement la destruction (contextes graphiques, ressources ou mémoirealloués par des méthodes native écrites en C ou C++).Vous pouvez éventuellement indiquer à la Machine Virtuelle qu'une référence var1 désignant un objetn'est plus utile en la mettant à null (var1 = null;), pour que le Garbage Collector puisse détruire l'objetdésigné par var1 si celui-ci n'est plus désigné par aucune référence.

En java, la destruction des objets se fait automatiquement quand ils ne sont plus utilisés (référencés).L'opérateur delete du C++ servant à détruire explicitement les objets créés dynamiquement est doncinutile.

En java, il n'existe pas de syntaxe prédéfinie pour les destructeurs. Vous pouvez outrepasser laméthode finalize () pour "nettoyer" vos objets mais contrairement au destructeur du C++ où ledestructeur est invoqué à l'appel de delete (), finalize () est invoquée automatiquement par leGarbage Collector quand un objet n'a plus aucune référence le désignant et qu'il peut donc être détruit.Le moment précis où va intervenir le Garbage Collector n'est pas prévisible, donc s'il vous fauteffectuer des opérations obligatoires quand un objet devient inutile (effacement d'un dessin à l'écranpar exemple), c'est à vous de créer une méthode que vous invoquerez au moment voulue (vouspouvez l'appeler delete () si vous voulez).

Comme en C++, les objets Java sont alloués dynamiquement à leur création via l'opérateur new. EnJava, c'est le seul moyen d'allouer de la mémoire, donc il n'existe plus de fonctions telles que malloc(), realloc () ou free (). L'opérateur sizeof () servant surtout pour évaluer la taille d'un objet àallouer n'existe plus non plus. En C, sizeof () est utile aussi pour la portabilité d'un programme, cartous les types de base n'ont pas la même taille suivant les systèmes (int peut avoir une taille de 16 ou32 bits, par exemple) : en Java, tous les types de base ont la même taille.

Comment ça marche ?

Pour mieux comprendre comment Java manipule les objets de leur création à leur destruction, voici unefigure décrivant la vie d'un objet :

figure 7. La vie d'un objet Java de sa création à sa destruction

Page 50: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 21

Ce programme très simple vous montre la nuance très importante entre une référence et un objet : unmême objet peut avoir n'importe quel nombre de références le désignant, mais une référence ne peutdésigner qu'un seul objet à la fois.A tout moment, la Machine Virtuelle connaît le nombre de références (ou de variables) qui désignentchacun des objets d'un programme : quand pour un objet, ce nombre devient nul, ceci signifie que plusaucune variable du programme ne désigne cet objet. S'il n'existe plus de variable désignant cet objet, leprogramme n'a donc plus de moyen de le manipuler, il est logique de le considérer comme inutile et dele supprimer.

Pour vous montrer toute la puissance et l'intérêt du Garbage Collector, voici un programme C et unprogramme Java mettant en oeuvre l'utilisation de listes chaînées :

#include <stdlib.h>/* Déclaration d'un type de liste chaînée */typedef struct _eltListe{ int nombre; struct _eltListe *suivant;} EltListe, *ListeChainee; /* Crée une liste d'éléments ayant *//* leur nombre compris entre min et max */ListeChainee creerListe (int min, int max){ ListeChainee elt = (ListeChainee) malloc (sizeof (EltListe)); elt->nombre = min; if (min < max) elt->suivant = creerListe (min +1, max); else elt->suivant = NULL; return elt;} /* Enlève un élément individuel */ListeChainee enleverElement (ListeChainee liste, int nombre){ ListeChainee eltCherche; ListeChainee eltPrecedent = NULL; /* Recherche de l'élément contenant */ /* le nombre */ for (eltCherche = liste; eltCherche != NULL; eltCherche = eltCherche->suivant) if (eltCherche->nombre != nombre) eltPrecedent = eltCherche; else { /* Suppression de l'element */ /* de la liste chaînée */ if (eltCherche == liste) liste = liste->suivant; else eltPrecedent->suivant = eltCherche->suivant; free (eltCherche); } return liste;} /* Libère la mémoire prise par tous *//* les éléments de la liste */void viderListe (ListeChainee liste){ while (liste != NULL) { ListeChainee eltPrecedent = liste;

// Déclaration d'une classe de liste chaînéepublic class ListeChainee{ int nombre; ListeChainee suivant; // Construit une liste d'éléments ayant // leur nombre compris entre min et max ListeChainee (int min, int max) { nombre = min; if (min < max) suivant = new ListeChainee (min + 1, max); else suivant = null; } // Enlève un élément individuel ListeChainee enleverElement (int nombre) { ListeChainee eltCherche; ListeChainee eltPrecedent = null; // Recherche de l'élément contenant // le nombre (this désigne la tête // de liste elle-même) for (eltCherche = this; eltCherche != null; eltCherche = eltCherche.suivant) if (eltCherche.nombre != nombre) eltPrecedent = eltCherche; else // Suppression de la référence sur // de l'element recherche, l'objet // peut donc être supprimé if (eltCherche == this) return this.suivant; else eltPrecedent.suivant = eltCherche.suivant; return this; } // void viderListe ()// est inutile

Page 51: CJava

vendredi 11 février 2000 Du C/C++ à Java : Création et utilisation des classes Page: 22

liste = liste->suivant; free (eltPrecedent); }} void main () { ListeChainee liste = creerListe (1, 10); liste = enleverElement (liste, 8); viderListe (liste);}

public static void main (String [ ] args) { ListeChainee liste = new ListeChainee (1, 10); liste = liste.enleverElement (8); liste = null; }}

L'instruction liste = null entraîne que l'unique référence sur l'objet de tête de liste est perdue, donc leGarbage Collector peut supprimer cet objet. Quand il le supprime, la variable suivant de cet objet estsupprimée et il n'existe plus de référence sur l'élément suivant. Ce dernier peut être supprimé à son tour,ainsi de suite jusqu'à qu'au dernier élément de la liste. Dans cet exemple, liste = null n'est même pasobligatoire car la variable liste est supprimée à la sortie de la méthode main (), ce qui provoque lesmêmes effets.Une fois compris l'exemple précédent, vous pouvez essayer de créer à partir de celui-ci une classe deliste doublement chaînée (avec liens suivant et precedent).

Si vous ne voulez pas croire en la magie, il vous faudra sûrement un certain temps pour faire confianceau Garbage Collector sans arrière pensée. Ce type de gestion de la mémoire étant très pratique, le réflexede ne plus libérer la mémoire explicitement comme en C/C++ (avec free () ou delete) s'acquièred'office, mais vous prendrez plus de temps à comprendre comment vos objets sont détruits dans telle outelle situation.La meilleure piste pour répondre à vos interrogations, est de vous demander par combien de variablessont référencés le ou les objets sur lesquels vous avez des doutes. Si par enchaînement, ce nombretombe à 0, vous pouvez oublier vos doutes. Comme en Java, vous ne détruisez pas explicitement les objets, toute référence est égale soit à null soitelle désigne un objet TOUJOURS valide. Vous ne pouvez pas avoir de risque de manipuler un objet quin'existe plus comme dans le programme C suivant :

void fonction1 (){ char *chaine = malloc (20); strcpy (chaine, "bonjour\n"); /* ... */ free (chaine); /* ... */ printf (chaine);}

En C, si dans un programme vous utilisez par erreur un pointeur après avoir libéré l'espace mémoire qu'ildésigne, le compilateur ne vous indiquera aucune erreur. De plus, ce genre d'erreur est souvent difficile àtrouver.En Java, si vous essayez d'accéder à un objet par une référence égale à null, une exceptionNullPointerException est déclenchée.

Page 52: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 1

Objets, tableaux et chaînes de caractères

La classe ObjectLa classe Class

Les tableauxLes chaînes de caractères

La classe StringLa classe StringBuffer

La classe System

La classe Object

Java étant un langage pur objet, la première classe à étudier est naturellement la super classe donthéritent implicitement toute les autres (celles fournies avec Java et celles que vous créerez) : la classeObject.Cette classe comporte un petit nombre de méthodes, dont toutes les autres classes héritent et quecertaines classes dérivées peuvent éventuellement outrepasser. Les classes différentes de la classeObject utilisées par ces méthodes seront détaillées ultérieurement.

Constructeur

public Object ()

Méthodes

public final Class getClass ()

Renvoie la classe d'un objet. A l'exécution, chaque classe utilisée dans un programme est représentée parune instance de la classe Class.

public boolean equals (Object obj)

Renvoie true si les deux objets (l'objet sur lequel est invoqué equals () et obj) sont égaux, false sinon.Il faut entendre par égaux, s'ils désignent le même objet. Une classe doit outrepasser cette méthode, sielle veut que la signification de l'égalité entre deux objets soit moins stricte, par exemple en comparant lavaleur de leurs variables.

public int hashCode ()

Renvoie un code entier utilisé pour le stockage des objets dans les tables de hash (Hashtable). Si uneclasse outrepasse equals (), elle doit en général outrepasser aussi hashCode () pour renvoyer le mêmecode pour deux objets égaux par la méthode equals (). La condition inverse n'est pas obligatoire (deuxobjets peuvent renvoyer un code de hash identique mais être différents par la méthode equals ()).La méthode hashCode () de la classe Object renvoie l'adresse d'un objet.

protected Object clone () throws CloneNotSupportedException

Duplique un objet. Un objet de la même classe que l'objet sur lequel on invoque clone () est créé avecune copie de toutes ses variables. Renvoie le nouvel objet.Une exception OutOfMemoryError peut être éventuellement déclenchée en cas de mémoire insuffisante.L'exception CloneNotSupportedException est déclenchée si la classe de l'objet cloné ou une de sessuper classes n'implémente pas explicitement l'interface Cloneable.La méthode clone () est protected donc pour pouvoir dupliquer un objet objet1 de classe Classe1 parl'expression objet1.clone (), Classe1 doit outrepasser clone () et lui donner un contrôle d'accèspublic. Comme toutes les classes dérivent de la classe Object, cette méthode n'est en fait utile pour lesautres classes que pour créer un nouvel objet de même classe et copier la valeur de toutes les variables

Page 53: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 2

de l'original.Si une des variables recopiées est une référence sur un objet, seule la référence est recopiée et désignerale même objet. Donc, si vous voulez que les références clonées désignent des objets différents, vousdevez cloner ces objets vous même, dans la méthode clone ().Voici un exemple d'utilisation de clone () :

class Classe0 implements Cloneable{ double unNombre; public Object clone () throws CloneNotSupportedException { // Appel de la méthode clone () de la classe Object return super.clone (); } // ...} class Classe1 implements Cloneable{ int var; Classe0 objet0 = new Classe0 (); public Object clone () throws CloneNotSupportedException { // Appel de la méthode clone () de la classe Object // puis clonage de objet0 Classe1 nouveau = (Classe1)super.clone (); // cast de Object vers Classe1 nouveau.objet0 = (Classe0)objet0.clone (); // cast de Object vers Classe0 return nouveau; } // ...} public String toString ()

Renvoie une chaîne de caractères représentant la valeur d'un objet. Chaque classe devrait outrepassercette méthode pour créer une chaîne représentant la valeur de leurs instances. La méthode toString ()de la classe Object renvoie le nom de la classe de l'objet sur lequel on invoque cette méthode, suivi ducaractère '@' et de la valeur en hexadécimal renvoyée par hashCode ().

public final void notify () throws IllegalMonitorStateExceptionpublic final void notifyAll () throws IllegalMonitorStateExceptionpublic final void wait (long millis ) throws IllegalMonitorStateException, InterruptedExceptionpublic final void wait (long millis, int nanos) throws IllegalMonitorStateException, InterruptedExceptionpublic final void wait () throws IllegalMonitorStateException, InterruptedException

Ces méthodes sont utilisées pour prévenir ou attendre des threads (tâches) synchronisés sur l'accès à unobjet. millis désigne un nombre de millisecondes et nanos un nombre de nanosecondes. wait (0) etwait (0, 0) sont équivalentes à wait ().Ces méthodes seront développées ultérieurement, dans le chapitre sur les threads. Notez qu'étant final,elles ne peuvent être outrepassées dans les classes dérivées.

protected void finalize() throws Throwable

Cette méthode est invoquée automatiquement avant qu'un objet soit détruit par le Garbage collector. Lesclasses ayant des traitements spécifiques à effectuer à la destruction d'un objet, doivent outrepasser cetteméthode. La méthode finalize () de la classe Object ne fait rien. Voir aussi la destruction d'objets.

Toutes les classes Java héritent de la classe Object. Vous ne pouvez créer plusieurs hiérarchies declasses comme en C++.

La classe Class

Cette classe final permet de représenter chacune des classes (et des interfaces) chargées par la Machine

Page 54: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 3

Virtuelle Java, en faisant correspondre à chaque classe une instance de classe Class.

Méthodes

public static Class forName (String className) throws ClassNotFoundException

Renvoie un objet de classe Class correspondant à la classe ou à l'interface de nom className. classNamedoit être un nom de classe complet avec package (comme par exemple java.lang.Object). Comme laclasse Class n'a pas de constructeur public, les seules manières de récupérer une instance de classeClass sont de passer par cette méthode ou la méthode getClass () de la classe Object.

public Object newInstance () throws InstantiationException, IllegalAccessException

Crée une nouvelle instance d'une classe. Cette méthode est moins pratique que l'opérateur new pourcréer des objets car il faut intercepter les exceptions InstantiationException etIllegalAccessException que peut déclencher la méthode newInstance ().Associée à la méthode forName (), elle est par contre très utile pour instancier des objets d'une classedont vous n'avez que le nom et qui a un constructeur sans paramètre, comme par exempleClass.forName ("java.lang.Object").newInstance () qui crée un objet de classe Object. Voir aussi lacréation d'objets et l'application InstantiationAvecNom .

public ClassLoader getClassLoader ()

Renvoie le chargeur de classe utilisé pour charger une classe ou null si c'est le chargeur par défaut.

public String getName ()

Renvoie le nom complet d'une classe (avec son package).

public Class getSuperclass ()

Renvoie la super classe d'une classe.

public Class [ ] getInterfaces ()

Renvoie un tableau des interfaces implémentées par une classe. Si la classe n'implémente aucuneinterface ce tableau a une longueur nulle (length = 0).

public boolean isInterface ()

Renvoie true ou false suivant que l'objet sur lequel cette méthode est appelée est une interface ou uneclasse.

public String toString ()

Cette méthode renvoie le nom de la classe ou de l'interface précédé des mots class ou interface .toString () outrepasse la méthode de la classe Object.

La méthode equals () de la classe Object n'est pas outrepassée dans cette classe car c'est inutile :Comme à chaque classe chargée par la Machine Virtuelle correspond une instance de la classe Classunique, vous pouvez comparez deux objets de classe Class directement avec l'opérateur == ou !=.

A partir de Java 1.1, cette classe a été très enrichie et comporte des méthodes qui permettent d'interrogertoutes les variables, les méthodes et les contructeurs d'une classe.

Les tableaux

Comme tout type qui n'est pas un type de base, les tableaux sont des objets alloués dynamiquement.Les éléments du tableau peuvent être d'un type de base, d'une classe ou d'une interface, et le tableaului-même hérite de la classe Object et de toutes ses méthodes.Comme en C, un tableau contenant n éléments, a son premier élément à l'indice 0 et son dernier àl'indice n-1. Une référence table qui désigne un tableau peut accéder à la variable length de ce tableau(table.length) pour déterminer le nombre d'éléments mémorisés dans celui-ci.

Page 55: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 4

Exemple de déclarations et de créations de tableaux :

class Classe1{ // Déclaration de références sur des tableaux int [ ] tableEntiers; float tableFloats [ ]; // Les crochets peuvent être avant ou après la variable Object [ ] tableObjets; Cloneable [ ] tableClonaeable; // Création de tableaux int [ ] tableEntiers2 = new int [5]; Object [ ] tableObjets2 = new Object [10]; Cloneable [ ] tableClonaeable2 = new Cloneable [10]; // Création d'un tableau de longueur nulle int [ ] tableauVide = new int [0]; // Création de tableaux initialisés long [ ] tableLongs = {1L, 2L, 5L}; Classe1 objet1 = new Classe1 (); Classe1 [ ] tableObjets3 = {objet1, new Classe1 (), null}; short [ ][ ] tableShorts = {{1, 2}, {1, 2, 3}, null, {0}}; int [ ] tableauVide2 = {}; }

A partir de Java 1.1, les méthodes static newInstance () de la classe java.lang.reflect.Arraypermettent aussi de créer des tableaux comme dans l'exemple suivant :

import java.lang.reflect.*; public class ClasseJava11{ public static void main (String [] args) throws ClassNotFoundException { // Autre possibilité de création de tableaux à partir de Java 1.1 Object tableEntiers = Array.newInstance (int.class, 5); float [] tableFloats = (float [])Array.newInstance (float.class, 2); Object tableObjets = Array.newInstance (Class.forName ("java.lang.Object"), 10); }}

Un tableau peut être créé avec une longueur nulle. Quel en est l'intérêt ?

Certaines méthodes comme getInterfaces () de la classe Class renvoie un tableau qui peutn'avoir aucun élément. Après avoir appelé une telle méthode, vous n'aurez pas à tester si laréférence renvoyée est égale à null avant de lancer une boucle sur les n éléments du tableaurenvoyé. Si table désigne un tableau de longueur nulle, on peut connaître la classe du tableau grâce àtable.getClass () mais pas si table est égal à null.

Une fois qu'un tableau est créé, sa taille ne peut être modifiée ; par contre, la classe System du packagejava.lang fournit la méthode arraycopy () permettant de copier une partie d'un tableau dans un autre,et la classe Vector du package java.util est idéale pour manipuler des tableaux de taille variable.

Les valeurs d'un tableau créé grâce à l'opérateur new sont initialisées à leur valeur par défaut.

Dans un soucis de sécurité, Java vérifie si les tableaux sont manipulés correctement :

Si l'accès à un élément i (grâce à table [i]) est invalide (i < 0 ou i >= table.length), Javadéclenche une exception ArrayIndexOutOfBoundsException. Si à la création d'un tableau, la taille requise est négative une exceptionNegativeArraySizeException est déclenchée. Si vous tentez de stocker dans un tableau un élément incompatible avec ceux du tableau, uneexception ArrayStoreException est déclenchée.

Java permet de créer les tableaux multi-dimensionnels de deux manières différentes : vous pouvez créer

Page 56: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 5

un tableau directement avec plusieurs dimensions ou créer vous même les sous tableaux, un par un,comme dans l'exemple suivant, permettant de créer un tableau de taille dim1 x dim2 initialisé avecvaleurDefaut :

class Classe1{ public int [ ][ ] methode1 (int dim1, int dim2) { int [ ][ ] table1 = new int [dim1][dim2]; // Création d'un tableau dim1 x dim2 return table1; } public int [ ][ ] methode2 (int dim1, int dim2, int valeurDefaut) { int [ ][ ] table1 = new int [dim1][ ]; // Création de la première dimension int i, j; for (i = 0; i < dim1; i++) { table1 [i] = new int [dim2]; // Création de la deuxième dimension for (j = 0; j < dim2; j++) table1 [i][j] = valeurDefaut; } return table1; }}

L'avantage de ce système est que vous pouvez créer des sous tableaux de dimensions différentes (pourcréer un triangle de Pascal, par exemple).

Il est possible d'interroger la classe d'un tableau et le nom de cette classe, grâce aux méthodes getClass() de la classe Object et getName () de la classe Class. Ce nom est construit avec en tête autant decaractère [ que le nombre de dimensions du tableau suivi soit du caractère L, du nom de la classe ou del'interface complet et d'un point virgule (;) si le tableau mémorise des références sur des objets, soit d'undes caractères suivant si le tableau mémorise des valeurs d'un des types de base :

Caractère Type des élémentsdu tableau

B byte

C char

D double

F float

I int

J long

L classe ou interface

S short

Z boolean

Par exemple, (new Object [3]).getClass ().getName () renvoie "[Ljava.lang.Object;" et (newdouble [0][0]).getClass ().getName () renvoie "[[D".Avec Java 1.0, il est impossible de créer une nouvelle instance d'un tableau, en connaissant sa classe eten utilisant la méthode newInstance () de la classe Class. Par exemple, si vous exécutez l'instruction(new int [2]).getClass ().newInstance (), une exception InstantiationException sera déclenchée.A partir de Java 1.1, l'utilisation des méthodes static newInstance () de la classejava.lang.reflect.Array, permet de résoudre ce problème, comme dans l'exemple Array.newInstance(Class.forName ("java.lang.Object"), 5).

Les tableaux implémentant implicitement l'interface Cloneable, il est possible de les dupliquer grâce à laméthode clone () de la classe Object. Si le tableau comporte plus d'une dimension, il faut dupliquer

Page 57: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 6

aussi les sous-tableaux pour obtenir une copie complète, comme dans l'exemple :

class Classe1{ void methode1 () { int [ ][ ] table = {{15, 20, 30}, { 5, 10, 15}}; // Duplication de la première dimension int [ ][ ] tableClone = (int [][])table.clone (); int i; for (i = 0; i < table.length; i++) // Duplication des sous tableaux tableClone [i] = (int [])table [i].clone (); }}

La création d'un tableau de n objets ne crée pas n instances pour les n éléments du tableau, maisuniquement n références à des objets. C'est à vous d'affecter chacune de ces références, soit à unnouvel objet à créer, soit à un objet existant.De même, la duplication d'un tableau de n objets avec la méthode clone () de la classe Object, necrée aucune copie des objets qu'il contient.

Les tableaux sont une sorte de classe final (pas dérivable) en Java. Ils sont d'un abord plus simplequ'en C, langage dans lequel ils peuvent être utilisés comme des pointeurs, ce qui sème souvent laconfusion chez les débutants.

Les tableaux Java sont alloués dynamiquement. Ils comportent une variable length indiquant le nombred'éléments du tableau et Java vérifie les dépassements d'indice quand on accède à un élément.

Les tableaux étant des objets, il est possible de créer des tableaux de longueur nulle. L'instructionObject [ ] table = { }; crée un tableau qui ne contient aucun objet et qui est désigné par laréférence tab. Par contre l'instruction Object [ ] table = null; initialise la référence tab à null sanscréer d'objet.

L'accès aux tableaux étant en Java, bien protégé par les exceptions, l'impossibilité de pouvoir surchargerl'opérateur [ ], comme en C++, ne s'avère pas si importante.

Les chaînes de caractères

Les chaînes de caractères sont représentées en Java par les classes String ou StringBuffer. Ces deuxclasses ne jouent pas exactement le même rôle :

String est utilisé pour représenter les chaînes de caractères constantes, qui peuvent être partagéessans risque par plusieurs threads, puisque leur contenu ne peut pas être changé. StringBuffer est utilisé pour les chaînes de caractères dont on veut modifier le contenu.

Toutes les chaînes de caractères Java mémorisent des caractères de type char, donc des caractèresUnicode codés sur 16 bits.

Les objets de classe String peuvent être initialisés directement avec une chaîne de caractères, sanspasser par le constructeur :

class Classe1{ // Deux manières différentes de créer un objet // de classe String avec la chaîne "Bonjour" String chaine1 = "Bonjour"; String chaine2 = new String ("Bonjour");}

Les chaînes de caractères Java peuvent utiliser l'opérateur + pour effectuer des concaténations. De plus,l'opérateur + peut convertir automatiquement les valeurs littérales et les objets (en appelant leur méthodetoString ()), pour fabriquer une chaîne, comme dans l'expression suivante :

"Bonjour au numéro " + 1 + " et à l'objet " + unObjet

Page 58: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 7

Si unObjet est égal à null, la chaîne de conversion est "null".En fait, le compilateur convertit les opérateurs + utilisés en appel aux différentes méthodes append () de laclasse StringBuffer. Le premier argument de l'opérateur + doit être de classe String, c'est à dire soit unechaîne de caractères entre guillemets "abc" ou un objet de classe String. Pour les objets des autres classes,utilisez la méthode toString () pour obtenir une chaîne de caractères, et pour les variables de type de baseutilisez les méthodes static valueOf () de la classe String.

En Java, les chaînes de caractères sont représentées par deux classes, l'une String pour les chaînesconstantes, l'autre StringBuffer pour les chaînes modifiables. A la différence du C, elles ne sont pasune application particulière des tableaux et ne se terminent pas par le caractère nul ('\u0000').

L'opérateur + permet d'effectuer la concaténation de chaînes, de valeurs littérales et d'objets. Adieustrcat (), printf () et compagnie !

Les opérateurs << et >> utilisés sur les streams pour fabriquer plus facilement des chaînes en C++, ontleur équivalent avec l'opérateur + sur les chaînes de caractères en Java.

La classe String

La classe String qui est final comporte de nombreuses méthodes. En voici la liste (quelques méthodemineures ont été ajoutées à partir de Java 1.1) :

Constructeurs

public String (String value)

Construit une nouvelle chaîne qui est la copie de value.

public String (char value [ ])

Construit une nouvelle chaîne initialisée avec la suite de caractères données dans le tableau value.

public String (byte ascii [ ], int hibyte)

Construit une nouvelle chaîne initialisée avec la suite d'octets donnée dans le tableau ascii ; chaquecaractère ASCII du tableau ascii est transformé en un caractère Unicode, en utilisant hibyte pour lapartie haute du caractère.Autres constructeurs :

public String ()public String (char value [ ], int offset, int count) throws IndexOutOfBoundsExceptionpublic String (byte ascii [ ], int hibyte, int offset, int count) throws IndexOutOfBoundsExceptionpublic String (StringBuffer buffer)

Méthodes

public int length ()

Renvoie la longueur de la chaîne, c'est à dire le nombre de caractères Unicode de la chaîne.

public char charAt (int index)

Renvoie le caractère à l'indice index (index est compris entre 0 et length () - 1).

public void getChars (int srcBegin, int srcEnd, char dst [ ], int dstBegin) throws IndexOutOfBoundsExceptionpublic void getBytes (int srcBegin, int srcEnd, byte dst [ ], int dstBegin) throws IndexOutOfBoundsExceptionpublic char [ ] toCharArray () public int hashCode ()

Cette méthode outrepasse la méthode hashCode () de la classe Object, pour renvoyer un code différent

Page 59: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 8

si deux chaînes de caractères sont différentes.

public boolean equals (Object anObject)

Cette méthode outrepasse la méthode equals () de la classe Object, pour renvoyer true si anObject estde la classe String, et si les deux chaînes de caractères sont les mêmes.

public boolean equalsIgnoreCase (String anotherString)

Comme equals () mais la comparaison est faite sans tenir compte des majuscules/minuscules deschaînes comparées.

public int compareTo (String anotherString)

Compare une chaîne de caractères avec anotherString. Renvoie une valeur négative, nulle, ou positivesuivant que la chaîne de caractère est respectivement plus petite, égale ou plus grande queanotherString.

public boolean regionMatches (int toffset, String other, int ooffset, int len)public boolean regionMatches (boolean ignoreCase, int toffset, String other, int ooffset, int len)public boolean startsWith (String prefix, int toffset)public boolean startsWith (String prefix)public boolean endsWith (String suffix)

Ces méthodes permettent de comparer une partie d'une chaîne de caractères à une autre (entre deuxindices, au début ou à la fin).

public int indexOf (int ch)public int indexOf (int ch, int fromIndex)public int lastIndexOf (int ch)public int lastIndexOf (int ch, int fromIndex)public int indexOf (String str)public int indexOf (String str, int fromIndex)public int lastIndexOf(String str)public int lastIndexOf (String str, int fromIndex)

Renvoient l'indice de la première ou la dernière occurrence d'un caractère ch ou d'une chaîne str dansune chaîne de caractères, ou -1 si aucune occurrence n'a pas été trouvée.

public String substring (int beginIndex)public String substring (int beginIndex, int endIndex)

Renvoient une sous-chaîne d'une chaîne de caractères, à partir de l'indice beginIndex ou entre les deuxindices beginIndex et endIndex (endIndex exclu).

public String concat (String str)

Renvoie la chaîne, résultat de la concaténation de str à la fin d'une chaîne de caractères.

public String replace (char oldChar, char newChar)

Renvoie une chaîne où tous les caractères oldChar sont convertis en newChar.

public String toLowerCase ()public String toUpperCase ()

Renvoie une chaîne où tous les caractères majuscules sont convertis en minuscules, et inversement.

public String trim ()

Renvoie une chaîne où tous espaces en tête et en queue d'une chaîne de caractères sont supprimés.

public static String valueOf (char data [ ])public static String valueOf (char data [ ], int offset, int count) throws IndexOutOfBoundsException

Ces méthodes permettent de créer des chaînes de caractères à partir de tableaux de caractères.

Page 60: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 9

public static String valueOf (Object obj)

Renvoie une chaîne représentant la valeur de obj sous forme de chaîne de caractères. En fait, équivalentà obj.toString ().

public static String valueOf (boolean b)public static String valueOf (char c)public static String valueOf (int i)public static String valueOf (long l)public static String valueOf (float f)public static String valueOf (double d)

Renvoie une chaîne de caractères correspondant à la valeur des types par défaut (voir aussi les classesInteger, Long, Float et Double qui fournissent des méthodes pour convertir un nombre en une chaînede caractères et inversement).

public String intern () public String toString ()

Méthode de la classe Object, outrepassée pour qu'elle renvoie la chaîne de caractères.

La classe StringBuffer

La classe StringBuffer contrairement à la classe String, utilise un buffer de taille variable pourmémoriser une chaîne de caractères modifiables. Cette classe final maintient elle-même l'allocationd'espace supplémentaire pour mémoriser des caractères supplémentaires. Voici la liste des méthodes decette classe :

Constructeurs

public StringBuffer ()

Construit une chaîne vide.

public StringBuffer (int length) throws NegativeArraySizeException

Construit une chaîne vide, avec une taille initiale length.

public StringBuffer (String str)

Construit une chaîne vide, à partir de la chaîne str.

Méthodes

public int length ()

Renvoie le nombre de caractères mémorisés dans de la chaîne.

public int capacity ()

Renvoie la capacité courante de la chaîne, représentant le nombre de caractères qu'il est possibled'insérer, avant qu'il ne soit alloué de l'espace supplémentaire.

public synchronized void ensureCapacity (int minimumCapacity)

Permet de s'assurer, que la chaîne à une capacité d'au moins minimumCapacity caractèressupplémentaires.

public synchronized void setLength (int newLength) throws IndexOutOfBoundsException

Modifie la taille de la chaîne. Si la chaîne actuellement mémorisée est plus longue, elle sera tronquée.Les caractères éventuellement ajoutés sont nuls ('\u0000'), pour que length () renvoie la valeur

Page 61: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 10

newLength.

public synchronized char charAt (int index) throws IndexOutOfBoundsException

Renvoie le caractère mémorisé à l'indice index (valeur comprise entre 0 et length () - 1).

public synchronized void getChars (int srcBegin, int srcEnd, char dst [ ], int dstBegin) throws IndexOutOfBoundsException

Copie à l'indice dstBegin du tableau dst les caractères compris entre les indices srcBegin et srcEnd.

public synchronized void setCharAt (int index, char ch) throws IndexOutOfBoundsException

Change par ch le caractère à l'indice index de la chaîne.

public synchronized StringBuffer append (Object obj)public synchronized StringBuffer append (String str)public synchronized StringBuffer append (char str [ ])

Ajoute en fin de chaîne un objet, une chaîne ou un tableau de caractères.

public synchronized StringBuffer append (char str [ ], int beginIndex, int length) throws IndexOutOfBoundsException

Ajoute en fin de chaîne les caractères du tableau str, compris entre beginIndex et beginIndex + length- 1.

public synchronized StringBuffer append (char c)public StringBuffer append (boolean b)public StringBuffer append (int i)public StringBuffer append (long l)public StringBuffer append (float f)public StringBuffer append (double d)

Ajoute en fin de chaîne la valeur d'un type de base convertie en chaîne.

public synchronized StringBuffer insert (int offset, Object obj) throws IndexOutOfBoundsExceptionpublic synchronized StringBuffer insert (int offset, String str) throws IndexOutOfBoundsExceptionpublic synchronized StringBuffer insert (int offset, char str [ ]) throws IndexOutOfBoundsException

Insère à l'indice offset d'une chaîne un objet, une chaîne ou un tableau de caractères.

public synchronized StringBuffer insert (int offset, char c) throws IndexOutOfBoundsExceptionpublic StringBuffer insert (int offset, boolean b) throws IndexOutOfBoundsExceptionpublic StringBuffer insert (int offset, int i) throws IndexOutOfBoundsExceptionpublic StringBuffer insert (int offset, long l) throws IndexOutOfBoundsExceptionpublic StringBuffer insert (int offset, float f) throws IndexOutOfBoundsExceptionpublic StringBuffer insert (int offset, double d) throws IndexOutOfBoundsException

Insère à l'indice offset d'une chaîne la valeur d'un type de base convertie en chaîne.

public synchronized StringBuffer reverse ()

Inverse les caractères d'une chaîne.

public String toString ()

Méthode de la classe Object, outrepassée pour qu'elle renvoie la chaîne de caractères mémorisée.

Page 62: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 11

Les méthodes append (), insert () et reverse () renvoie l'objet de classe StringBuffer lui-même,une fois modifié.

La classe System

Cette classe final permet d'accéder à différentes fonctionnalités du système de la Machine VirtuelleJava, et comportent plusieurs variables et méthodes très utiles.Toutes les variables et les méthodes de cette classe sont static.Les variables in, out et err permettent de sortir ou de lire sur l'entrée et la sortie standard ; out estparticulièrement pratique pour imprimer des chaînes au moment du debug des applications Java avecjava , ou des applets avec appletviewer ou avec certains navigateurs (Microsoft Internet Explorer etNetscape Navigator vous permettent d'afficher la fenêtre de sortie standard Java dans la fenêtre consoleJava).Alors, n'hésitez pas à utiliser out pour vérifier les variables ou les points de passage d'un programme (parexemple en appelant System.out.println ()), surtout si vous cherchez les bugs dans un programmemulti-threads, situation où il est difficile de positionner des points d'arrêts (breakpoints ).

Variables

public static InputStream in

Entrée standard pour saisir des caractères.

public static PrintStream out

Sortie standard pour écrire des messages.

public static PrintStream err

Sortie standard des erreurs pour écrire des messages d'erreurs.

Méthodes

public static void arraycopy (Object source, int srcOffset, Object dest, int dstOffset, int length) throws ArrayStoreException, IndexOutOfBoundsException

Copie les length éléments du tableau source à partir de l'indice srcOffset dans le tableau dest à l'indicedstOffset.Si les tableaux source et dest désignent le même tableau, le traitement effectué permet d'éviter quecertaines informations soient perdues (au cas où les intervalles se recouvrent).Une exception ArrayStoreException est déclenchée s'il n'est pas possible de stocker un élément desource dans dest avec un cast implicite.

public static long currentTimeMillis ()

Renvoie le temps courant en millisecondes écoulé depuis le 1er Janvier 1970.

public static void exit (int status) throws SecurityException

Quitte la Machine Virtuelle Java avec le code de sortie status.

public static void gc ()

Lance volontairement le Garbage Collector.

public static void runFinalization ()

Permet volontairement d'appeler la méthode finalize () des objets qui ne sont plus référencés.

public static SecurityManager getSecurityManager ()

Page 63: CJava

vendredi 11 février 2000 Du C/C++ à Java : Objets, tableaux et chaînes de caractères Page: 12

public static void setSecurityManager (SecurityManager s) throws SecurityException

Permet d'obtenir ou de changer le gestionnaire de sécurité. setSecurityManager () ne peut être appeléqu'une seule fois.

public static String getProperty (String property) throws SecurityExceptionpublic static String getProperty (String property, String default) throws SecurityException

Permet d'obtenir une des propriétés du système (si le gestionnaire de sécurité le permet). Si la propriétéproperty n'existe pas, default est renvoyée.Voici la liste des différentes propriétés définies dans Java 1.0 :java.version, java.vendor, java.vendor.url, java.home, java.class.version, java.class.pathos.name, os.arch, os.versionfile.separator, path.separator, line.separatoruser.name, user.home, user.dir

Les valeurs par défaut des propriétés du système peuvent être modifiées directement au lancement de laMachine Virtuelle en utilisant une ou plusieurs options -Dpropriete=valeur avec la commande java .

public static Properties getProperties () throws SecurityExceptionpublic static void setProperties (Properties props) throws SecurityException

Permet d'obtenir ou de modifier toutes les propriétés du système.

public static void load (String filename) throws SecurityException, UnsatisfiedLinkErrorpublic static void loadLibrary (String libname) throws SecurityException, UnsatisfiedLinkError

Permet de charger un fichier de code ou une librairie (qui implémentent par exemple des méthodesnative d'une classe).

A partir de Java 1.1, cette classe déclare notamment les méthodes setIn (), setOut () et setErr () quipermettent de rediriger l'entrée et les sorties standards.

L'application suivante vous permet d'avoir un aperçu des propriétés courantes de votre MachineVirtuelle. Recopiez la dans un fichier SystemProperties.java , que vous compilez avec l'instruction javacSystemProperties.java pour ensuite l'exécuter avec java ou Java Runner , grâce à l'instruction javaSystemProperties :

public class SystemProperties{ public static void main (String [ ] args) { System.getProperties ().list (System.out); } }

Page 64: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 1

Les instructions et les opérateurs

Les blocsif ... else, switch

while, do ... while, forLes expressionsLes opérateurs

Les conversions (casts)Priorité des opérateurs

Les blocs

Vous allez pouvoir parcourir très rapidement ce chapitre si vous connaissez déjà le C ou le C++ : C'estsurtout à ce niveau que Java et le C se ressemblent le plus car leur jeu d'instructions et d'opérateurs sonttrès proches.

Un bloc est une ensemble dans un ordre quelconque de déclarations de variables locales, d'instructions(if, switch, while, do, for, try, throw, synchronized ou return), d'affectations, d'appels de méthode oude créations d'objets.A partir de Java 1.1, un bloc peut aussi déclarer n'importe où des classes internes :

{ TypeVariable variableLocale1; TypeVariable variableLocale2 = valeurOuExpression ; TypeVariable variableLocale3 [ ]; TypeVariable variableLocale4, variableLocale5; // Instructions if, switch, do, while, for, try, throw, synchronized ou return // ou affectations, appels de méthode ou création d'objets suivis de points virgules ; // A partir de Java 1.1 : déclaration de classes internes}

Une instruction peut être éventuellement vide (ne rien faire) : dans ce cas, elle se note ; . Ce typed'instruction est quelques fois utilisé comme corps des instructions de boucles.TypeVariable est soit un type de base, soit le nom d'une classe.A partir de Java 1.1, une variable locale ou un paramètre peut être déclaré final, pour garantir que lavaleur qu'ils contiennent ne sera pas modifiée.Une variable locale ne peut être déclarée deux fois avec le même nom à l'intérieur d'un même bloc, niporter le même nom qu'un des paramètres d'une méthode. De plus, dans le cas d'un bloc imbriqué dansun autre, une variable locale ne peut porter le même nom qu'une autre variable déclarée dans le blocexterne.Une variable locale (ou un paramètre d'une méthode) variable1 déclarée dans un bloc d'une classeClasse1 peut porter le même nom que celui d'une variable de Classe1. Dans ce cas, la variablevariable1 de Classe1 est cachée par la variable locale variable1. Si vous voulez faire référence à lavariable de la classe dans le bloc, vous pouvez utiliser l'expression Classe1.variable1, si variable1 estune variable de classe (static), ou l'expression this.variable1 si variable1 est une variable d'instance.L'utilisation de this est développée plus loin dans ce chapitre.Toute variable (locale ou non) variable1 déclarée dans une classe Classe1 peut porter le même nomqu'une méthode de Classe1 ou le même nom qu'une classe.Une fois que le contrôle quitte un bloc, toutes les variables locales qui y ont été déclarées n'existentplus. Par conséquent, dans un bloc, la portée d'une variable locale est limitée entre le point où elle estdéclarée et la fin de ce bloc.De façon similaire, les classes internes ont la même portée que des variables locales.

Page 65: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 2

Les variables locales en Java, sont toutes "automatiques" : Elles sont détruites une fois sorties du blocdans lequel elles sont déclarées. Les mots clé du C auto et register n'existent pas, et static ne peutpas être utilisé pour les variables locales.

Les variables locales du C/C++ allouées sur la pile d'exécution de type struct, union ou class doiventêtre remplacées par des références qui désignent des objets créés dynamiquement avec l'opérateur new.Leur destruction se fera automatiquement non à la sortie du bloc, mais grâce à l'intervention du GarbageCollector.

Les variables locales peuvent être déclarées à n'importe où à l'intérieur d'un bloc, comme en C++. Siune variable locale est utilisée avant d'être initialisée, ceci provoque une erreur de compilation et passeulement un warning comme en C/C++.

Contrairement au C, une variable locale déclarée dans un bloc d'une méthode methode1 () ne peutporter le même nom qu'un des paramètres de methode1 () ou qu'une des variables locales déclarées àl'extérieur de ce bloc. Les variables locales ne peuvent cacher qu'une variable de classe ou d'instance.C'est à dire l'exemple suivant provoquera des erreurs à la compilation :

class Classe1{ int var; void methode1 (int var) // Pas d'erreur { //... { int var; // Erreur : var existe déjà comme paramètre //... } } void methode2 () { int var; // Pas d'erreur //... { int var; // Erreur : var existe déjà comme variable locale int var2; //... } // Après l'accolade fermante var2 n'existe plus. //... { int var2; // Pas d'erreur : var2 n'est pas déclarée // dans le bloc externe //... } }}

if ... else, switch

Les instructions if et switch ont la même syntaxe qu'en C/C++, c'est-à-dire :

if (expressionBooleenne ) instructionOuBlocSiVrai if (expressionBooleenne ) instructionOuBlocSiVraielse instructionOuBlocSiFaux switch (expressionEntiere ){ case expressionConstante1 : instructionOuBlocCas1 break; // ou return; ou rien pour passer au case suivant case expressionConstante2 : instructionOuBlocCas2 break; // ou return; ou rien pour passer au case suivant // ... default : instructionOuBlocParDefaut break; // ou return;

Page 66: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 3

}

Si les expressions expressionConstantei qui suivent chaque case ne sont pas constantes, vous devezutiliser l'instruction if.

instructionOuBloc... peut éventuellement contenir les instructions return; ou return valeur; poursortir de la méthode courante (valeur doit être du type de retour de la méthode).

Il existe une petite différence entre le C et Java pour l'instruction if (expression) : expression doitêtre obligatoirement du type boolean ; Donc, une condition comme if (x = y - 1) ... ne générerapas un warning (avec certains compilateurs C) mais une erreur de compilation en Java.Cette obligation alourdit peut être l'écriture mais en améliore la lisibilité.

while, do ... while, for

Les instructions de boucles ont la même syntaxe qu'en C/C++, c'est-à-dire :

while (expressionBooleenne ) instructionOuBloc

Tant que l'expression expressionBooleenne est true, l'instruction ou le bloc d'instructioninstructionOuBloc est exécuté.

do instructionOuBlocwhile (expressionBooleenne );

Comme pour l'instruction while, mais l'instruction ou le bloc d'instruction instructionOuBloc estexécuté au moins une fois, puisque expressionBooleenne est vérifiée après la première exécution deinstructionOuBloc .

for (expressionInit ; expressionBooleenne ; expressionIncrementation ) instructionOuBloc for (TypeVariable variableLocale = valeurOuExpression ; expressionBooleenne ; expressionIncrementation ) instructionOuBloc

expressionInit est exécuté puis tant que expressionBooleenne est true, l'instruction ou le blocd'instruction instructionOuBloc puis expressionIncrementation sont exécutés.

instructionOuBloc peut éventuellement contenir les instructions suivantes :

break; pour sortir de la boucle courante. continue; pour retourner au while ( ) ou au for ( ) courant sans terminer instructionOuBloc . return; ou return valeur; pour sortir de la méthode courante (valeur doit être du type de retourde la méthode).

L'équivalent de l'instruction for avec while est comme suit :

{ expressionInit ; while (expressionBooleenne ) { instructionOuBloc ; expressionIncrementation ; }}

Cette équivalence est vraie sauf si instructionOuBloc contient l'instruction continue, En effet, aprèsl'exécution d'un continue dans instructionOuBloc , l'instruction suivante à être exécutée est l'expressionexpressionIncrementation de l'instruction for, tandis que pour l'instruction while c'est l'expression

Page 67: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 4

expressionBooleenne .

La première instruction du for expressionInit , peut comporter plusieurs initialisation de variables,séparées par des virgules (,) ; la troisième instruction expressionIncrementation peut elle aussi, être unensemble d'instructions séparées par des virgules (,), comme dans l'exemple suivant manipulant deuxindices dans un même for :

class Classe1{ int [ ] factorielles (int max) { // Création d'un tableau de max éléments int [ ] tableau = new int [max]; // Initialisation du tableau avec les max premières factorielles for (int i = 0, fact = 1; i < max; i++, fact = fact * i) tableau [i] = fact; return tableau; }}

Comme pour if, l'expression déterminant la poursuite d'une boucle while ou for doit être du typeboolean.

for permet de déclarer une ou plusieurs variables locales, qui servent généralement d'incrémentscomme dans l'exemple : for (int i = 0; i < 5; i++) table [i] = 0;

Les expressions

Une expression peut prendre une des formes suivantes :

Une valeur littérale d'un des types de base. Un accès à une variable locale au bloc ou à un paramètre d'une méthode, de la forme variable1. Un accès à une variable, de la forme variable1 ou expression .variable1. expression est soitune classe ou une interface si variable1 est une variable de classe (static), soit une référence surun objet de Classe1 si variable1 est une variable d'instance de la classe Classe1 ou d'une dessuper classes de Classe1. Une expression pour accéder à un élément d'un tableau, de la forme tab [expression2 ] ouexpression .tab [expression2 ], où expression2 doit être une expression convertible en int. tabpeut être une variable locale, une variable de classe, ou une variable d'instance. this, super ou null. Une expression de création de tableau, utilisant l'opérateur new, de la forme new typeOuClasse[expression ]. Une conversion avec l'opérateur de cast, de la forme (typeOuClasse)expression . Une expression booléenne utilisant l'opérateur instanceof, de la forme objet instanceofClasse1. Une expression utilisant un opérateur arithmétique unaire (opunaire expression ) ou binaire (expression1 opbinaire expression2 ).

Les expression suivantes peuvent être utilisées comme expression ou comme instruction, si elles sontsuivies d'un point virgule (;) :

Une expression utilisant un des opérateurs arithmétiques unaires ++ ou --, de la forme++variable1, --variable1, variable1++ ou variable1--. Un appel à une méthode, de la forme methode (arg1, arg2, ...) ou expression .methode (arg1,

arg2, ...). expression est soit une classe ou une interface si methode () est une méthode declasse (static), soit une référence sur un objet de Classe1 si methode () est une méthoded'instance de Classe1 ou d'une des super classes de Classe1. Chacun des arguments peut être biensûr une expression.Si methode () est surchargée, la méthode appelée sera celle dont la déclaration correspond au typedes arguments.Si methode () est outrepassée, la méthode appelée par l'expression objet.methode () sera la

Page 68: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 5

méthode methode () de la classe d'appartenance de objet. Une expression de création d'objet, utilisant l'opérateur new, de la forme new Classe(argConstructeur ).Si Classe a plusieurs constructeurs qui sont surchargées, le constructeur appelé sera celui dont ladéclaration correspond au type des arguments. Une affectation avec l'opérateur = ou les opérateurs d'affectation composés op = (ou op peut êtreun des opérateurs suivants : *, /, %, +, -, <<, >>, >>>, &, ^ ou |). Dans ce cas, l'expression x op = y

est équivalente à x = x op y.

Contrairement au C/C++, lors de l'appel d'une méthode en Java, les arguments sont obligatoirementévalués l'un après l'autre de gauche à droite avant d'être passés à la méthode. Ceci permet d'éviter deseffets de bords imprévisibles. Par exemple, l'expression methode (i = 1, i++, ++i) sera évaluéecomme methode (1, 1, 3).

A part les appels aux méthodes, les créations d'objet, les affectations, l'utilisation des opérateurs ++ et--, toutes les expressions Java doivent être utilisées (comme argument ou comme valeur à affecter, parexemple). Vous ne pouvez écrire val1 * val2; tout seul. Ceci permet de repérer des erreursd'écritures du type i == 0; qui ne font rien (suite à une opération Copier/Coller trop rapide).

L'opérateur virgule (,) de séparation d'instructions du C, n'existe pas en Java, excepté pouréventuellement la première et la troisième instruction d'un for, et pour séparer la déclaration deplusieurs variables de même type (comme par exemple int x, y;). Vous pouvez très bien l'éviter enrassemblant les instructions dans un bloc

Les expressions constantes utilisées après un case ou pour initialiser les constantes d'une interface, sontdes expressions ne pouvant utiliser que des opérateurs arithmétiques avec des valeurs littérales ou desvariables final initialisées avec des expressions constantes.

Utilisation de this et de super

Si dans une méthode non static methode1 () d'une classe Classe1, vous avez besoin d'une référence del'objet sur lequel methode1 () a été invoqué, vous pouvez utiliser le mot clé this. Ceci est illustré dansl'exemple suivant :

class Classe1{ boolean methode1 () { return equals (this); }} class Classe2{ void methode () { Classe1 objet1 = new Classe1 (); objet1.methode1 (); }}

La méthode equals () de la classe Object requiert comme paramètre une référence sur un objet. Ici,l'argument this lui est passé, qui en fait désigne objet1 (au passage le résultat est forcément true). thisne peut être utilisé que dans des méthodes non static (une méthode static n'est pas invoquée sur unobjet).

Page 69: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 6

Pour bien comprendre ce que représente this et l'appel d'une méthode sur un objet, voici un exemple deprogramme C (et non C++), avec une traduction possible en Java : /* Définition d'un type de structure */ * utilisant un int */typedef struct{ int unEntier;} Type1; void modifier (Type1 *objet1, int var){ objet1->unEntier = var;} /* Fonction créant un objet de type */ * Type1 et appelant modifier () */void uneMethode (){ Type1 *objet1 = malloc (sizeof (Type1)); modifier (objet1, 10);}

// Déclaration d'une classe// utilisant un intclass Type1{ int unEntier; void modifier (int var) { // this est facultatif this.unEntier = var; }} class Classe1{ // Méthode créant un objet de classe // Type1 et appelant modifier () void uneMethode () { Type1 objet1 = new Type1 (); objet1.modifier (10); }}

A l'appel objet1.modifier (10); plusieurs opérations sont effectuées implicitement :

1. La classe Type1 de objet1 est recherchée. 2. La méthode modifier () de Type1 est appelée avec son argument 10. 3. La "variable" this est initialisée avec objet1 dans la méthode modifier ().

this peut être utilisé seul pour désigner une référence d'un objet, instance de la classe Classe1 ou suivide l'opérateur point (.) pour accéder aux variables et méthodes d'instance d'un objet. Ceci peut être utilepour distinguer une variable et un paramètre (ou une variable locale) qui ont le même nom, comme dansl'exemple suivant :

class Classe1{ int var; int var2; Classe1 (int var) { this.var = var; var2 = var + 1; // équivalent à this.var2 = this.var + 1; }}

En fait, à chaque fois que vous utilisez une méthode ou une variable non static de la classe Classe1, àl'intérieur d'une des méthodes de Classe1, vous utilisez implicitement this, mais pour des commoditésd'écriture, il ne vous est requis de l'écrire que pour éviter toute confusion.

A partir de Java 1.1, une nouvelle utilisation de this a été introduite pour distinguer si besoin est,l'instance d'une classe interne ClasseI de l'instance de la classe Classe0 dans laquelle ClasseI estdéclarée : ClasseI.this désigne l'instance de la classe interne ClasseI et Classe0.this désignel'instance de la classe Classe0.

Pour référencer l'objet de la super classe de this, on utilise super. Dans la pratique, super est surtoututilisé pour invoquer explicitement la méthode outrepassée d'une super classe.Un exemple d'utilisation de super est donné au chapitre sur la création des classes.

Page 70: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 7

L'opérateur -> n'existe pas. Donc, comme pour toute référence en Java, this est suivi de l'opérateurpoint (.) pour accéder aux variables et méthodes d'instance d'un objet.

Contrairement au C++, this ne peut être la variable de destination d'une expression d'affectation,c'est-à-dire que par exemple, Java n'accepte pas l'expression this = unObjet.

Les opérateurs

Opérateurs arithmétiques

++, -- Opérateurs de post incrémentation et post décrémentation : variable++ ajoute 1 à variable,et renvoie la valeur de variable avant que celle-ci soit incrémentée.variable-- retire 1 à variable, et renvoie la valeur de variable avant que celle-ci soitdécrémentée.

++, -- Opérateurs de pré incrémentation et pré décrémentation : ++variable ajoute 1 à variable, etrenvoie la nouvelle valeur de variable.--variable retire 1 à variable , et renvoie la nouvelle valeur de variable.

+, - +expression n'a aucun effet sur expression , -expression renvoie la valeur opposée deexpression .

~ ~expressionEntiere renvoie le complément de expressionEntiere , bit à bit. Par exemple,~0xA7 (10100111 en binaire) est égale à 0x58 (01011000 en binaire).

! !expressionBooleenne renvoie le complément logique de expressionBooleenne , c'est-à-direfalse si expressionBooleenne est égale à true, et inversement.

*, / expression1 * expression2 renvoie la multiplication de expression1 par expression2 .expression1 / expression2 renvoie la division de expression1 par expression2 , oudéclenche une exception ArithmeticException, si expression2 est nulle et la divisions'opère sur des expressions entières.

% expression1 % expression2 renvoie le reste de la division de expression1 parexpression2 , ou déclenche une exception ArithmeticException, si expression2 est nulle etles expressions sont des entiers.

+, - expression1 + expression2 renvoie l'addition de expression1 et de expression2 .Si l'un des opérandes expression1 ou expression2 est de la classe String, l'autre opérandeest converti en String et le résultat est la concaténation des deux chaînes.expression1 - expression2 renvoie la valeur de expression1 + (-expression2 ).

<<, >>, >>> expressionEntiere << nbreDecalage renvoie la valeur de expressionEntiere dont les bitssont décalés à gauche, nbreDecalage fois.expressionEntiere >> nbreDecalage renvoie la valeur de expressionEntiere dont les bitssont décalés à droite, nbreDecalage fois, avec extension du bit de signe.expressionEntiere >>> nbreDecalage renvoie la valeur de expressionEntiere dont lesbits sont décalés à droite, nbreDecalage fois, avec introduction de zéro à gauche.

<, >, <=, >= expression1 < expression2 renvoie true si expression1 est strictement inférieure àexpression2 .expression1 > expression2 renvoie true si expression1 est strictement supérieure àexpression2 .expression1 <= expression2 renvoie true si expression1 est inférieure ou égale àexpression2 .expression1 >= expression2 renvoie true si expression1 est supérieure ou égale àexpression2 .

==, != expression1 == expression2 renvoie true si expression1 est égale à expression2 . Siexpression1 et expression2 sont des références sur des objets, le résultat est true si les 2références désignent le même objet, ou si elles sont égales à null.expression1 != expression2 renvoie true si expression1 est différente de expression2 .expression1 != expression2 est équivalent à !(expression1 == expression2 ).

Page 71: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 8

&, ^, | expressionEntiere1 & expressionEntiere2 renvoie le résultat d'un ET bit à bit entre lesopérandes.expressionEntiere1 ^ expressionEntiere2 renvoie le résultat d'un OU exclusif bit à bitentre les opérandes.expressionEntiere1 | expressionEntiere2 renvoie le résultat d'un OU bit à bit entre lesopérandes.Les opérandes peuvent être éventuellement de type boolean.

&&, || expressionBooleenne1 && expressionBooleenne2 renvoie le résultat d'un ET logique entreles opérandes. Si expressionBooleenne1 est false alors expressionBooleenne2 n'est pasévaluée, et false est tout de suite renvoyé.expressionBooleenne1 || expressionBooleenne2 renvoie le résultat d'un OU logique entreles opérandes. Si expressionBooleenne1 est true alors expressionBooleenne2 n'est pasévaluée, et true est tout de suite renvoyé.

? : expressionBooleenne1 ? expression1 : expression2 renvoie la valeur de expression1 siexpressionBooleenne1 est true, sinon la valeur de expression2 .x = expressionBooleenne1 ? expression1 : expression2 ; est équivalent à :

if (expressionBooleenne1 ) x = expression1 ;else x = expression2 ;

Java a deux opérateurs de décalages à droite >> et >>>. >> recopie à gauche le bit de signe tandis que>>> introduit des zéros à gauche.

L'opérateur instanceof

L'opérateur instanceof permet de vérifier si une référence désigne un objet d'une certaine classe oud'une certaine interface. Il s'utilise de la manière suivante : objet instanceof Classe1 et le résultat esttrue si objet désigne une instance de Classe1 ou des classes dérivées de Classe1 , et false sinon. Siobjet est égal à null, le résultat est toujours false.Cet opérateur est surtout utile pour évaluer la classe Classe1 d'un objet dont la référence est d'unesuper classe de Classe1, comme dans l'exemple suivant :

class Classe0{ } class Classe1 extends Classe0{ } class UneClasse{ void methode () { Classe0 objet1 = new Classe1 (); Classe0 objet2 = new Classe0 (); Object objet3 = new Classe0 (); Object objet4 = null; boolean resultat1 = objet1 instanceof Classe1; // true boolean resultat2 = objet1 instanceof Classe0; // true boolean resultat3 = objet2 instanceof Classe1; // false boolean resultat4 = objet3 instanceof Classe0; // true boolean resultat5 = objet4 instanceof Object; // false }}

Par extension, objet instanceof Object est toujours égal à true si objet est différent de null (touteclasse hérite de Object et donc tout objet est une instance d'une classe dérivée de Object).

Java introduit l'opérateur instanceof qui permet de vérifier si une référence désigne un objet qui estune instance d'une classe ou d'une interface donnée.

Page 72: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 9

Opérateurs du C/C++ absent en Java

OPERATEUR DESCRIPTION

-> Opérateur primaire d'accès aux pointeurs

:: Opérateur primaire d'accès aux classes

* & Opérateurs unaires pour les pointeurs

sizeof

delete Opérateur de destruction d'objet

Les conversions (casts)

Il existe 5 contextes dans lesquels une conversion peut avoir lieu :

Les conversions intervenant dans une affectation d'une expression, variable = expression, où letype de expression doit être converti dans le type de variable. Les conversions appliquées sur chacun des arguments d'une méthode pour que leur typecorrespondent à celui déclaré par chacun des paramètres de la méthode. Ces conversions se fontde la même manière que pour les affectations. Les conversions explicites du programmeur par un opérateur de cast. Celles-ci permettentd'effectuer n'importe quelle conversion d'un type dans un autre, si ce sont des types de base, etd'une classe dans une autre classe, si ces deux classes ont un lien d'héritage entre elles. Les conversions en chaîne de caractères permettent de convertir n'importe quel type en un objetde classe String. Les conversions nécessaires pour que dans une opération numérique comme oper1 op oper2, lesopérandes oper1 et oper2 soient convertis dans un même type pour que l'opérateur op puisse êtreappelé :

Si l'un des deux opérandes est du type double, l'autre est converti en double. Si l'un des deux opérandes est du type float, l'autre est converti en float. Si l'un des deux opérandes est du type long, l'autre est converti en long. Sinon, les deux opérandes sont convertis en int.

Conversions entre types de base avec gain de précision

Conversions de byte en short, int, long, float ou double. Conversions de short en int, long, float ou double. Conversions de char en int, long, float ou double. Conversions de int en long, float ou double. Conversions de long en float ou double. Conversions de float en double.

Toutes ces conversions ne font perdre aucune précision au nombre converti. Elles ne requièrent aucunopérateur de cast, le compilateur effectue automatiquement ces conversions, mais pour clarifier votrecode, vous pouvez utiliser un cast.

Conversions entre types de base avec perte de précision

Conversions de byte en char. Conversions de short en byte ou char. Conversions de char en byte ou short. Conversions de int en byte, short ou char. Conversions de long en byte, short, char ou int. Conversions de float en byte, short, char, int ou long. Conversions de double en byte, short, char, int, long ou float.

Ces conversions ne sont autorisées par le compilateur que si le nombre à convertir est converti

Page 73: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 10

explicitement, grâce à l'opérateur de cast qui s'utilise ainsi : nombreType1 = (type1)nombreType2.

Conversions de références d'une classe dans une autre

Toutes les conversions suivantes sont possibles sans cast explicite dans la programmation : 1. Conversion d'une référence de classe ClasseY dans une référence de classe ClasseX, si ClasseY est une

classe dérivée directement ou indirectement de ClasseX (qui peut être la classe Object). Sachant quetoute objet objetClasseY de la classe ClasseY hérite des variables et des méthodes de ClasseX,objetClasseY peut aussi être considéré comme un objet de ClasseX.

2. Conversion d'une référence de classe ClasseX dans une référence d'interface InterfaceX, si ClasseXimplémente l'interface InterfaceX.

3. Conversion d'une référence sur une interface InterfaceZ dans une référence sur une interfaceInterfaceX, si InterfaceZ est une interface dérivée de InterfaceX.

4. Conversion d'une référence sur une interface ou un tableau dans une référence sur la classe Object. 5. Conversion d'une référence sur un tableau de classe ou d'interface ClasseY (ClasseY tabY [ ]) dans une

référence sur un tableau de classe ou d'interface ClasseX (ClasseX tabX [ ]), si ClasseY peut êtreconverti en ClasseX suivant les critères précédents.

Il faut bien percevoir l'intérêt de ces conversions car c'est grâce à l'héritage, à la possibilité d'outrepasser desméthodes et grâce à ces conversions que Java (comme tout langage orienté objet) permet de mettre en pratiqueles concepts de la programmation orientée objet. Comme ce sont des casts implicites, on ne s'aperçoit pasforcément qu'on les utilise...Voici des exemples de cast implicite entre références :

interface InterfaceX{ } interface InterfaceZ extends InterfaceX{ } class ClasseX implements InterfaceX{ } class ClasseY extends ClasseX{ } class ClasseZ implements InterfaceZ{ } class UneClasse{ void uneMethode () { // Création d'un objet de chaque classe ClasseX objetClasseX = new ClasseX (); ClasseY objetClasseY = new ClasseY (); ClasseZ objetClasseZ = new ClasseZ (); // Création de tableaux d'un élément ClasseX [] tabClasseX = new ClasseX [1]; ClasseY [] tabClasseY = new ClasseY [1]; ClasseZ [] tabClasseZ = new ClasseZ [1]; InterfaceZ [] tabInterfaceZ = new InterfaceZ [1]; // Cast implicite sur les objets ClasseX objetX = objetClasseY; // 1. cast de ClasseY vers ClasseX Object objet = objetClasseY; // cast de ClasseY vers Object InterfaceX objetInterfaceX = objetClasseX; // 2. cast de ClasseX vers InterfaceX objetInterfaceX = objetClasseY; // cast de ClasseY vers InterfaceX // classeY dérive de classeX // donc classe Y implémente aussi InterfaceX InterfaceZ objetInterfaceZ = objetClasseZ; // 3. cast de ClasseZ vers InterfaceZ objetInterfaceX = objetInterfaceZ; // cast de InterfaceZ vers InterfaceX objet = objetInterfaceX; // 4. cast de InterfaceZ vers Object objet = tabClasseY; // cast d'un tableau vers Object objet = tabInterfaceZ; // cast d'un tableau vers Object

Page 74: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 11

// 5. Les mêmes cas de cast mais sur les tableaux ClasseX [] tabObjetsX = tabClasseY; Object [] tabObjets = tabClasseY; InterfaceX [] tab2InterfaceX = tabClasseX; tabInterfaceX = tabInterfaceZ; InterfaceZ [] tabInterfaceZ = tabClasseZ; tabInterfaceX = tabInterfaceZ; tabObjets = tabInterfaceX; }}

Les conversions suivantes ne sont par contre possibles que si vous utilisez explicitement un opérateur de cast,de la manière suivante : objetClasseY = (ClasseY)objetClasseX.

1. Conversion d'une référence de classe ClasseX dans une référence de classe ClasseY, si ClasseX est unesuper classe de ClasseY . Ceci implique notamment qu'une référence de classe Object peut êtreconvertie dans une référence de n'importe quelle classe.

2. Conversion d'une référence de classe ClasseX dans une référence d'interface InterfaceX, si ClasseXn'est pas final et que ClasseX n'implémente pas l'interface InterfaceX (ceci veut dire que la conversionsera acceptée à l'exécution si une classe dérivée de ClasseX implémente InterfaceX).

3. Conversion d'une référence sur la classe Object dans une référence sur une interface ou un tableau. 4. Conversion d'une référence d'interface InterfaceX dans une référence de classe ClasseX qui n'est pas

final, ou qui est final et implémente l'interface InterfaceX. 5. Conversion d'une référence d'interface InterfaceX dans une référence d'interface InterfaceZ, si

InterfaceX n'est pas une interface dérivée de InterfaceZ, et que les deux interfaces ne déclarentaucune méthode ayant les mêmes paramètres mais un type de retour différent.

6. Conversion d'une référence sur un tableau de classe ou d'interface ClasseX (ClasseX tabX [ ]) dans uneréférence sur un tableau de classe ou d'interface ClasseY (ClasseY tabY [ ]), si ClasseX peut êtreconverti en ClasseY suivant les critères précédents.

Toutes ces conversions sont acceptées par le compilateur, mais à l'exécution peuvent être refusées aprèsvérification et provoquer le déclenchement d'une exception ClassCastException, Cette exception estdéclenchée si la référence désignant un objet de classe ClasseX (celle utilisée à sa création par l'instruction newClasseX ()) n'est pas convertie dans la classe ClasseX ou dans une classe ou une interface dans laquelle uneréférence de ClasseX est convertible implicitement.Voici des exemples de cast explicite entre références (attention, les classes ne sont pas les mêmes que dansl'exemple des conversions implicites) :

interface InterfaceX{ } interface InterfaceZ extends InterfaceX{ } class ClasseX{ } class ClasseY extends ClasseX implements InterfaceX{ } class ClasseZ implements InterfaceZ{ } class UneClasse{ void uneMethode () { // Création d'un objet de chaque classe Object objet1 = new ClasseX (); // cast implicite de ClasseX vers Object ClasseX objet2 = new ClasseY (); // cast implicite de ClasseY vers ClasseX Object objet3 = new ClasseZ (); // cast implicite de ClasseZ vers Object // Création de tableaux d'un élément Object tab1 = new ClasseX [1]; // Cast explicite sur les objets

Page 75: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 12

ClasseY objetY = (ClasseY)objet2; // 1. cast de ClasseX vers ClasseY ClasseX objetX = (ClasseX)objet1; // cast de Object vers ClasseX objetY = (ClasseY)objet1; // cast de Object vers ClasseY // acceptée à la compilation mais déclenche // une exception ClassCastException à l'exécution // car objet1 ne désigne pas un objet de classe ClasseY InterfaceX objet InterfaceX = (InterfaceX)objet2; // 2. cast de ClasseX vers InterfaceX objet InterfaceX = (InterfaceX)objet1; // cast de Object vers InterfaceX // acceptée à la compilation mais déclenche // une exception ClassCastException à // l'exécution car objet1 désigne un objet // de classe ClasseX et classeX n'implémente // pas InterfaceX InterfaceZ objetInterfaceZ = (InterfaceZ)objet3; // 3. cast de Object vers InterfaceZ ClasseX [ ] tabObjetsX = (ClasseX [ ])tab1; // cast de Object vers ClasseX [ ] tabObjetsX = (ClasseX [ ])objet1; // cast de Object vers ClasseX [] acceptée // à la compilation mais déclenche une // exception ClassCastException à // l'exécution car objet1 ne désigne pas // un objet de classe ClasseX [ ] ClasseZ objetZ = (ClasseZ)objetInterfaceZ; // 4. cast de InterfaceZ vers ClasseZ objet InterfaceX = objetZ; // cast implicite de ClasseZ vers InterfaceX objetInterfaceZ = (InterfaceZ)objet InterfaceX; // 5. cast de InterfaceX vers InterfaceZ }}

La figure suivante résume les conversions les plus usuelles que vous serez amené à utiliser :

figure 8. Conversions implicites/explicites

Les casts s'opèrent sur les références et non sur les objets. Dans les deux lignes suivantes :

Classe2 objetClasse2 = new Classe2 ();Classe1 objetClasse1 = (Classe1)objetClasse2;

objetClasse1 et objetClasse2 ne sont que des références sur un objet de classe Classe2.Le fait d'effectuer le cast (Classe1) (qu'il soit explicite ou non) ne transforme en rien l'objet de classeClasse2. Ceci est très important, car si vous invoquez une méthode de Classe1, par l'expressionobjetClasse1.methode1 () et que methode1 () est outrepassée dans Classe2, ce sera effectivement laméthode methode1 () de Classe2 qui sera appelée, car objetClasse1 désigne un objet de Classe2.

Page 76: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les instructions et les opérateurs Page: 13

Les casts automatiques entre types de base sont moins nombreux en Java. Aussitôt qu'il y a perte deprécision possible (float en int, long en byte, par exemple), vous devez faire un cast explicite.

Les casts d'une référence d'un type de classe dans un autre ne sont possibles que si la classe dedestination a un lien direct d'héritage avec la classe de l'objet casté. Si la classe de conversion n'est pasla classe réelle de l'objet ou une de ses super classes, une exception ClassCastException estdéclenchée.Plus simplement, vous ne pouvez, comme en C, caster une référence sur un type dans n'importe quelautre type.

Java ne permet pas de surcharger les opérateurs de cast, mais vous pouvez éventuellement utiliser lesconstructeurs pour compenser cette absence : pour convertir un objet de classe Classe1 en Classe2,vous créer un constructeur dans la classe Classe2 prenant en paramètre une référence de classeClasse1 :

class Classe2{ public Classe2 (Classe1 objetACaster) { // Retranscrire les variables de Classe1 // en celles de Classe2 }}

Il vous suffit de créer un objet de Classe2 ainsi: Classe2 objetCaste = new Classe2(objetDeClasse1);.Attention, dans ce cas vous créez un autre objet, qui est réellement de classe Classe2, contrairement àun cast qui ne crée aucun objet mais seulement convertit une référence d'une classe dans une autre.

Priorité des opérateurs

Tableau de précédence (priorité) des opérateurs. Les opérateurs sur une même ligne ont la mêmepriorité, et sont rangés ligne par ligne du plus prioritaire au moins prioritaire.

OPERATEUR ASSOCIATIVITE DESCRIPTION

. ( ) [ ] new de gauche à droite Opérateurs primaires

! ~ ++ -- + - (cast ) de droite à gauche Opérateurs unaires

* / % de gauche à droite Multiplication, division, reste

+ - de gauche à droite Addition, soustraction

<< >> >>> de gauche à droite Décalages

< <= > >= instanceof de gauche à droite Comparaisons

== != de gauche à droite Egalité, différence

& de gauche à droite Opérateur ET bit à bit

^ de gauche à droite Opérateur OU EXCLUSIF bit à bit

| de gauche à droite Opérateur OU bit à bit

&& de gauche à droite Opérateur ET

|| de gauche à droite Opérateur OU

? : de gauche à droite Condition

= *= /= %= += -= <<= >>= >>>= &= ^= |= de droite à gauche Affectation

L'opérateur new a la même priorité que l'opérateur . , ce qui permet d'écrire directement new Classe1().methode1 (). En C++, il faut écrire (new Classe1 ())->methode1 ().

Page 77: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 1

Les exceptions

throw, try, catch,...La classe Throwable

Les exceptions RuntimeLes classes d'erreursLes autres exceptions

throw, try, catch,...

Pourquoi traiter des exceptions dès maintenant ? Parce qu'en Java, contrairement au C et au C++, lesexceptions et leur traitement font partie intégrante du langage et sont utilisées systématiquement poursignaler toute erreur survenue pendant l'exécution d'une méthode (débordement d'indice d'un tableau,erreur d'accès à un fichier,...). De nombreuses méthodes sont susceptibles de déclencher (throw ) desexceptions et donc il est impératif de savoir comment les traiter ou passer outre.Une fois acquis le principe de cette forme de traitement d'erreur, vous pourrez utiliser les classesd'exceptions Java existantes ou créer vos propres classes pour traiter les erreurs qui peuvent survenirdans vos méthodes.

La gestion d'erreur par exceptions permet d'écrire de manière plus claire (donc plus maintenable) unprogramme, en isolant le traitement d'erreur de la suite d'instructions qui est exécutée si aucune erreurne survient. Généralement, dans les langages ne disposant pas des exceptions (comme le C), lesfonctions susceptibles de poser problème renvoient des valeurs que vous devez traiter immédiatementpour vérifier si aucune erreur n'est survenue.

La gestion des erreurs se fait grâce aux exceptions en Java. Donc, il n'existe pas de variables telles queerrno... Les exceptions sont d'un abord plus difficile mais une fois compris le principe, laprogrammation des erreurs se fait plus simplement et "proprement".

Les exceptions font partie du noyau du langage Java et leur gestion est obligatoire.

Syntaxe

En Java, cinq mots-clé servent à traiter les exceptions :

L'instruction throw exception1; permet de déclencher l'exception exception1. exception1 doitêtre une référence sur un objet d'une classe d'exception ClasseException . Toutes les classesd'exception sont de la classe Throwable ou de ses dérivées (les classes Error, Exception,RuntimeException et leur dérivées). Une exception peut être déclenchée par le système oun'importe où dans une méthode. Le bloc suivant l'instruction try permet d'encadrer les séries d'instructions où une ou plusieursexceptions sont susceptibles d'être déclenchées. Les instructions de ce bloc représentent letraitement normal de votre programme. Il peut donc comporter des instructions déclenchant ounon des exceptions et éventuellement des instructions throw. Le bloc de l'instruction try doit être suivi d'une ou plusieurs instructions catch, et chacun de cescatch doit être suivi d'un bloc d'instructions. Chaque catch spécifie quelle classe d'exception il estcapable d'intercepter, quand une exception est déclenchée dans le bloc du try précédent le catch.Un catch capable de traiter la classe ClasseException ou une des classes dérivées deClasseException respecte la syntaxe suivante :

try BlocInstructionsTrycatch (ClasseException exceptionInterceptee) BlocInstructions

Page 78: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 2

Quand une exception exception1 de classe ClasseException est déclenchée dans le blocBlocInstructionsTry , le contrôle passe au premier catch suivant BlocInstructionsTry qui traitela classe d'exception ClasseException . Ce catch reçoit en paramètre l'exception déclenchée.Si aucun de ces catch n'est capable d'intercepter exception1, le contrôle est rendu au premiercatch capable d'intercepter une exception de classe ClasseException , parmi les méthodesmémorisées dans la pile d'exécution et exécutant un try ... catch. Si aucun catch n'est rencontré,la Machine Virtuelle Java indique l'exception qui est survenue et arrête le thread dans laquelle elleest survenue (ce qui généralement bloque le programme).Le bloc instructions d'un catch peut éventuellement redéclencher l'exception interceptéeexceptionInterceptee pour la propager dans la pile d'exécution, grâce à l'instruction throwexceptionInterceptee;. Le bloc d'instructions du dernier catch peut être optionnellement suivi de l'instruction finally,suivi lui aussi d'un bloc d'instructions spécifiant les instructions à exécuter à la suite du bloc try siaucune exception n'a été déclenchée ou à la suite du traitement d'un catch. Dans la déclaration d'une méthode methode1 (), le mot-clé throws permet de déclarer la liste desclasses d'exceptions que methode1 () est susceptible de déclencher. methode1 () peut déclencherdes exceptions dans les deux situations suivantes :

Elle appelle une ou plusieurs instructions throw exception1; et n'intercepte pas toutes cesexceptions avec l'instruction catch. Elle appelle d'autres méthodes susceptibles de déclencher des exceptions et n'intercepte pastoutes ces exceptions.

Seules les classes d'exceptions RuntimeException, Error et toutes leurs classes dérivées, ne sontpas obligées d'être citées après throws.Ce type de déclaration permet d'être sûr qu'une exception déclenchée par une méthode seratoujours traitée ou ignorée sciemment par le programmeur.

Chacune des instructions try, catch et finally doivent être suivi d'un bloc { ... } même si ce bloc necomporte qu'une seule d'instruction (Désolé, les afficionados du code compact en seront pour leursfrais !).

Voici un exemple de traitement local d'une exception déclenchée grâce à throw dans un bloc try etinterceptée par un des catch qui suivent :

class Classe0{ // ... void methode1 () { try { // ... throw new Exception (); } catch (Exception exception1) { // Que faire en cas d'exception ? } }}

Une méthode qui est susceptible de déclencher une exception peut s'écrire ainsi :

class Classe1{ // ... void methode1 () throws ClasseException { // ... // En cas d'erreur, déclenchement d'une exception throw new ClasseException (); // ... }

Page 79: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 3

}

ClasseException est soit une classe prédéfinie dérivée de la classe Throwable, soit une classe dérivéed'une de ces classes créé par vous.

Quand vous appelez methode1 (), vous devez soit inclure l'appel à cette méthode dans un try ... catch,soit déclarer que la méthode qui appelle methode1 () est susceptible de déclencher une exception de laclasse ClasseException , comme dans l'exemple suivant :

class Classe2{ Classe1 objet1 = new Classe1 (); // ... void methodeX () { try { objet1.methode1 (); // ... } catch (ClasseException exception1) { // Que faire en cas de problème ? } // ... Eventuellement d'autres catch (...) finally { // Le bloc finally est optionnel // Que faire après que le bloc try ou // qu'un bloc catch aient été exécutés ? } } void methodeY () throws ClasseException { objet1.methode1 (); // ... }}

Le bloc finally est toujours exécuté, même si l'instruction return est exécutée dans les blocs try etcatch : il sert à regrouper les instructions qu'il faut exécuter pour laisser dans un état correct votreprogramme qu'une exception est été déclenchée ou non. Par exemple, si le bloc try traite des accès à unfichier (ouverture, lecture/écriture,...), il est logique de fermer ce fichier dans le bloc finally, pour qu'ilsoit toujours finalement fermé.Si une exception exception1 est déclenchée dans un bloc try et qu'aucun catch qui suit try n'intercepteexception1, alors le bloc finally est exécuté avant que le système ne continue à propager l'exception ettrouve (ou non) un catch traitant les exceptions de la classe de exception1.Si une exception exception2 est déclenchée dans un bloc catch, alors le bloc finally est aussi exécutéavant que le système ne continue à propager cette exception et trouve (ou non) un catch traitant lesexceptions de la classe de exception2.

Page 80: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 4

figure 9. Chemin parcouru lors du traitement d'exceptions

La figure précédente illustre les chemins différents par lesquels peut passer le contrôle dans lesméthodes methodeX () et methodeY (), suivant qu'une exception dans methode1 () est déclenchée(chemins vert et jaune) ou non (chemins rouge et bleu).

Afin de bien comprendre la gestion des erreurs avec les exceptions, voici un programme C typique traduiten Java où vous pourrez faire le parallèle entre constantes numériques façon C, et exception façon Java (àrecopier dans un fichier EssaiException.java compilé avec l'instruction javac EssaiException.java, pourensuite l'exécuter avec java ou Java Runner , grâce à l'instruction java EssaiException) :

/* Déclaration des constantes d'erreur */#define ERR_OK 0#define ERR_A_EGAL_B 1 int uneMethode (int a, int b) { if (a == b) return ERR_A_EGAL_B; else { printf ("%d et %d OK !\n", a, b); return ERR_OK; }} int main () { int erreur; if ((erreur = uneMethode (1, 2)) == ERR_OK) printf ("Pas d'erreur\n"); else if (erreur == ERR_A_EGAL_B) printf ("Erreur\n");}

// Déclaration d'une classe d'exceptionclass AEgalBException extends Exception{ public String toString () { return "A égal à B !"; }} public class EssaiException{ static void uneMethode (int a, int b) throws AEgalBException { if (a == b) throw new AEgalBException (); else System.out.println (a + " et " + b + " OK !"); } public static void main (String [ ] args) { try { uneMethode (1, 2); System.out.println ("Pas d'erreur"); } catch (AEgalBException e) { System.out.println ("Erreur " + e); } }}

Page 81: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 5

Voici un autre exemple d'application dont la méthode newObject () permet de créer un objet enconnaissant le nom de sa classe. Cette méthode simplifie le traitement des exceptions que peuventdéclencher les méthodes forName () et newInstance () de la classe Class en renvoyant une exceptionde classe IllegalArgumentException qu'il n'est pas obligatoire d'intercepter (à recopier dans un fichierInstantiationAvecNom.java compilé avec l'instruction javac InstantiationAvecNom.java pour ensuitel'exécuter avec java ou Java Runner , grâce à l'instruction java InstantiationAvecNom) :

public class InstantiationAvecNom{ // Methode transformant toutes les exceptions qui peuvent survenir // pendant l'instanciation d'une classe en une exception IllegalArgumentException. // nomClasse doit indiquer un nom de classe avec son package public static Object newObject (String nomClasse) { try { return Class.forName (nomClasse).newInstance (); } catch (ClassNotFoundException e) { throw new IllegalArgumentException ( "La classe " + nomClasse + " n'existe pas"); } catch (InstantiationException e) { throw new IllegalArgumentException ( "La classe " + nomClasse + " est abstract"); } catch (IllegalAccessException e) { throw new IllegalArgumentException ( "La classe " + nomClasse + " n'est pas public"); } catch (NoSuchMethodError e) { throw new IllegalArgumentException ( "La classe " + nomClasse + " n'a pas de constructeur par d\u00e9faut"); } } public static void main (String [ ] args) { // Essai avec différentes classes String nomsClasses [] = {"java.lang.Object", // Ok "java.lang.String", // Ok "java.lang.Integer", // Pas de constructeur par défaut "java.lang.Runnable"}; // Interface (= classe abstract) for (int i = 0; i < nomsClasses.length; i++) try { System.out.println (nomsClasses [i] + " : " + newObject (nomsClasses [i])); } catch (IllegalArgumentException e) { System.out.println (e); System.out.println ("La classe " + nomsClasses [i] + " ne peut etre instancie par Class.forName (\"" + nomsClasses [i] + "\").newInstance ();"); } }}

Autres exemples

Applets Chrono , ObservateurCalcul , EchoClient , PaperBoardClient , PlayApplet , CalculetteSimple ,BoutonsNavigation , AnimationFleche , ScrollText et Horloge .Applications LectureFichier , NumerotationLigne , ConcatenationFichiers , TestProtocole , HelloFromNet ,EchoServer et PaperBoardServer .

Page 82: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 6

Avantages des exceptions

Bien que d'un abord plus compliqué qu'une gestion d'erreur avec des constantes numériques, lesexceptions comportent de nombreux avantages que vous percevrez à l'usage :

Chaque exception est une instance d'une classe : cette classe peut comporter toute sorte deméthodes et de variables, qui permettent une gestion d'erreur bien plus riche qu'une simpleconstante numérique. De plus, vous pouvez créer une hiérarchie de classes d'exceptions, si besoinest. Une méthode methode1 () est obligée de déclarer la liste des classes d'exceptions qu'elle estsusceptible de déclencher, grâce à la clause throws. Ceci oblige les utilisateurs de methode1 () deprendre en compte ces exceptions, soit en les traitant dans un try ... catch (voir methodeX ()), soiten les ajoutant à la liste des classes d'exceptions déclenchées par leur méthode (voir methodeY ()).Cette obligation peut paraître lourde à priori, mais elle assure une gestion correcte des erreurs quipeuvent survenir dans un programme. (Qui peut affirmer qu'il a toujours géré toutes les erreursdans un programme C ?...). Le bloc d'instructions d'un try représente la suite des instructions qui sont censées se dérouler s'iln'y a pas d'erreur. Quand vous retournez des codes d'erreurs, vous devez les tester tout de suitepour traiter les cas d'erreurs éventuelles : ceci peut nuire à la lisibilité du code. Quand une exception est déclenchée, le système recherche dans la pile d'exécution la premièreméthode qui traite cette exception dans un bloc catch. Comme dans l'exemple qui suit, ceci permetéventuellement de centraliser vos traitements d'exception dans une méthode methodePrincipale() au lieu de traiter toutes les exceptions qui peuvent survenir dans chacune des méthodesmethodeI () où pourrait survenir une exception.

class UneClasse{ private void methodeQuiDeclencheUneException () throws Exception { throw new Exception (); } private void methode1 () throws Exception { methodeQuiDeclencheUneException (); } private void methode2 () throws Exception { methode1 (); methodeQuiDeclencheUneException (); } private void methode3 () throws Exception { methode1 (); } public void methodePrincipale () { try { methode2 (); methode3 (); } catch (Exception exception) { // Que faire en cas d'exception } }}

Page 83: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 7

L'équivalent de la clause catch (...) du C++ est catch (Throwable exception). En effet, toutes lesclasses d'exceptions Java héritent de la classe Throwable.

La clause throw; qui permet de redéclencher une exception traitée dans un catch, a pour équivalent enJava throw exception;, où exception est l'exception reçu en paramètre par le catch.

Java introduit le mot-clé throws qui permet de spécifier la liste des classes d'exceptions que peutdéclencher une méthode, et que doit prendre en compte tout utilisateur de cette méthode (certainscompilateurs C++ utilisent throw).

Le traitement des exceptions en Java comporte une clause supplémentaire et optionnelle par rapport auC++ : l'instruction finally. Cette instruction permet de spécifier l'ensemble des instructions àexécuter une fois terminé le bloc d'instructions d'un try ou d'un des catch, qu'une exception ait étédéclenchée ou non.

Soit methode1 () une méthode d'une classe Classe1, déclarant avec la clause throws une liste d'exceptionClasseExceptionI qu'elle est susceptible de déclencher. Si methode1 () est outrepassée dans une classeClasse2 dérivée de Classe1, alors cette méthode ne peut déclarer que les exceptions ClasseExceptionIou les exceptions dérivées de ClasseExceptionI (interdiction de déclencher des exceptions dont lesclasses ne sont pas liées à celles que peut déclencher la méthode outrepassée).Bien sûr, ceci ne s'applique que pour les classes d'exceptions différentes de RuntimeException, Error ettoutes leurs classes dérivées.Voici un exemple vous montrant ceci :

abstract class Classe1{ abstract Class chercherClasse (String nomClasse);} class Classe2 extends Classe1{ // chercherClasse () est outrepassée Class chercherClasse (String nomClasse) { try { if (nomClasse.equals ("")) throw new IllegalArgumentException ("Nom de classe vide"); return Class.forName (nomClasse); } catch (ClassNotFoundException e) { // nomClasse pas trouvée : la méthode forName () de la classe // Class nous impose d'intercepter cette exception... throw new IllegalArgumentException ("Nom de classe inconnu"); } // IllegalArgumentException est une classe dérivée de // RuntimeException donc il n'est pas obligatoire d'intercepter // les exceptions de cette classe } // Vous auriez pu décider de ne pas intercepter l'exception de // de class ClassNotFoundException et de déclarer par exemple : /* Class chercherClasse (String nomClasse) throws ClassNotFoundException { return Class.forName (nomClasse); } */ // Ceci génère une erreur car il n'est pas possible d'outrepasser // chercherClasse () et de déclarer que cette méthode est susceptible de // déclencher des exceptions que chercherClasse () de Classe1 ne déclare pas...}

Par contre, une méthode methode1 () outrepassant celle d'une super classe peut ne pas déclenchercertaines des exceptions que la méthode outrepassée a déclarées dans sa clause throws, comme parexemple :

class Classe1{ void methode1 () throws Exception {

Page 84: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 8

// ... throw new Exception (); }} class Classe2 extends Classe1{ void methode1 () { // ... }}

Ceci peut être utile quand vous voulez outrepasser la méthode clone () de la classe Object dans uneclasse Classe1 pour permettre dans certains cas, de cloner les objets de la classe Classe1 sans avoir àintercepter l'exception CloneNotSupportedException :

class Classe1 implements Cloneable{ // ... // La méthode clone () de la classe Object peut déclencher // une exception CloneNotSupportedException, mais ici // dans Classe1 clone () ne le fait pas public Object clone () { try { Classe1 clone = (Classe1)super.clone (); // ... return clone; } catch (CloneNotSupportedException e) { // Ne peut survenir car cette classe implémente Cloneable // mais obligation d'intercepter l'exception car la méthode clone () // de la classe Object déclare qu'elle peut déclencher une exception // de classe CloneNotSupportedException return null; } }} class Classe2{ void methode (Classe1 objet1) { Classe1 objet2 = (Classe1)objet1.clone (); // ... }}

La classe Throwable

Les classes d'exceptions Java se divisent en plusieurs catégories. Elles héritent toutes de la classeThrowable décrite ci-dessous. Celle-ci n'est pas habituellement utilisée directement, mais toutes lesexceptions héritent de ses méthodes, qui peuvent être intéressantes à utiliser ou à outrepasser.

Constructeurs

public Throwable ()public Throwable (String message)

Allocation d'un nouvel objet Throwable, l'un sans message et l'autre avec message décrivant l'exceptionsurvenue. Une trace de l'état de la pile est automatiquement sauvegardé.

Méthodes

public String getMessage ()

Page 85: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 9

Renvoie le message détaillé associé à l'objet.

public void printStackTrace ()public void printStackTrace (PrintStream s)

Imprime sur la sortie standard ou sur un stream, l'exception et la trace de l'exception dans la pile.

public Throwable fillInStackTrace ()

Réinitialise la trace de la pile d'exécution. Cette méthode est utile uniquement quand vous voulezredéclencher une exception traitée par un catch, de la manière throw exception.fillInStackTrace ().

public String toString ()

Méthode outrepassée de la classe Object, renvoyant une description sommaire de l'exception

Les exceptions Runtime

Les catégories des exceptions Runtime (classe RuntimeException et ses dérivées) et des classes d'erreurs(classe Error et ses dérivées) sont spéciales : contrairement aux autres exceptions, un programme n'estpas obligé de traiter les exceptions de ce type dans un try ... catch, et ceci essentiellement pour desraisons pratiques de programmation. En effet, en consultant la liste suivante vous vous rendrez compteque ces exceptions peuvent survenir très souvent dans un programme : Si Java obligeait à les traiter àchaque fois, votre programme aurait beaucoup plus de traitement d'exceptions que de code réellementutile.De même, si vous voulez vous servir d'une de ces classes pour déclencher avec throw une exceptiondans une méthode methode1 (), vous n'êtes pas obligé de la déclarer dans la clause throws de methode1().La classe RuntimeException dérive de la classe Exception. Voici la liste des exceptions dérivées deRuntimeException, qui sont susceptibles d'être déclenchées au cours de l'exécution d'un programme Java:

ArithmeticException : Une exception est survenue sur une opération arithmétique, comme une division d'unentier par zéro. ArrayStoreException : Tentative de stocker dans un tableau un élément qui n'est pas du type des éléments dutableau ou castable dans ce type. ClassCastException : Tentative de cast d'un objet dans un type incorrecte. IllegalArgumentException : Une méthode a été appelée avec un mauvais argument ou invoquée sur unmauvais objet. Les classes suivantes dérivent de cette classe d'exception :

IllegalThreadStateException : Un thread était dans un état inadéquat pour l'opération requise. NumberFormatException : Tentative de convertir dans un type numérique une chaîne de caractères malformattée.

IllegalMonitorStateException : Le thread courant a tenté d'attendre ou de prévenir d'autres threads, sur unobjet non verrouillé par ce thread (Exception déclenchée par les méthodes wait () et notify () de la classeObject, voir aussi la synchronisation des threads). IndexOutOfBoundsException : Un index (sur un tableau, une chaîne) ou un intervalle défini par deux index ontdépassé les limites inférieures ou supérieures. Les classes suivantes dérivent de cette classe d'exception :

ArrayIndexOutOfBoundsException pour les tableaux. StringIndexOutOfBoundsException pour les chaînes de caractères.

NegativeArraySizeException : Tentative de créer un tableau ou une chaîne avec une taille négative. NullPointerException : Tentative d'utiliser une référence null alors qu'une référence sur un objet valide étaitattendue. SecurityException : Tentative de violation de sécurité.

Le package java.util définit les exceptions suivantes signalant des opérations interdites : java.util.EmptyStackException : Tentative d'accéder à un élément dans une Stack vide. java.util.NoSuchElementException : Tentative d'accéder à un élément dans un ensemble d'éléments vide.

Page 86: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 10

Il n'est pas obligatoire de traiter les exceptions des classes RuntimeException, Error et leur dérivéesdans un try ... catch, et ceci qu'elles soient citées ou non dans la clause throws, des méthodesinvoquées. En fait, quand ce type d'exception est cité, ce n'est que pour information.

A la lecture de la liste précédente, vous pouvez voir que la Machine Virtuelle Java gère de manièrefine les erreurs courantes qui peuvent survenir dans un programme. Au cours de la mise au point d'unprogramme, ce type d'erreur survient souvent : par défaut, l'exception déclenchée sera interceptée parla Machine Virtuelle qui va inscrire à l'écran l'exception en question ainsi que l'état de la piled'exécution au moment de son déclenchement. Grâce à ces informations, vous retrouverezgénéralement très rapidement d'où provient l'erreur sans avoir à lancer un debugger.Globalement, vous verrez qu'à l'usage cette fonctionnalité vous permet de corriger beaucoup plus vitevos programmes et que vous vous servirez beaucoup moins souvent du debugger que dans d'autreslangages.

Les classes d'erreurs

Les classes d'erreurs dérivent de la classe Error, qui dérive elle-même de la classe Throwable. Elles sontgénéralement provoquée par la Machine Virtuelle Java à l'exécution, suite à un problème sur lechargement ou l'utilisation des classes, ou sur la Machine Virtuelle elle-même. Elles peuvent êtreintéressantes à analyser à la suite d'un plantage d'un programme. La liste de ces exceptions vous estdonnée sans plus de détail :

AWTError LinkageError

ClassCircularityError ClassFormatError IncompatibleClassChangeError

AbstractMethodError IllegalAccessError InstantiationError NoSuchFieldError NoSuchMethodError

NoClassDefFoundError UnsatisfiedLinkError VerifyError

ThreadDeath VirtualMachineError

InternalError OutOfMemoryError StackOverflowError UnknownError

Les autres exceptions

Vous devez obligatoirement prendre en compte les exceptions dont la classe dérive de Exception (saufRuntimeException et ses classes dérivées), soit en les traitant dans un try ... catch, soit, grâce à la clausethrows, en les ajoutant à la liste des classes d'exception susceptibles d'être renvoyées par une méthode.Exception dérive de la classe Throwable. Les classes d'exceptions qui suivent sont donc déclenchées parcertaines méthodes que vous trouverez dans la bibliothèque Java :

ClassNotFoundException : Une classe ou une interface d'un certain nom n'a pas été trouvée. CloneNotSupportedException : La méthode clone () de la classe Object a été appelée sur un objet dont laclasse d'appartenance n'implémente pas l'interface Cloneable. IllegalAccessException : Tentative de charger une classe dont le nom est correct, mais qui n'est pas publicet se trouve dans un package différent. InstantiationException : La classe spécifiée en paramètre de newInstance () est abstract, un tableau ou

Page 87: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les exceptions Page: 11

une interface, ceci interdisant la création d'un nouvel objet. InterruptedException : Le thread courant était en attente et un autre thread a interrompue son attente grâce laméthode interrupt () de la classe Thread.

Les packages java.io et java.net définissent les exceptions suivantes qui permettent de vérifier les erreursd'entrées-sorties. Ces classes dérivent toutes de la classe java.io.IOException (qui dérive elle-même de laclasse Exception) : java.io.EOFException : La fin de fichier a été rencontrée pendant une opération de lecture. java.io.FileNotFoundException : Fichier inexistant dans le système de fichiers. java.io.InterruptedIOException : Le thread courant était en attente de la fin d'une opération d'entrée-sortie,et un autre thread a interrompue son attente grâce la méthode interrupt () de la classe Thread. java.io.UTFDataFormatException : Erreur de conversion d'une chaîne au format UTF-8 (ou inversement).java.net.MalformedURLException : Une chaîne de caractères décrivant un URL était mal formattée ouindiquait un protocole inconnu. java.net.ProtocolException : Erreur sur le protocole réseau. java.net.SocketException : Une opération sur un socket ne s'est pas déroulé correctement. java.net.UnknownHostException : L'hôte (host) d'un réseau n'a pu être atteint. java.net.UnknownServiceException : La connection réseau ne supporte pas ce service.

Le package java.awt défini l'exception suivante : java.awt.AWTException

Pour le traitement d'erreur de vos programmes, vous pouvez déclencher vous-même des exceptions enutilisant les classes d'exceptions existantes (comme par exemple IllegalArgumentException) ou des nouvellesclasses d'exceptions.

Page 88: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 1

Les threads

Définition d'un threadLa création d'un threadLes états d'un thread

La synchronisation des threadsLa classe Thread

Définition d'un thread

L'environnement de la Machine Virtuelle Java est multi-threads. L'équivalent de thread pourrait êtretâche en français, mais pour éviter la confusion avec la notion de système multitâches, nous emploieronsle mot thread plutôt que tâche. Le fait que Java permettent de faire tourner en parallèle plusieurs threadslui donne beaucoup d'intérêt : Ceci permet par exemple de lancer le chargement d'une image sur le Web(ce qui peut prendre du temps), sans bloquer votre programme qui peut ainsi effectuer d'autresopérations.Pour vous montrer les possibilités du multi-threading voici une applet qui peut lancer trois horlogestournant en parallèle (au passage, voici une démonstration de réutilisation de la classe TimeCounter déjàutilisée au premier chapitre).

Ne confondez pas le multi-threads avec le traitement événementiel grâce à un timer, dont le résultatrendrait la même chose. Dans cette applet, il y a réellement trois threads différents qui gèrent chacunune horloge mise à jour à intervalle régulier. La mise à jour n'est pas déclenchée suite à un événementdu type WM_TIMER émis régulièrement par le gestionnaire de fenêtres.

Plusieurs aspects des threads sont à étudier pour bien comprendre leur fonctionnement et leur utilisation: la gestion par la Machine Virtuelle Java pour répartir le temps d'exécution entre les différents threads,la manière de créer un thread, les différents états possibles d'un thread, et la synchronisation entrethreads pour le partage de données.

L'environnement Java est multi-threads, et le langage permet d'utiliser cette fonctionnalité pour créervos propres threads, et synchroniser des threads qui partagent des données.

Le partage du temps entre threads

Comment faire tourner plusieurs threads en même temps alors que votre ordinateur ne possède qu'unseul microprocesseur ? La réponse vient de manière assez évidente : A tout moment, il n'y a en fait qu'unseul thread en cours d'exécution, et éventuellement d'autres threads en attente d'exécution.Si le système permet de partager le temps d'exécution entre les différents threads, il leur donne chacunleur tour un petit temps d'exécution du processeur (quelques millisecondes). Sinon, chaque fois qu'unthread a terminé d'exécuter une série d'instructions et qu'il cède le contrôle au système, le systèmeexécute un des threads en attente, et ainsi de suite... Si la série d'instructions qu'exécute chaque threadprend un temps assez court, l'utilisateur aura l'illusion que tous les threads fonctionnent ensemble.Le seul contrôle que peut avoir le programmeur sur la gestion de l'ordre dans lequel les threads enattente s'exécuteront, s'effectue en donnant une priorité à chaque thread qu'il crée. Quand le systèmedoit déterminer quel thread en attente doit être exécuté, il choisit celui avec la priorité la plus grande, ouà priorité égale, celui en tête de file d'attente.

Page 89: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 2

Sur certains systèmes, la Machine Virtuelle Java ne partage pas d'elle-même le temps du processeurentre les threads susceptibles d'être exécutés. Si vous voulez que vos programmes Java se comportentsimilairement sur tous les systèmes, vous devez céder le contrôle régulièrement dans vos threads avecles méthodes telles que sleep () ou yield (), pour permettre aux autres threads en attente, des'exécuter. Sinon, tant que l'exécution d'un thread n'est pas interrompue, les autres threads resteront enattente !

La création d'un thread

Il existe deux moyens d'écrire des threads dans un programme : Les deux moyens passent par l'écritured'une méthode run () décrivant les instructions que doit exécuter un thread. Cette méthode run () estsoit intégrée dans une classe dérivée de la classe Thread , soit intégrée dans n'importe quelle classe quidoit alors implémenter l'interface Runnable (cette interface ne décrit qu'une méthode : run ()). Laseconde méthode est très utile : elle permet d'ajouter les fonctionnalités des threads à une classeexistante, dans une classe dérivée.Par exemple, elle est utilisée par la classe TimeCounter qui dérive de la classe Counter et implémentel'interface Runnable. La classe Counter a d'abord été créée pour des besoins simples : Avoir à dispositionun compteur digital au look sympa, avec des méthodes telles que incrementCounter () oudecrementCounter (). Puis, le besoin s'est fait sentir d'avoir un compteur de temps : il a suffi donc decréer une classe TimeCounter dérivée de Counter, et d'y ajouter (entre autres) la méthode run (), quiincrémente toutes les secondes le compteur.Une autre démarche aurait pu être de créer la classe TimeCounter en la dérivant de la classe Thread, etd'y ajouter en utilisant la composition une variable de classe Counter, et une méthode run () effectuantles mêmes opérations. Mais, en conception orientée objet, cette seconde démarche semblait moinsnaturelle : En effet, un objet TimeCounter est plutôt comme tout objet Counter, un objet graphiqueauquel il a été ajouté la possibilité de s'incrémenter automatiquement toutes les secondes.

Un certain nombre de méthodes sont nécessaires pour contrôler l'exécution d'un thread. Elles sonttoutes décrites au paragraphe décrivant la classe Thread, mais en voici les principales :

La classe Thread dispose principalement de deux sortes de constructeurs : Thread () et Thread(Runnable objetRunnable).Quand vous créer un objet instance d'une classe ClasseThread dérivée de Thread, le premier estappelé implicitement par le constructeur de ClasseThread.Le second est utilisé quand vous voulez créer un objet de classe Thread dont la méthode run () àexécuter se trouve implémentée dans un classe implémentant l'interface Runnable. Au passage,vous noterez que le paramètre du second constructeur doit être une référence d'interface Runnable: En fait, vous passerez en argument une référence sur un objet d'une classe ClasseRunnableimplémentant Runnable ; ceci est un exemple de conversion d'une référence d'une classe ClasseXdans une référence d'interface InterfaceY, si ClasseX implémente l'interface InterfaceY, appliquéeavec ClasseRunnable pour ClasseX et Runnable pour InterfaceY. start () : Cette méthode permet de démarrer effectivement le thread sur lequel elle est invoquée,ce qui va provoquer l'appel de la méthode run () du thread. Cet appel est obligatoire pourdémarrer l'exécution d'un thread. En effet, la création d'un objet de classe Thread ou d'une classedérivée de Thread (par exemple, grâce à l'appel new Thread ()) ne fait que créer un objet sansappeler la méthode run (). stop () : Cette méthode permet d'arrêter un thread en cours d'exécution. Elle est utileprincipalement pour stopper des threads dont la méthode run () ne se termine jamais (comme parexemple, dans la classe TimeCounter, la méthode run () n'a pas de raison de s'arrêter d'elle-mêmepuisqu'aux dernières nouvelles, on n'a pas encore trouver le moyen d'arrêter le temps !). sleep () : Ces méthodes static permettent d'arrêter le thread courant pendant un certain laps detemps, pour permettre ainsi à d'autres threads en attente, de s'exécuter. Par exemple, une fois mis àjour une horloge par un thread, celui-ci peut arrêter son exécution pendant une minute, enattendant la prochaine mise à l'heure. yield () : Cette méthode static permet au thread courant de céder le contrôle pour permettre àd'autres threads en attente, de s'exécuter. Le thread courant devient ainsi lui-même en attente, etregagne la file d'attente. De manière générale, vos threads devraient s'arranger à effectuer desséries d'instructions pas trop longues ou à entrecouper leur exécution grâce à des appels auxméthodes sleep () ou yield ().

Page 90: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 3

Il faut éviter de programmer des séries d'instructions interminables sans appel à sleep () ou yield(), en pensant qu'il n'y aura pas d'autres threads dans votre programme. La Machine Virtuelle Javapeut avoir elle aussi des threads système en attente et votre programme s'enrichira peut-être unjour de threads supplémentaires... setPriority () : Permet de donner une priorité à un thread. Le thread de plus grande priorité seratoujours exécuté avant tous ceux en attente.

Pour illustrer l'utilisation des threads, voici un exemple d'un chronomètre affichant les 1/10 de seconde(Utiliser le bouton Arrêter pour l'arrêter et la redémarrer) :

et le programme Java correspondant (à copier dans un fichier dénommé Chrono.java et invoqué à partird'un fichier HTML) :

import java.awt.*;import java.applet.Applet; public class Chrono extends Applet implements Runnable{ private Thread chronometre; private int dixiemeseconde = 0; // Méthode appelée par le système au démarrage de l'applet public void start () { // Au début de l'applet, création et démarrage du chronomètre chronometre = new Thread (this); chronometre.start (); } public void run () { try { while (chronometre.isAlive ()) { // Dessine le compteur (appel indirect à la méthode paint ()), // puis l'augmente de 1 repaint (); dixiemeseconde++; // Arrête le thread pendant 1/10 s (100 ms) Thread.sleep (100); } } catch (InterruptedException e) { } } // Méthode appelée par le système à l'arrêt de l'applet public void stop () { // A la fin de l'applet, arrêt du chronometre chronometre.stop (); } // Méthode appelée par le système pour mettre à jour le dessin de l'applet public void paint (Graphics gc) { // Dessine le temps écoulé sous forme de hh:mm:ss:d en noir et helvetica gc.setColor (Color.black); gc.setFont (new Font ("Helvetica", Font.BOLD, size ().height)); gc.drawString (dixiemeseconde / 36000 + ":" + (dixiemeseconde / 6000) % 6 + (dixiemeseconde / 600) % 10 + ":" + (dixiemeseconde / 100) % 6 + (dixiemeseconde / 10) % 10 + ":" + dixiemeseconde % 10, 2, size ().height - 2); }}

Ce programme s'utilisant sous forme d'applet, la classe Chrono dérive de Applet, et implémentel'interface Runnable. Comme décrit au chapitre sur les applets et aux chapitres suivants, la méthode paint

Page 91: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 4

() de la classe Applet est appelée pour mettre à jour le dessin apparaissant dans la fenêtre d'une applet :Ici, elle est outrepassée pour dessiner le chronomètre.Quand l'applet est créée, une instance de la classe Chrono est allouée et la méthode start () créant lethread chronometre, est appelée. Si vous observez bien le comportement de cette applet, vous vousrendrez facilement compte que le chronomètre à une tendance à retarder... Ceci est normal : En effet, àchaque tour de boucle while (), le thread est arrêté pendant un dixième de seconde grâce à l'appelThread.sleep (100), après le redessin de l'applet avec la méthode repaint () dans run (). Mais, le faitde redessiner le chronomètre prend un faible délai qui s'additionne au 1/10 de seconde d'arrêt du threadchronometre. Une programmation plus précise devrait notamment tenir compte de ce délai pour lesoustraire de la valeur de 100 millisecondes passée à la méthode sleep (). La classe System déclare uneméthode currentTimeMillis (), donnant le temps courant, qui peut vous y aider. A vous de jouer !...

Les états d'un thread

Pendant son existence, un thread passe par plusieurs états qu'il est utile de connaître pour biencomprendre les threads et leurs possibilités. La figure suivante représente l'ensemble des états possiblesd'un thread, et les transitions existantes pour passer d'un état dans l'autre. Ne vous inquiétez pas par sacomplexité, vous aurez besoin essentiellement des méthodes décrites dans le paragraphe précédent(start (), stop (), yield () et sleep ()).

figure 10. Etats d'un thread

Quand un nouveau thread est créé, il est dans l'état nouveau thread et ne devient exécutable qu'après avoirappelé la méthode start () sur ce nouveau thread.

Parmi tous les threads dans l'état exécutable , le système donne le contrôle au thread de plus grandepriorité, ou à priorité égale, celui en tête de file d'attente, parmi les threads dans l'état exécutable . Lethread qui a le contrôle à un moment donné est le thread courant . Le thread courant en cours d'exécutioncède le contrôle à un autre thread exécutable dans l'une des circonstances suivantes :

A la fin de la méthode run (), le thread passe dans l'état mort . A l'appel de yield (), le thread passe dans l'état exécutable et rejoint la fin de la file d'attente. Sur les systèmes permettant de partager le temps d'exécution entre différents threads, le threadpasse dans l'état exécutable après qu'un certain laps de temps se soit écoulé. En attentant que des opérations d'entrée/sortie (IO) se terminent, le thread passe dans l'étatbloqué . A l'appel de sleep (), le thread passe dans l'état bloqué pendant le temps spécifié en argument,puis repasse à l'état exécutable , une fois ce délai écoulé. A l'appel d'une méthode synchronized sur un objet Objet1, si Objet1 est déjà verrouillé par unautre thread, alors le thread passe dans l'état bloqué tant que Objet1 n'est pas déverrouillé (voir lasynchronisation). A l'invocation de wait () sur un objet, le thread passe dans l'état en attente pendant le délaispécifié en argument ou tant qu'un appel à notify () ou notifyAll () n'est pas survenu (voir lasynchronisation). Ces méthodes sont déclarées dans la classe Object.A l'appel de stop (), le thread passe dans l'état mort . A l'appel de suspend (), le thread passe dans l'état bloqué , et ne redevient exécutable qu'une fois

Page 92: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 5

que la méthode resume () a été appelée.

Les deux derniers méthodes ne sont pas static et peuvent être invoquées aussi sur les threadsexécutables qui ne sont en cours d'exécution.

La synchronisation des threads

Tous les threads d'une même Machine Virtuelle partage le même espace mémoire, et peuvent donc avoiraccès à n'importe quelles méthode ou variable d'objets existants. Ceci est très pratique, mais dans certainscas, vous pouvez avoir besoin d'éviter que deux threads n'aient accès n'importe quand à certainesdonnées. Si par exemple, un thread threadCalcul a pour charge de modifier une variable var1 qu'unautre thread threadAffichage a besoin de lire pour l'afficher, il semble logique que tant quethreadCalcul n'a pas terminé la mise à jour ou le calcul de var1, threadAffichage soit interdit d'y avoiraccès. Vous aurez donc besoin de synchroniser vos threads.

Utilisation de synchronized

La synchronisation des threads se fait grâce au mot clé synchronized, employé principalement commemodifieur d'une méthode. Soient une ou plusieurs méthodes methodeI () déclarées synchronized, dansune classe Classe1 et un objet objet1 de classe Classe1 : Comme tout objet Java comporte un verrou(lock en anglais) permettant d'empêcher que deux threads différents n'aient un accès simultané à unmême objet, quand l'une des méthodes methodeI () synchronized est invoquée sur objet1, deux cas seprésentent :

Soit objet1 n'est pas verrouillé : le système pose un verrou sur cet objet puis la méthode methodeI() est exécutée normalement. Quand methodeI () est terminée, le système retire le verrou surObjet1.La méthode methodeI () peut être récursive ou appeler d'autres méthodes synchronized deClasse1 ; à chaque appel d'une méthode synchronized de Classe1, le système rajoute un verrousur Objet1, retiré en quittant la méthode. Quand un thread a obtenu accès à un objet verrouillé, lesystème l'autorise à avoir accès à cet objet tant que l'objet a encore des verrous (réentrance desméthodes synchronized). Soit objet1 est déjà verrouillé : Si le thread courant n'est pas celui qui a verrouillé objet1, lesystème met le thread courant dans l'état bloqué , tant que objet1 est verrouillé. Une fois queobjet1 est déverrouillé, le système remet ce thread dans l'état exécutable , pour qu'il puisse essayerde verrouiller objet1 et exécuter methodeI ().

Si une méthode synchronized d'une classe Classe1 est aussi static, alors à l'appel de cette méthode, lemême mécanisme s'exécute mais cette fois-ci en utilisant le verrou associé à la classe Classe1.Si Classe1 a d'autres méthodes qui ne sont pas synchronized, celles-ci peuvent toujours être appeléesn'importe quand, que objet1 soit verrouillé ou non.

Voici un exemple illustrant l'utilisation de méthodes synchronized, avec une applet affichant les résultatsd'un calcul de courbes, quand ceux-ci sont valables. Comme cette applet fait des calculs continuels dansdes boucles sans fin, elle n'est pas incluse dans cette page pour éviter de bloquer votre navigateur, maisessayez-là sur votre machine pour découvrir tout l'intérêt de la synchronisation des threads.

Voici le programme Java (à copier dans un fichier dénommé AfficheurDeCalcul.java et invoqué à partird'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class AfficheurDeCalcul extends Applet{ private Thread calculateur; private Thread afficheur;

Page 93: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 6

// Méthode appelée par le système au démarrage de l'applet public void start () { setBackground (Color.white); // Démarrage de deux threads l'un pour calculer une courbe, // l'autre pour l'affichage calculateur = new Calculateur (this); afficheur = new Afficheur (this); calculateur.start (); afficheur.start (); } // Méthode appelée par le système à l'arrêt de l'applet public void stop () { // Arrêt des deux threads afficheur.stop (); calculateur.stop (); } private int [ ] courbe; // calculerCourbe () et paint () sont // synchronized ce qui les empêche de fonctionner simultanément synchronized public void calculerCourbe () { // Création d'un tableau de la largeur de l'applet courbe = new int [size ().width]; // Calcul des points d'une sinusoïde avec fréquence aléatoire double pasCalcul = 2 * Math.PI / courbe.length / Math.random (); for (int i = 0; i < courbe.length; i++) courbe [i] = (int)( (Math.sin (i * pasCalcul) + 1) * size ().height / 2); } synchronized public void dessinerCourbe () { update (getGraphics ()); // update () efface le fond puis appelle paint () } // Méthode appelée par le système pour mettre à jour le dessin de l'applet synchronized public void paint (Graphics gc) { if (courbe != null) { // Dessin de la courbe en noir en reliant les points un à un gc.setColor (Color.black); for (int i = 1; i < courbe.length; i++) gc.drawLine (i - 1, courbe [i - 1], i, courbe [i]); } }} class Calculateur extends Thread{ private AfficheurDeCalcul applet; public Calculateur (AfficheurDeCalcul applet) { this.applet = applet; } public void run () { while (isAlive ()) applet.calculerCourbe (); // Lance les calculs indéfiniment }} class Afficheur extends Thread{ private AfficheurDeCalcul applet; public Afficheur (AfficheurDeCalcul applet) { this.applet = applet; }

Page 94: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 7

public void run () { while (isAlive ()) applet.dessinerCourbe (); // Lance les affichages indéfiniment }}

Dans cette exemple, les méthodes calculerCourbe () et dessinerCourbe () de la classeAfficheurDeCalcul sont synchronized. Quand calculerCourbe () préparent les résultats dans le tableaucourbe de l'applet, il ne faut pas qu'un autre thread puisse dessiner la courbe de cette applet en appelantdessinerCourbe (), et inversement !L'objet représentant l'applet est verrouillé à l'appel de ces méthodes, pour bloquer tout autre threadtentant d'invoquer calculerCourbe () ou dessinerCourbe () sur cet objet. Les deux threadscalculateur et afficheur s'interdisent ainsi mutuellement d'exécuter simultanément calculerCourbe ()ou dessinerCourbe () sur l'objet calculateur. Si, en recopiant l'exemple, vous essayez de supprimerl'un ou les deux synchronized, vous verrez tout à coup que les courbes affichées ne sont plus trèsrégulières, preuve que la courbe est modifiée pendant son affichage !...A l'usage, vous vous rendrez compte que les boucles sans fin (ou presque !) des méthodes run ()fonctionnent généralement correctement mais ont une forte tendance à plomber les performances dusystème, car elles tournent continuellement sans s'arrêter... Le programme se présente ainsi par soucis desimplification et pour que vous puissiez vous rendre compte que deux threads qui s'ignorent (ils nes'appellent jamais l'un l'autre) peuvent se synchroniser pour accéder à un même objet pour obtenir unrésultat correct.

Le système ne crée pas de file d'attente pour les threads bloqués : Quand un objet est déverrouillé,n'importe quel thread bloqué sur cet objet est susceptible d'être débloqué pour avoir accès à une de sesméthodes synchronized. Dans l'exemple précédent, rien n'empêche en effet les méthodescalculerCourbe () ou dessinerCourbe () de s'exécuter plusieurs fois de suite, avant que l'autreméthode ne verrouille l'objet représentant l'applet et puisse s'exécuter. Pour vous le prouver, il voussuffit d'ajouter des appels à System.out.println (...) dans ces deux méthodes...

Il existe une autre syntaxe d'utilisation de synchronized :

class Classe1{ // ... void methode1 () { // ... synchronized (objet1) { // objet1 est verrouillé // jusqu'à la fin du bloc } }}

Un thread peut accéder à un bloc synchronized, si objet1 n'est pas verrouillé par un autre thread. Sic'est le cas, comme pour une méthode synchronized, le thread est bloqué tant que objet1 n'est pasdéverrouillé.

La Machine Virtuelle Java n'a pas de moyen de repérer les deadlocks (impasses) : Ceux-ci peuventsurvenir quand par exemple, deux threads thread1 et thread2 restent dans l'état bloqué parce quethread1 attend qu'un objet objetX soit déverrouillé par thread2, alors que thread2 attend qu'un objetYsoit déverrouillé par thread1. C'est à vous de faire attention dans votre programmation pour qu'undeadlock ne survienne pas.

Synchronisation avec wait () et notify ()

Comme il est expliqué dans l'exemple précédent, synchronized permet d'éviter que plusieurs threadsaient accès en même temps à même objet, mais ne garantit pas l'ordre dans lequel les threads cesméthodes seront exécutées. Pour cela, il existe plusieurs méthodes de la classe Object qui permettent demettre en attente volontairement un thread sur un objet (avec les méthodes wait ()), et de prévenir des

Page 95: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 8

threads en attente sur un objet que celui-ci est à jour (avec les méthodes notify () ou notifyAll ()).Ces méthodes ne peuvent être invoquées que sur un objet verrouillé par le thread courant , c'est-à-direque le thread courant est en train d'exécuter une méthode ou un bloc synchronized, qui a verrouillé cetobjet. Si ce n'est pas le cas, une exception IllegalMonitorStateException est déclenchée.

Quand wait () est invoquée sur un objet objet1 (objet1 peut être this), le thread courant perd lecontrôle, est mis en attente et l'ensemble des verrous d'objet1 est retiré. Comme chaque objet Javamémorise l'ensemble des threads mis en attente sur lui, le thread courant est ajouté à la liste des threadsen attente de objet1. objet1 étant déverrouillé, un des threads bloqués parmi ceux qui désiraientverrouiller objet1, peut passer dans l'état exécutable et exécuter une méthode ou un bloc synchronizedsur objet1.

Un thread thread1 mis en attente est retiré de la liste d'attente de objet1, quand une des trois raisonssuivantes survient :

thread1 a été mis en attente en donnant en argument à wait () un délai qui a fini de s'écouler. Le thread courant a invoqué notify () sur objet1, et thread1 a été choisi parmi tous les threads enattente . Le thread courant a invoqué notifyAll () sur objet1.

thread1 est mis alors dans l'état exécutable , et essaye de verrouiller objet1, pour continuer sonexécution. Quand il devient le thread courant , l'ensemble des verrous qui avait été enlevé d'objet1 àl'appel de wait (), est remis sur objet1, pour que thread1 et objet1 se retrouvent dans le même étatqu'avant l'invocation de wait ().

Un thread mis en attente en utilisant la méthode wait () sans argument sur un objet, ne peut redevenirexécutable qu'une fois qu'un autre thread a invoqué notify () ou notifyAll () sur ce même objet.Donc, wait () doit toujours être utilisé avec notify (), et être invoqué avant cette dernière méthode.

Par exemple, si dans l'exemple précédent, vous ajoutez à la fin de la méthode calculerCourbe (), vousajoutez notifyAll () et au début de dessinerCourbe (), vous ajoutez wait (), vous obtiendrez ceci :

public class AfficheurDeCalcul extends Applet{ // ... synchronized public void calculerCourbe () { courbe = new int [size ().width]; double pasCalcul = 2 * Math.PI / courbe.length / Math.random (); for (int i = 0; i < courbe.length; i++) courbe [i] = (int)( (Math.sin (i * pasCalcul) + 1) * size ().height / 2); // Prévenir les autres threads du calcul d'une nouvelle courbe notifyAll (); } synchronized public void dessinerCourbe () { try { // Attendre qu'une nouvelle courbe soit calculée wait (); update (getGraphics ()); } catch (InterruptedException e) { } } // ...}

A l'appel de wait () (ici sur l'objet this), le thread afficheur qui appelle la méthode dessinerCourbe ()est mis en attente jusqu'à ce que ce que calculerCourbe () appelle notifyAll () pour prévenir lesthreads en attente qu'une nouvelle courbe est maintenant disponible. Ceci évite que dessinerCourbe ()soit éventuellement exécutée plusieurs fois de suite alors qu'aucune nouvelle courbe n'a été calculée.

Page 96: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 9

Il vaut mieux utiliser notifyAll () que notify (), car il est possible d'enrichir ce programme en créantpar exemple des threads qui devront appeler dessinerCourbe () pour mettre à jour des fenêtressupplémentaires, ou en créant un autre thread appelant une méthode synchronized qui enregistre lacourbe dans un fichier. Si la méthode notify () était appelée, un seul thread serait prévenu et mis à jouren ignorant les autres.

Cette modification du programme n'empêche toujours pas la méthode calculerCourbe () de s'exécuterplusieurs fois de suite, car le thread calculateur qui appelle cette méthode, prévient en invoquantnotifyAll () les threads en attente qu'une nouvelle courbe a été calculée, mais n'est jamais mis enattente pour laisser les autres threads utiliser ces nouveaux résultats. Une dernière modification desméthodes calculerCourbe () et dessinerCourbe () permet au thread afficheur appelantdessinerCourbe () de prévenir le thread calculateur en attente qu'il a terminé de dessiner la nouvellecourbe :

public class AfficheurDeCalcul extends Applet{ // ... synchronized public void calculerCourbe () { try { // Attendre que les autres threads aient utilisé une courbe if (courbe != null) wait (); } catch (InterruptedException e) { } courbe = new int [size ().width]; double pasCalcul = 2 * Math.PI / courbe.length / Math.random (); for (int i = 0; i < courbe.length; i++) courbe [i] = (int)( (Math.sin (i * pasCalcul) + 1) * size ().height / 2); notifyAll (); } synchronized public void dessinerCourbe () { try { // Attendre qu'une courbe soit créée if (courbe == null) wait (); update (getGraphics ()); // Prévenir que la courbe a été utilisée courbe = null; notify (); } catch (InterruptedException e) { } } // ...}

Ici, en affectant la variable courbe à null ou avec un nouveau tableau, un thread peut savoir si l'autre àterminer son traitement ou non. Si ce traitement n'est pas terminé, le thread se met en attente . Ilredeviendra exécutable quand l'autre thread le préviendra qu'il a fini en appelant notify ().Vous noterez que dessinerCourbe () mettant à null la variable courbe avant d'appeler notify (), ilfaudrait utiliser une autre logique de programmation pour que cette courbe reste disponible pour d'autresthreads qui seraient créés.

Cet exemple, utilisant deux boucles (sans fin) pour le calcul et l'affichage des courbes, entraîne uneprogrammation d'un abord assez complexe. Mais, ceci n'est utilisé que pour des moyens dedémonstration : Généralement, dans ce type de programme, un calcul est effectué ponctuellement surcommande et pas en boucle, et l'affichage attend la fin du calcul pour démarrer. Donc, la programmationavec uniquement synchronized comme dans la première version de cet exemple, suffira dans la plupartdes cas pour synchroniser l'accès aux données.

Page 97: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 10

La programmation de la synchronisation des threads est une tâche ardue, sur laquelle vous passerezsûrement du temps... Si vous désirez l'utiliser, il faut bien s'imaginer par quels états vont passer lesthreads, quelle implication aura l'utilisation des méthodes wait () et notify () sur l'ordre d'exécutiondes instructions du programme, tout en gardant bien à l'esprit que ces méthodes ne peuvent êtreinvoquées que sur des objets verrouillés.Le piège le plus classique est de se retrouver avec un deadlock parce que les threads sont tous enattente après avoir appelé chacun d'eux la méthode wait ().

La classe Thread

Variables

public final static int MIN_PRIORITYpublic final static int NORM_PRIORITYpublic final static int MAX_PRIORITY

Ces variables (qui sont en fait des constantes), sont utilisées en argument de la méthode setPriority (),pour donner une priorité à vos threads (MIN_PRIORITY est égal à 1, NORM_PRIORITY à 5 et MAX_PRIORITY à10). NORM_PRIORITY est la priorité par défaut d'un thread.

Constructeurs

public Thread () public Thread (Runnable target)

Construit un nouveau thread à partir de la classe target implémentant l'interface Runnable. target doitimplémenter la méthode run () qui sera la méthode exécutée au démarrage du nouveau thread créé.

public Thread (ThreadGroup group, Runnable target) throws SecurityException, IllegalThreadStateException

Construit un nouveau thread à partir de la classe target avec comme groupe de thread group. La classeThreadGroup permet de regrouper un ensemble de threads, et d'exécuter (stop (), suspend (),...) desméthodes sur tous les threads d'un groupe.

public Thread (String name)public Thread (ThreadGroup group, String name) throws SecurityException, IllegalThreadStateExceptionpublic Thread (Runnable target, String name)public Thread (ThreadGroup group, Runnable target, String name) throws SecurityException, IllegalThreadStateException

Mêmes constructeurs que précédemment avec un nom name.

Méthodes

La classe Thread compte un grand nombre de méthodes, dont voici la description des plus intéressantes.Pour pouvoir manipuler le thread courant que vous ne connaissez pas forcément, certaines de cesméthodes sont des méthodes de classe :

public static Thread currentThread ()

Renvoie une référence sur le thread actuellement en cours d'exécution.

public synchronized void start () throws IllegalThreadStateException

Provoque le démarrage du thread sur lequel start () est invoqué puis l'appel à la méthode run ().Cette méthode rend la main immédiatement (le nouveau thread est lancé en parallèle au thread courant).

public void run ()

run () est la méthode où sont décrites les instructions que doit exécuter un thread. Elle est appelée une

Page 98: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 11

fois que le thread a démarré. run () doit être outrepassée dans une classe dérivée de Thread ou uneclasse implémentant l'interface Runnable.

public final synchronized void stop () throws SecurityException

Arrête le thread sur lequel stop () est invoqué.

public final void stop (Throwable exception) throws SecurityException

Arrête le thread sur lequel stop () est invoqué en déclenchant l'exception exception.

public final boolean isAlive ()

Renvoie true si un thread est vivant, c'est-à-dire que ce thread a démarré avec start () et n'a pas étéarrêté soit avec stop (), soit parce qu'il a terminé d'exécuter toutes les instructions de la méthode run().

public static void yield ()

Permet de suspendre le thread courant pour laisser la main à d'autres threads en attente d'exécution.

public static void sleep (long millis) throws InterruptedExceptionpublic static void sleep (long millis, int nanos) throws InterruptedException

Provoque l'arrêt du thread courant pendant millis millisecondes, ou pendant millis millisecondes etnanos nanosecondes. Ces méthodes sont susceptibles de déclencher une exceptionInterruptedException, qui n'est pas utilisée dans Java 1.0, mais vous oblige quand même à inclurel'appel à sleep () dans un try ... catch.

public final void suspend () throws SecurityException

Suspend l'exécution d'un thread vivant. Si plusieurs suspend () ont été invoquées sur un même thread,un seul resume () est nécessaire pour que ce thread reprenne son activité.

public final void resume () throws SecurityException

Reprend l'exécution d'un thread, après une suspension avec suspend (). Si ce thread n'a pas étésuspendu, le thread poursuit son exécution.

public void checkAccess ()

Vérifie si le thread courant peut modifier le thread sur lequel checkAccess () est invoqué. Si cela lui estinterdit, une exception SecurityException est déclenchée.

public final void setPriority (int newPriority) throws SecurityException, IllegalArgumentExceptionpublic final int getPriority ()

Modifie ou renvoie la priorité d'un thread. newPriority doit avoir une valeur comprise entreMIN_PRIORITY et MAX_PRIORITY.

public final void setName (String name) throws SecurityExceptionpublic final String getName ()

Modifie ou renvoie le nom d'un thread.

public final void setDaemon (boolean on) throws SecurityException, IllegalThreadStateExceptionpublic final boolean isDaemon ()

Permet de spécifier ou de savoir si un thread est un thread qui tourne en tâche de fond, pour rendre engénéral des services aux autres threads (daemon thread en anglais). Quand il n'a plus que des threads quitournent en tâche de fond dans le système, la Machine Virtuelle Java s'arrête.

Page 99: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les threads Page: 12

public final synchronized void join (long millis) throws InterruptedExceptionpublic final synchronized void join (long millis, int nanos) throws InterruptedExceptionpublic final void join () throws InterruptedException

Ces méthodes provoquent l'arrêt du thread courant jusqu'à la mort du thread sur lequel est invoqué join(), et pendant un délai maximum de de millis millisecondes, ou millis millisecondes et nanosnanosecondes.

public static void dumpStack ()

Imprime sur System.err l'état de la pile d'exécution du thread courant.

public final ThreadGroup getThreadGroup ()

Renvoie le groupe de threads auquel appartient un thread.

public static int activeCount ()public static int enumerate (Thread tarray [ ])

Ces méthodes renvoient le nombre de threads actifs dans le groupe auquel appartient le thread courant,et la liste des threads actifs de ce groupe dans le tableau tarray ( tarray doit exister et être de taillesupérieure ou égale à la valeur renvoyée par activeCount ()).

public void interrupt ()

Cette méthode et les deux suivantes ne sont implémentées qu'à partir de Java 1.1. Cette méthode permetd'interrompre un thread. Si ce thread est en attente, il est exécuté et une exceptionInterruptedException est déclenchée.

public static boolean interrupted ()public boolean isInterrupted () public String toString ()

Renvoie une chaîne de caractère représentant un thread (comprenant son nom, sa priorité et le nom dugroupe de thread auquel il appartient). Cette méthode outrepasse celle de la classe Object.

public void destroy ()public int countStackFrames () throws IllegalThreadStateException

Exemples

Application PaperBoardServer .Applets Chrono , AfficheurDeCalcul , ObservateurCalcul , PaperBoardClient , AnimationFleche , ScrollText etHorloge .

Page 100: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 1

Les classes internes

Les classes internesLes classes anonymes

Autres nouveautés Java 1.1

Ce chapitre décrit les ajouts apportés dans le langage Java à partir de Java 1.1, et particulièrement lesclasses internes (inner classes ).

Les classes internes

Syntaxe

Avec Java 1.0, il n'est possible de créer des classes public ou non qu'au niveau le plus haut dans unfichier .java , c'est à dire des classes externes dépendant directement d'un package. Java 1.1 introduit lapossibilité de créer des classes internes ou interfaces internes qui sont déclarées à l'intérieur d'une classeou d'une interface, en plus des méthodes et des variables :

class ClasseExterne{ // Déclararation d'une classe interne ModifieurClasseInterne class ClasseInterne { // Corps de ClasseInterne : // Déclaration des variables, des méthodes, des constructeurs,... } // Déclaration d'une classe interne dérivant d'une super classe // et implémentant une interface ModifieurClasseInterne class ClasseInterne2 extends nomDeSuperClasse implements nomInterface //, nomInterface2, ... { // ... } // Déclararation d'une interface interne ModifieurInterfaceInterne interface InterfaceInterne { } // Autres déclarations}

ModifieurClasseInterne est optionnel et peut être un ou plusieurs des mots-clés suivants :

public, protected ou private : Ces mots clés indiquent le contrôle d'accès de la classe interne etont le même sens que pour la déclaration des variables d'une classe. final : Comme pour une classe externe, une classe interne déclarée final ne peut être dérivée. abstract : Comme pour une classe externe, il est impossible de créer une instance d'une classeinterne déclarée abstract. static : Les classes internes déclarées sont très différentes si elles sont déclarées static ou non.Comme pour les variables static, une classe interne static ou ses instances ne dépend d'aucuneinstance de la classe externe dans laquelle est elle est définie. Dans ce cas, il est possible de créerune instance d'une classe interne simplement par new ClasseExterne.ClasseInterne () parexemple.L'instance d'une classe interne non static stocke automatiquement une référence vers l'instance dela classe externe ClasseExterne dont elle dépend, ce qui permet d'utiliser directement toutes lesméthodes et les variables de la classe ClasseExterne. Cette référence doit être donnée à la créationd'un objet de cette classe interne comme par exemple objetClasseExterne.new ClasseInterne ()pour créer un objet de classe ClasseInterne dépendant de l'objet objetClasseExterne de classe

Page 101: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 2

ClasseExterne.

ModifieurInterfaceInterne peut prendre toutes les valeurs que ModifieurClasseInterne , sauf final(abstract est implicite).Une classe interne non static ne peut pas déclarer des variables et des méthodes static.

De même dans un bloc, il est possible de déclarer des classes internes locales dont la portée est limitéeau bloc. Dans ce cas, ModifieurClasseInterne ne peut être prendre comme valeur que final ouabstract.

Une classe interne peut déclarer elle-même d'autres classes internes.

Pour chacune des classes internes déclarées est généré un fichier .class à la compilation. Pour assurerl'unicité du nom de ces fichiers, la syntaxe suivante est utilisée : La classe interne ClasseInternedéclarée à l'intérieur d'une classe externe ClasseExterne, sera stockée dans le fichierClasseExterne$ClasseInterne.class .Pour les classes internes déclarées dans un bloc, le nom de fichier comporte en plus un identifiantnumérique généré par le compilateur donnant comme nom de fichier par exempleClasseExterne$1$ClasseInterne.class .

Java 1.1 permet de déclarer des classes internes (inner classes ). Les classes internes staticcorrespondent aux classes internes du C++ (nested classes ). Par contre les classes internes non staticsont un concept inexistant en C++ et permettent aux instances de ces classes de garder implicitementun lien avec l'instance de la classe externe dont elles dépendent.

Le mécanisme utilisé par le compilateur Java 1.1 pour générer les classes internes est entièrementcompatible avec la Machine Virtuelle Java 1.0.Donc même si vous faites fonctionner vos applets avec Java 1.0, vous pouvez leur permettre quandmême d'utiliser les classes internes en les compilant avec un compilateur Java 1.1 en donnant commeclasspath la librairie des classes de Java 1.0.

Utilisation

Bien qu'il ne soit pas obligatoire de s'en servir, les classes internes apportent un plus pour l'organisationet la programmation des classes de votre programme :

L'existence de certaines classes n'a de sens que dans le contexte d'une autre classe. Dans ce cas, il peut êtreintéressant de les déclarer comme classes internes pour montrer aux utilisateurs de ces classes dans quelcontexte elles s'utilisent. Les classes externes peuvent avoir un contrôle d'accès public ou friendly . Toutes les classes non public d'unpackage donné sont accessibles à toutes les autres classes de ce package, ce qui n'a pas toujours l'effet désiré.Une classe interne dont le contrôle d'accès est private n'est accessible que par la classe externe dans laquelleelle est déclarée. Le nommage des classes est simplifié : certaines classes utilitaires de même genre peuvent avoir à êtredéclarées dans des contextes différents. Si ces classes sont déclarées comme classes internes, elles pourrontporter le même nom sans interférer entre elles, et vous n'aurez pas à inventer des noms à rallonge pour lesdifférencier. Comme une classe interne peut être déclarée n'importe où dans une classe, il est permis de la rapprocher del'endroit où elle est le plus utilisée, pour améliorer la lisibilité du programme. La possibilité d'utiliser directement toutes les variables et les méthodes de la classe externe dans une classeinterne non static simplifie dans de nombreux cas la programmation, comme dans le cas suivant repris del'applet AfficheurDeCalcul : Cette applet déclare les deux classes non public Calculateur et Afficheurdérivant de la classe Thread. Ces deux classes ont besoin d'une référence sur l'instance de l'applet etl'utilisation des classes internes permet d'en simplifier la programmation car elles gardent cette référenceautomatiquement :

Page 102: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 3

Sans classe interne Avec classe interne

import java.applet.Applet;import java.awt.*; public class AfficheurDeCalcul extends Applet{ private Thread calculateur; private Thread afficheur; public void start () { setBackground (Color.white); // Création de deux instances des classes // Calculateur et Afficheur calculateur = new Calculateur (this); afficheur = new Afficheur (this); calculateur.start (); afficheur.start (); } // ... // Les méthodes stop (), calculerCourbe () // dessinerCourbe () et paint () // sont inchangées } // Fin de AfficheurDeCalcul // Classe friendly dérivant de Thread class Calculateur extends Thread{ private AfficheurDeCalcul applet; public Calculateur (AfficheurDeCalcul applet) { this.applet = applet; } public void run () { while (isAlive ()) applet.calculerCourbe (); }} // Classe friendly dérivant de Thread class Afficheur extends Thread{ private AfficheurDeCalcul applet; public Afficheur (AfficheurDeCalcul applet) { this.applet = applet; } public void run () { while (isAlive ()) applet.dessinerCourbe (); }}

import java.applet.Applet;import java.awt.*; public class AfficheurDeCalcul extends Applet{ private Thread calculateur; private Thread afficheur; public void start () { setBackground (Color.white); // Création de deux instances des classes // internes Calculateur et Afficheur calculateur = new Calculateur (); afficheur = new Afficheur (); calculateur.start (); afficheur.start (); } // ... // Les méthodes stop (), calculerCourbe () // dessinerCourbe () et paint () // sont inchangées // Classe interne dérivant de Thread private class Calculateur extends Thread { public void run () { while (isAlive ()) // calculerCourbe (), méthode de // la classe externe AfficheurDeCalcul // peut être appelée directement calculerCourbe (); } } // Classe interne dérivant de Thread private class Afficheur extends Thread { public void run () { while (isAlive ()) // dessinerCourbe (), méthode de // la classe externe AfficheurDeCalcul // peut être appelée directement dessinerCourbe (); } } } // Fin de AfficheurDeCalcul

Les classes anonymes

Par extension des classes internes locales, vous pouvez déclarer aussi des classes "anonymes" en Java.C'est un ajout à la syntaxe de l'opérateur new : Après l'instruction new Classe1 (), il est possibled'ajouter un bloc permettant de modifier le comportement de Classe1, en outrepassant telle ou telleméthode de Classe1.Résultat : un objet d'une classe "anonyme" dérivée de Classe1 est créé, puis un cast implicite de cetteclasse vers Classe1 est effectué.

Page 103: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 4

SuperClasse objet = new SuperClasse (/* argument1, argument2, ...*/) { // Méthodes de SuperClasse outrepassées // pour modifier le comportement de SuperClasse };

Dans la même logique, il est possible de créer une instance d'une classe anonyme implémentant uneinterface InterfaceX, grâce à l'instruction :

InterfaceX objet2 = new InterfaceX () { // Implémentation de toutes les méthodes de InterfaceX };

Dans ce cas, le bloc qui suit new InterfaceX () doit implémenter toutes les méthodes de InterfaceXpour qu'il soit possible de créer une instance d'une telle classe.Comme toute classe interne, une classe anonyme peut déclarer un ensemble de variables et de méthodesd'instances.

Pour chacune des classes anonymes déclarées est généré un fichier .class à la compilation. Pour assurerl'unicité du nom de ces fichiers, le nom de chaque fichier est constitué du nom de la classe externe suividu symbole $ et d'un identifiant numérique généré par le compilateur, comme par exempleClasseExterne$1.class .

Bien que les classes anonymes peuvent en apparence obscurcir la lisibilité d'un programme, il existe unensemble de circonstances où il est intéressant de les utiliser :

Pour créer une instance d'un objet d'une classe dont on veut outrepasser juste une ou deuxméthodes. Implémenter localement une interface telle qu'un listener . Ce type d'interface est utilisé dans lagestion de l'Interface Utilisateur AWT à partir de Java 1.1 pour déclarer les méthodes qu'une classedoit implémenter pour être rappelées quand un événement survient.

Par exemple, il est possible d'encore simplifier l'applet AfficheurDeCalcul , en remplaçant les classesinternes Calculateur et Afficheur par des classes anonymes :

import java.applet.Applet;import java.awt.*; public class AfficheurDeCalcul extends Applet{ private Thread calculateur; private Thread afficheur; public void start () { setBackground (Color.white); // Création de deux instances de classes // anonymes implémentant la méthode run () // de la classe Thread calculateur = new Thread () { public void run () { while (isAlive ()) // calculerCourbe (), méthode de // la classe externe AfficheurDeCalcul // peut être appelée directement calculerCourbe (); } }; afficheur = new Thread () { public void run () { while (isAlive ()) // dessinerCourbe (), méthode de // la classe externe AfficheurDeCalcul

Page 104: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 5

// peut être appelée directement dessinerCourbe (); } }; calculateur.start (); afficheur.start (); } // ... // Les méthodes stop (), calculerCourbe () // dessinerCourbe () et paint () // sont inchangées}

Les classes anonymes permettent de transformer facilement un programme existant pour exécuter unbloc d'instructions dans un thread isolé en ajoutant sur place les quelques instructions suivantes :

Avant Après

// ... { // Bloc d'instructions }

// ... new Thread () { public void run () { // Bloc d'instructions } }.start ();

Pour éviter toute confusion avec le reste des instructions, utilisez des règles d'écriture et uneindentation claires pour l'écriture des classes anonymes.

Autres nouveautés Java 1.1

Initialisations d'instance

En plus des initialisations static, il est possible d'ajouter à une classe des blocs d'initialisationsd'instance. Ces blocs d'instructions sont exécutés à la création d'un objet juste après le constructeur desa super classe et avant tout constructeur de sa classe.Ces initialisations sont surtout utiles pour les classes anonymes qui ne peuvent pas déclarer deconstructeurs.

Sauf pour les classes anonymes, les blocs d'initialisations d'instance d'une classe Classe1 ne peuventdéclencher d'exceptions que si tous les constructeurs de Classe1 déclarent qu'ils sont susceptibles dedéclencher ces classe d'exceptions avec la clause throws.

Initialisation de tableaux

Les tableaux peuvent être initialisés à leur création en faisant suivre l'instruction de création du tableaunew Classe0 [], par la liste des éléments à stocker, comme dans l'exemple suivant :

class Classe1{ // Les deux instructions suivantes sont équivalentes int [ ] tab1 = {1, 2}; int [ ] tab2 = new int [] {1, 2}; void methode1 (String [] tab) { } void methode2 ()

Page 105: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes internes Page: 6

{ // Possibilité de créer des tableaux, envoyés // directement en paramètre à une méthode methode1 (new String [] {"valeur1", "valeur2}); }}

Comme vous pouvez le voir, c'est surtout pratique pour envoyer un tableau en paramètre sans avoir à ledéclarer dans une instruction séparée.

Utilisation du mot-clé class

Toute classe ou interface peut être suivie du mot-clé class : ceci produit le même effet que l'utilisationde la méthode forName () de la classe Class.L'instruction String.class équivalente à Class.forName ("java.lang.String") est bien plus pratique àutiliser car vous n'êtes pas obligé de donner le package complet de la classe String et d'intercepterl'exception ClassNotFoundException que peut déclencher la méthode forName ().

Cette nouvelle syntaxe peut être aussi utilisée pour tous les types de base et void, de la manière suivante:

byte.classshort.classint.classlong.classfloat.classdouble.classchar.classboolean.class void.class

Ceci est utilisé en particulier par les classes du package java.lang.reflect pour manipuler tous lestypes Java (que ce soient des classes ou des types de base) sous forme d'un objet de classe Class.

Variables locales et paramètres final

Les variables locales et les paramètres d'une méthode ou d'un constructeur peuvent être déclarés final.

TypeRetour methode1 (final TypeParam1 param1Name /*,... */){ final TypeVariable variableLocale1 = valeur ; // ...}

Il n'est pas obligatoire d'initialiser une variable locale final dès sa déclaration, mais par contre il n'estpossible de lui assigner qu'une seule fois une valeur.Tout paramètre ou toute variable locale que vous voulez utiliser dans une classe anonyme doivent êtredéclarés final. Ceci permet à cette classe anonyme d'utiliser ces variables temporaires sans risquequ'elles soient modifiées ultérieurement.Par contre, toutes les variables d'instance ou de classe existent de façon permanente et peuvent êtreutilisées dans une classe anonyme qu'elles soient final ou non.

Comme avec const en C/C++, les paramètres d'une méthode peuvent être déclarés constants grâce àfinal en Java. Mais ceci interdit uniquement à une méthode de modifier la valeur d'un paramètre. Si unparamètre param1 final est une référence sur un objet, il impossible de modifier param1 mais l'objetdésigné par param1 lui peut être modifié.

Page 106: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 1

Conventions d'écriture et portage

Conventions d'écriturePortage de programmes écrits en C/C++

Ce chapitre vous indique les conventions généralement utilisées dans l'écriture des programmes et dessuggestions pour vous aider à récupérer des programmes écrits en C ou C++.Ces suggestions et les exemples qui sont donnés peuvent vous servir aussi comme complémentd'information avant de passer à l'étude de la bibliothèque Java.

Conventions d'écriture

Par convention, l'écriture de vos classes devrait respecter les conventions suivantes :

Si un fichier .java définit une classe ou une interface public, cette classe et le nom du fichierdoivent avoir le même nom. Le nom des classes commence par une majuscule, et représente une suite d'un ou plusieurs motsen minuscules, avec chaque début de mot en majuscule (par exemple MaClasse). Le nom des interfaces commence par une majuscule, et utilise généralement un adjectif qualificatif(se terminant souvent par able). Le nom des méthodes commence par une minuscule, et représente une action :

Les méthodes utilisées pour interroger ou modifier la valeur d'une variable var, doivents'appeler getVar () et setVar () respectivement, ou éventuellement isVar () et setVar ()si var est du type boolean. Cette convention n'est utile que si vous voulez utiliser facilementune classe comme JavaBean. Le nom des méthodes renvoyant une longueur se dénomme length (). Le nom des méthodes convertissant un objet en autre chose, commence par to (par exempletoString ()).

Le nom des variables non final commence par une minuscule. Ce type de variable est rarementdéclaré public ou protected ; il vaut mieux utiliser des variables private accessibles par desméthodes comme expliqué précédemment. Le nom des variables final (constantes) représente une suite d'un ou plusieurs mots enmajuscules, séparés par le caractère _ (par exemple MAX_PRIORITY). Le nom des packages représentant des sous-répertoires est en minuscules, et java est un nom depackage réservé pour les classes standards Java.

Comme vous pouvez le voir, ces conventions ne laissent que peu de choix sur la langue à utiliser dansun programme Java. Mais, comme toute convention, vous pouvez l'ignorer et créer votre propreconvention d'écriture.

Documentation des fichiers .java

Java définit des règles de syntaxe pour l'écriture des commentaires destinés à des fins de documentation.Si vous les respectez, vous pourrez les extraire pour fabriquer un fichier HTML, en utilisant lacommande javadoc .

Portage de programmes écrits en C/C++

Vous avez développé un certains nombres de routines en C ou de classes en C++, et vous aimeriez lesporter en Java... Les remarques signalées par les symboles et des chapitres précédents et lessuggestions qui suivent devraient vous guider pour mener à bien cette tâche qui peut prendre un certain

Page 107: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 2

temps suivant les fonctionnalités du C/C++ que vous avez utilisé.

Les suggestions décrites ici ne concernent que les routines C/C++ utilisant la bibliothèque standarddu C (stdio.h , stdlib.h ,...) et pas les applications utilisant les routines de l'Interface Graphique de tel outel système (Windows, XWindow/Motif,...).

Elles ne représentent pas forcément la solution idéale à tel ou tel problème, mais plutôt une solutionpragmatique et rapidement réalisable.Rien ne vous empêche de revoir complètement l'architecture de vos routines pour qu'elles respectentles principes de la programmation orientée objets à la lettre.

Conception des classes

Tout d'abord, essayez d'éventuellement modifier et de rassembler vos routines pour qu'elles puissentformer des classes cohérentes.Si la conception de vos routines n'utilise pas de principes de la programmation orientée objets commel'encapsulation, n'ayez pas de scrupules à transposer toutes vos variables globales et vos fonctions envariables et méthodes de classe static. Une fois votre première version de portage terminée, vouspourrez éventuellement utiliser plus amplement la programmation objet.N'oubliez d'ajouter le nom de la classe et l'opérateur point (.) devant les variables et les méthodesstatic d'une classe, quand vous voulez y accéder en dehors de cette classe (comme par exempleSystem.arraycopy ()).

Java n'utilisant pas de fichiers header .h , il faut rassembler les déclarations de constantes et de typesavec les fonctions dans des classes déclarées dans un ou plusieurs fichiers .java .

Remplacement des définitions de type typedef

typedef peut être utilisé en C de deux manières différentes :

Pour donner un nom aux types structurés struct, aux unions union et éventuellement aux types pointeurs surces types. Tous les types structurés sont transformés en classes. Pour renommer un type de base C : Dans ce cas, soit vous créez une classe ne contenant qu'une variable dece type, soit vous remplacez le nom de ce type par le type de base Java correspondant partout où il est utilisé.

Remplacement des instructions de précompilation #define

#define s'utilise de deux manières différentes en C, l'une pour déclarer des constantes, l'autre pour créer desmacros : Les macros doivent être transformées en méthodes : ceci oblige à typer les paramètres d'une macro, mais grâceà la surcharge des méthodes, vous pouvez créer plusieurs méthodes de même nom mais avec des paramètresde type différent. Les constantes doivent être remplacées par des variables static final et ajoutées soit aux classes auxquelleselles se rapportent, soit éventuellement à une ou plusieurs interfaces implémentées dans les classes qui ontbesoin d'y avoir accès.

Remplacement des instructions de précompilation #ifdef, #else, #endif

#ifdef s'utilise en C pour indiquer au compilateur qu'il doit compiler ou non une partie du code selon qu'unsymbole est défini ou non. Il est très souvent utilisé pour ajouter des instructions spéciales de suivi lorsqu'unprogramme est en phase de mise au point (ou de debugging ).L'utilisation de constantes Java (variables static final) permettent de réaliser un effet comparable commedans l'exemple suivant :

Page 108: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 3

// Définit un symbole DEBUG#define DEBUG void methode (){ //... #ifdef DEBUG printf ("OK"); #endif}

class Classe1{ static final int DEBUG = true; void methode () { //... if (DEBUG) System.out.println ("OK"); }}

Un des avantages de l' instruction #ifdef est notamment qu'il permet d'alléger le code compilé (le fichier .obj )des instructions qui sont définis dans le bloc #ifdef si la condition est fausse. Le compilateur Java fait demême : c'est-à-dire que dans l'exemple précédent si vous définissez DEBUG comme étant égal à false,l'instruction System.out.println ("OK"); ne sera pas dans le fichier compilé Classe1.class. Comme lacondition if (DEBUG) est forcément fausse, le compilateur utilise dès le départ une optimisation qui exclutl'instruction qui suit.

Remplacement des énumérations enum

Les énumérations enum définissent un ensemble cohérent de constantes dont la valeur est entière. Vouspouvez les remplacer soit par des classes déclarant un ensemble de constantes public, soit par des interfacesimplémentées dans les classes qui en ont besoin.

Remplacement des unions union

En C, les variables d'un type union permettent de typer de manière différente leur zone mémoire. Dansl'exemple :

union{ double x; int a;} varUnion;

varUnion a pour taille, la taille du plus grand de ses éléments, ici la taille d'un double (8 octets), et mémorisesoit un double par varUnion.x ou soit un int par varUnion.a.

Le portage le plus rapide consiste à remplacer les variables C de type union par une référence de classeObject. Une variable de classe Object permet de désigner n'importe quel objet Java, car toutes les classeshéritent de cette classe. De plus, l'opérateur instanceof permet de tester qu'elle est la classe de l'objetmémorisé par une telle référence. Si comme dans l'exemple précédent l'union C utilise des types de base,utilisez éventuellement à la place les classe d'emballages Java (Boolean, Character, Integer, Long, Float,Double).

Voici un programme C et un programme Java mis en parallèle pour illustrer une manière de transformer uneunion de cette manière. Ces programmes permettent d'évaluer une expression comportant des nombres doubleet les opérateurs +, -, * et /, mémorisée sous forme d'un arbre :

#include <stdio.h>#include <stdlib.h> struct _Expression;/* Structure Operation mémorisant *//* une expression avec opérateur binaire */typedef struct{ char operateur; struct _Expression *expr1, *expr2;} Operation;

// Fichier TestExpression.java// A exécuter par la commande // java TestExpression // Classe Operation mémorisant // une expression avec opérateur binaireclass Operation{ char operateur; Object expr1, expr2;}

Page 109: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 4

#define TYPE_VALEUR 0#define TYPE_OPERATION 1 /* Structure _Expression mémorisant *//* une union entre un double et une *//* valeur de type Operation *//* et un champ type permettant de *//* connaître le type dans l'union */typedef struct _Expression{ int type; union { double valeur; Operation operation; } expr;} *Expression; double calculerOperation (Operation oper);double calculerExpression (Expression expr){ /* Calcul du résultat suivant le type */ /* d'expression mémorisée dans l'union */ switch (expr->type) { case TYPE_VALEUR : return expr->expr.valeur; case TYPE_OPERATION : return calculerOperation (expr->expr.operation); } return 0;} /* Calcul d'une opération binaire */double calculerOperation (Operation oper) { /* Evaluation des deux opérandes */ double val1 = calculerExpression (oper.expr1); double val2 = calculerExpression (oper.expr2); switch (oper.operateur) { case '+' : return val1 + val2; case '-' : return val1 - val2; case '*' : return val1 * val2; case '/' : return val1 / val2; } return 0;} void main (){ /* Allocation de 5 expressions */ Expression expr = malloc (5 * sizeof (struct _Expression)); /* Construction de l'arbre représentant */ /* l'expression 2 + 3 / 4 */ expr [0].type = expr [1].type = TYPE_OPERATION; expr [0].expr.operation.operateur = '+'; expr [0].expr.operation.expr1 = &expr [2]; expr [0].expr.operation.expr2 = &expr [1]; expr [1].expr.operation.operateur = '/'; expr [1].expr.operation.expr1 = &expr [3]; expr [1].expr.operation.expr2 = &expr [4]; expr [2].type = expr [3].type = expr [4].type = TYPE_VALEUR; expr [2].expr.valeur = 2; expr [3].expr.valeur = 3;

// Pas besoin d'une classe Expression :// une expression est mémorisée par une// référence de classe Object// contenant soit un objet de classe// Double, soit une objet de classe// Operation // Classe TestExpressionpublic class TestExpression{ static double calculerExpression (Object expr) { // Calcul du résultat suivant la classe // de l'objet expr if (expr instanceof Double) return ((Double)expr).doubleValue (); if (expr instanceof Operation) return calculerOperation ((Operation)expr); throw new IllegalArgumentException (); } // Calcul d'une opération binaire static double calculerOperation (Operation oper) { // Evaluation des deux opérandes double val1 = calculerExpression (oper.expr1); double val2 = calculerExpression (oper.expr2); switch (oper.operateur) { case '+' : return val1 + val2; case '-' : return val1 - val2; case '*' : return val1 * val2; case '/' : return val1 / val2; } throw new IllegalArgumentException (); } public static void main (String [] arg) { // Construction de l'arbre représentant // l'expression 2 + 3 / 4 Operation expr1 = new Operation (); expr1.operateur = '/'; expr1.expr1 = new Double (3); expr1.expr2 = new Double (4); Operation expr0 = new Operation (); expr0.operateur = '+'; expr0.expr1 = new Double (2); expr0.expr2 = expr1;

Page 110: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 5

expr [4].expr.valeur = 4; printf ("Resultat de 2 + 3/4 = %g", calculerExpression (&expr [0])); }

System.out.println ( "Resultat de 2 + 3/4 = " + calculerExpression (expr0)); }}

Enfin, voici une version plus orientée objet du programme TestExpression.java :

// Déclaration de l'interface Calculable// (Aurait pu être aussi une classe abstract)interface Calculable{ double calculer ();} // Classe Nombre mémorisant un double// Le résultat de calculer () est ce nombreclass Nombre implements Calculable{ private double nombre; // Constructeur Nombre (double nombre) { this.nombre = nombre; } // Implémentation de la méthode calculer () public double calculer () { return nombre; }} // Classe Operation mémorisant une expression avec opérateur binaire// Le résultat de calculer () est l'évaluation de cette expressionclass Operation implements Calculable{ private char operateur; private Calculable expr1, expr2; // Constructeur Operation (char operateur, Calculable expr1, Calculable expr2) { this.operateur = operateur; this.expr1 = expr1; this.expr2 = expr2; } // Implémentation de la méthode calculer () public double calculer () { // Evaluation des deux opérandes double val1 = expr1.calculer (); double val2 = expr2.calculer (); switch (operateur) { case '+' : return val1 + val2; case '-' : return val1 - val2; case '*' : return val1 * val2; case '/' : return val1 / val2; } throw new IllegalArgumentException ("Operateur inconnu"); }} // Classe de test TestExpressionpublic class TestExpression{ public static void main (String [] arg) { // Création de l'expression 2 + 3 / 4

Page 111: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 6

Calculable expr = new Operation ('+', new Nombre (2), new Operation ('/', new Nombre (3), new Nombre (4))); System.out.println ("Resultat de 2 + 3/4 = " + expr.calculer ()); }}

Passage des valeurs par adresse

Comme il est signalé au chapitre sur la création des classes, tous les paramètres des fonctions sont passés parvaleur en Java. Si certaines de vos fonctions requièrent de leur passer des paramètres d'un type de base paradresse, comme dans l'exemple suivant :

void fonction1 (int *param1);int fonction2 (double *param1);

vous devrez transformer vos fonctions d'une des trois manières suivantes : Pour une fonction void du style de fonction1 (), vous pouvez la transformer en int fonction1 (intparam1), et renvoyer dans fonction1 () la valeur modifiée de param1. L'inconvénient de cette méthodeest qu'elle vous oblige à transformer tous les appels à fonction1 () pour en récupérer la valeur deretour. Pour une fonction du style fonction2 (), vous pouvez créer une classe DoubleValue mémorisant unevariable value de type double et passer une instance de DoubleValue à fonction2 (). Ainsi, si vousmodifiez la valeur de la variable value dans fonction2 (), l'appelant de fonction2 () aura accès à cettevariable modifiée. Notez que cette méthode est applicable aussi à fonction1 (). Dans les deux cas, la manière la plus rapide mais la moins orientée objet consiste à créer un tableaucontenant un seul élément. Comme pour tout objet Java, si vous modifiez l'élément que contient letableau dans la fonction appelée, l'appelant aura accès à cet elément modifié.

Voici un programme C et un programme Java mis en parallèle pour illustrer ces trois types de transformation :

Page 112: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 7

void fonction1 (int *param1){ *param1 = 1; /* ... */} int fonction2 (double *param1){ *param1 = 1; /* ... */ return 0;} void fonction3 (float *param1){ *param1 = 1; /* ... */ return 0;} void fonctionAppelante (){ int argInt = 0; double argDouble = 0; float argFloat = 0; int valRetour; fonction1 (&argInt); valRetour = fonction2 (&argDouble); fonction3 (&argFloat); /* ... */}

class VotreClasse{ int fonction1 (int param1) { param1 = 1; // ... return param1; } int fonction2 (DoubleValue param1) { param1.value = 1; // ... return 0; } int fonction3 (float [] param1) { param1 [0] = 1; // ... return 0; } void fonctionAppelante () { int argInt = 0; DoubleValue argDouble = new DoubleValue (0); int valRetour; float [] argFloat = {0}; argInt = fonction1 (argInt); valRetour = fonction2 (argDouble); fonction3 (argFloat); // ... }} // Classe d'emballage du type double// avec variable d'accès publicclass DoubleValue{ public double value; public DoubleValue (double value) { this.value = value; }}

Les classes d'emballage des types de base Boolean, Character, Integer, Long, Float, Double nepermettent pas de modifier la valeur de type de base qu'elle mémorise, donc elles ne peuvent pas êtreutilisées dans ce cas.Si vous utilisez très souvent le passage de valeurs par adresse, il est conseillé de créer des le départvos propres classes d'emballage mémorisant une variable public de type de base.

Allocation dynamique

Java ne permet de créer dynamiquement que des instances de classes, grâce à l'opérateur new. Tous les appelsau fonctions malloc () et calloc () doivent être remplacés par new Classe1 () pour créer une instance deClasse1 et par new Classe1 [nbreElements] pour créer un tableau mémorisant nbreElements références declasse Classe1 (il est rappelé que vous devez individuellement créer ou affecter chacun des nbreElementsréférences du tableau).Java n'a pas d'équivalent de la fonction realloc () et ne permet pas d'agrandir un tableau existant : il fautcréer un second tableau, puis copier le premier dans le second grâce à la méthode arraycopy () de la classeSystem. La classe Vector peut éventuellement vous servir pour utiliser des tableaux de taille variables, maisceci peut vous obliger à transformer beaucoup d'instructions de votre programme : Comme Java n'autorise pasla surcharge de l'opérateur [ ], l'accès aux éléments d'une instance de Vector ne se fait que par des méthodes.

Page 113: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 8

Tous les appels à free (ptr) peuvent être directement supprimés ou éventuellement remplacés par ptr =null; dans les cas où vous voulez que l'objet désigné par ptr ne soit plus référencé par ptr.

Plus vous maîtriserez le fonctionnement du Garbage Collector et la notion de référence, plus vous n'hésiterezplus à supprimer les instructions free () (C'est un des plus grand plaisirs du portage !).

Utilisation des chaînes de caractères

En Java, les chaînes de caractères sont représentées par les classes String et StringBuffer. Il faut remplacertous les tests de caractère nul ('\0') permettant de savoir si on a atteint la fin d'une chaîne de caractères en C,par des appels aux méthodes length () de ces classes.

Arithmétique des pointeurs

L'arithmétique des pointeurs est une notion absente en Java. Vous devrez remplacer son usage par l'utilisationd'un indice courant associé à un tableau, ou pour les chaînes de caractères utiliser éventuellement lesméthodes de la classe String comme substring (), pour créer des chaînes de caractères à la volée sans sesoucier de la libération de ces chaînes puisque le Garbage Collector est là pour ça.

Voici un programme C et un programme Java mis en parallèle pour illustrer une manière de transformer unefonction chercherSousChaine (str1, str2) , qui recherche dans la chaîne de caractères str1 une chaîne str2(équivalent de la fonction C strstr (char *str1, char *str2) et de la méthode Java indexOf (String str)de la classe String) :

#include <string.h> char *chercherSousChaine (char *str1, char *str2){ while (strlen (str1) >= strlen (str2)) if (!strncmp (str1, str2, strlen (str2))) return str1; else str1++; return NULL; // Pas trouvé}

class ClasseChaine{ public int chercherSousChaine (String str1, String str2) { int i = 0; while (str1.length () >= str2.length ()) if (str1.startsWith (str2)) return i; else { str1 = str1.substring (1); i++; } return -1; // Pas trouvé }}

Transformation des pointeurs sur fonctions

En C, les pointeurs sur fonctions sont très pratiques et beaucoup de bibliothèques C en font l'usage. Sonutilisation se regroupe principalement en deux catégories : Comme paramètre d'une fonction fct (), elle est utilisée souvent comme fonction à rappeler (call-back enanglais), pour modifier le comportement de fct (). Par exemple, la fonction de comparaison passée enparamètre à la fonction qsort () permet de trier un tableau de n'importe quel type d'élément, ou la procédurepassée en paramètre à la fonction CreateDialog () de Windows permet de modifier le comportement d'uneboite de dialogue.Ce type de pointeurs de fonctions peut être transformé par l'utilisation de méthodes outrepassées et a étéabordée au chapitre sur la création des classes. Comme élément d'un tableau regroupant un ensemble de pointeurs sur fonctions ayant toutes le mêmeprototype. Ce procédé est souvent utilisé par les automates, pour qu'ils puissent exécuter une action pour unétat donné.Dans ce cas, soit vous utilisez le procédé précédent en mémorisant des objets à place des fonctions dans letableau, comme dans l'exemple suivant :

Page 114: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 9

/* Déclaration d'un type pointeur sur *//* fonction prenant en paramètre un int */typedef void (* Action) (int param); /* Déclaration de deux fonctions *//* du même type que Action () */ void action1 (int param){ /* Corps de action1 () */ } void action2 (int param){ /* Corps de action2 () */ } /* Déclaration d'un tableau mémorisant *//* différents pointeurs de type Action */Action tabAction [] = {action1, NULL, action2, action1}; void ExecuterAction (int etat, int param){ /* Appel de fonction suivant etat */ if (tabAction [etat] != NULL) tabAction [etat] (param);} /* ... */

// Déclaration d'une interface déclarant une// méthode prenant en paramètre un intinterface Action{ void action (int param);} // Déclaration de deux classes implémentant // la méthode action () de cette interfaceclass Action1 implements Action{ public void action (int param) { /* Corps de action () */ }} class Action2 implements Action{ public void action (int param) { /* Corps de action () */ }} // Déclaration de la classe Automateclass Automate{ // Déclaration d'un tableau mémorisant // différents objets dont la classe // implémente l'interface Action Action tabAction [] = {new Action1 (), null, new Action2 (), new Action1 ()}; void ExecuterAction (int etat, int param) { // Appel de action () en fonction de etat if (tabAction [etat] != null) tabAction [etat].action (param); } // ...}

soit vous associez une constante à chacune des fonctions, vous remplacez les pointeurs du tableau par cesconstantes et choisissez la bonne fonction à appeler grâce à l'instruction switch (), comme dans l'exemplesuivant :

Page 115: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 10

/* Déclaration d'un type pointeur sur *//* fonction prenant en paramètre un int */typedef void (* Action) (int param); /* Déclaration de deux fonctions *//* du même type que Action () */void action1 (int param){ /* Corps de action1 () */ } void action2 (int param){ /* Corps de action2 () */ } /* Déclaration d'un tableau mémorisant *//* différents pointeurs de type Action */Action tabAction [] = {action1, NULL, action2, action1}; void ExecuterAction (int etat, int param){ /* Appel de fonction suivant etat */ if (tabAction [etat] != NULL) tabAction [etat] (param);} /* ... */

// Déclaration de la classe Automate class Automate{ // Déclaration de deux fonctions // d'action void action1 (int param) { /* Corps de action1 () */ } void action2 (int param) { /* Corps de action2 () */ } // Déclaration des deux constantes // représentant les deux méthodes final static int ACTION1 = 1; final static int ACTION2 = 2; // Déclaration d'un tableau mémorisant // différentes constantes d'action int tabAction [] = {ACTION1, 0, ACTION2, ACTION1}; void ExecuterAction (int etat, int param) { // Appel de la bonne méthode // en fonction de etat switch (etat) { case ACTION1 : action1 (param); break; case ACTION2 : action2 (param); break; } }}

Remplacement de l'héritage multiple

Java ne permet pas l'héritage multiple du C++. Si vous voulez néammoins conserver une architecture declasses qui utilise l'héritage multiple, vous pouvez utiliser les interfaces, en utilisant par exemple la solutionsuivante :

Page 116: CJava

vendredi 11 février 2000 Du C/C++ à Java : Conventions d'écriture et portage Page: 11

class Type1{ public : void methode1 () { /* ... */ }}; class Type2{ public : void methode2 () { /* ... */ }}; class ClasseDerivee : public Type1, public Type2{ // La classe ClasseDerivee hérite des // méthodes methode1 () et methode2 ()}; void main (){ Type1 *objet1 = new Type1 (); Type2 *objet2 = new Type2 (); ClasseDerivee *objet3 = new ClasseDerivee (); objet3->methode1 (); objet3->methode2 (); // Cast implicite vers les super classes objet1 = objet3; objet2 = objet3;}

class Type1{ public void methode1 () { /* ... */ }} // Utilisation d'une interface à la place// de la seconde classeinterface Type2{ void methode2 ();} class Classe2 implements Type2{ public void methode2 () { /* ... */ }} public class ClasseDerivee extends Type1 implements Type2{ // Création d'une instance de Classe2 // pour remplacer le second lien d'héritage Type2 objetClasse2 = new Classe2 (); // Implémentation de methode2 () pour // qu'elle appelle la méthode de Classe2 public void methode2 () { objetClasse2.methode2 (); } public static void main (String [] args) { Type1 objet1 = new Type1 (); Type2 objet2 = new Classe2 (); ClasseDerivee objet3 = new ClasseDerivee (); objet3.methode1 (); objet3.methode2 (); // Cast implicite vers la super classe // ou l'interface Type2 objet1 = objet3; objet2 = objet3; }}

Cette solution peut être longue à programmer si les super classes définissent un nombre important deméthodes. Par contre, cette solution permet de modifier aisément le programme qui utilise les classestransformées en interfaces : vous n'avez qu'à modifier le nom de la classe utilisée à l'instantiation des objets(ici transformer new Type2 () en new Classe2 ()).

Autres problèmes propres au C++

Paramètres passés par référence en C++ : si le paramètre est d'un type de base, vous devrez le traiter commes'il était passé par adresse. Si le paramètre est une instance d'une classe ou une structure, supprimersimplement le symbole & de la déclaration. Les appels à l'opérateur delete du C++ pour des destructeurs n'effectuant que des libérations de mémoiredeviennent normalement inutiles en Java. Pour les autres vous pouvez créer une méthode delete () dans vosclasses, et remplacer les appels delete objet; par objet.delete ();.

Page 117: CJava

vendredi 11 février 2000 Du C/C++ à Java : La bibliothèque Java Page: 1

La bibliothèque Java 1.0

Les packages de la bibliothèque JavaHiérarchie des classes Java 1.0

Maintenant que vous connaissez le langage Java, il vous reste à apprendre les classes Java fournies enstandard avec la Machine Virtuelle Java.

Il est fourni avec le JDK le code source des classes des packages Java standards. Alors, n'hésitez pas àle consulter si vous recherchez plus d'informations sur le fonctionnement d'une classe ou d'uneméthode.

Dans certaines classes, vous pouvez être étonné que certaines méthodes synchronized semblentsimilaires à d'autres qui ne le sont pas. Ceci tient généralement du fait que certaines méthodes s'appellententre elles, et seule la méthode finalement appelée est synchronized.

Les packages de la bibliothèque Java 1.0

Les packages ci-après sont cités dans l'ordre des chapitres du manuel.

Classes de base : le package java.lang

Ce package est développé dans le chapitre suivant et rassemble les classes de base de Java. Toutes lesclasses et interfaces de java.lang sont automatiquement importées par le compilateur.

Gestion de données et utilitaires : le package java.util

Ce package est développé dans le chapitre sur les outils Java et rassemble des classes d'utilitaires(gestion des collections de données, génération de nombres aléatoires, énumération, date,...). Il définitaussi les classes d'exceptions EmptyStackException et NoSuchElementException.

Les entrées-sorties : le package java.io

Ce package est développé dans le chapitre sur la gestion des fichiers et des flux de données et rassembleles classes permettant de gérer les entrées-sorties (accès fichiers, gestion de répertoires,...). Il définitaussi les classes d'exceptions IOException, EOFException, FileNotFoundException,InterruptedIOException et UTFDataFormatException.

Les accès réseau : le package java.net

Ce package est développé dans le chapitre sur les accès au réseau et rassemble les classes permettant degérer les accès réseau. Il définit aussi les classes d'exceptions MalformedURLException,ProtocolException, SocketException, UnknownHostException et UnknownServiceException.

Gestion des applets : le package java.applet

Ce package est développé dans le chapitre sur les applets. La classe Applet et les interfaces de cepackage permettent de programmer une applet Java et d'intégrer une applet dans un navigateur.

Interface utilisateur : le package java.awt

Page 118: CJava

vendredi 11 février 2000 Du C/C++ à Java : La bibliothèque Java Page: 2

Ce package est développé dans le chapitre sur les composants AWT et les suivants. Les classes de cepackage permettent de programmer l'interface graphique d'un programme ou d'une applet Java. Il définitaussi les classes d'exceptions AWTException et AWTError.

Manipulation d'images : le package java.awt.image

Ce package est développé dans le chapitre sur les images. Les classes de ce package permettent demanipuler les images (gestion du chargement des images, filtres, gestion des couleurs,...).

Liaison avec l'interface utilisateur du système : le package java.awt.peer

Ce package est abordé dans le chapitre sur les composants. Il définit un ensemble d'interfaces permettantaux composants graphiques Java (boutons, fenêtres,...) d'être représentés à l'écran par les composants dusystème sur lequel fonctionne une Machine Virtuelle Java.

Hiérarchie des classes Java 1.0

Voici la hiérarchie des classes Java dans sa version 1.0.

Classe java.lang.Object Interface java.applet.AppletContext Interface java.applet.AppletStub Interface java.applet.AudioClip Classe java.util.BitSet (implémente java.lang.Cloneable) Classe java.lang.Boolean Classe java.awt.BorderLayout (implémente java.awt.LayoutManager) Classe java.awt.CardLayout (implémente java.awt.LayoutManager) Classe java.lang.Character Classe java.awt.CheckboxGroup Classe java.lang.Class Classe java.lang.ClassLoader Interface java.lang.Cloneable Classe java.awt.Color Classe java.awt.image.ColorModel

Classe java.awt.image.DirectColorModel Classe java.awt.image.IndexColorModel

Classe java.lang.Compiler Classe java.awt.Component (implémente java.awt.image.ImageObserver)

Classe java.awt.Button Classe java.awt.Canvas Classe java.awt.Checkbox Classe java.awt.Choice Classe java.awt.Container

Classe java.awt.Panel Classe java.applet.Applet

Classe java.awt.Window Classe java.awt.Dialog

Classe java.awt.FileDialog Classe java.awt.Frame (implémente java.awt.MenuContainer)

Classe java.awt.Label Classe java.awt.List Classe java.awt.Scrollbar Classe java.awt.TextComponent

Classe java.awt.TextArea Classe java.awt.TextField

Classe java.net.ContentHandler Interface java.net.ContentHandlerFactory Interface java.io.DataInput

Page 119: CJava

vendredi 11 février 2000 Du C/C++ à Java : La bibliothèque Java Page: 3

Interface java.io.DataOutput Classe java.net.DatagramPacket Classe java.net.DatagramSocket Classe java.util.Date Classe java.util.Dictionary

Classe java.util.Hashtable (implémente java.lang.Cloneable) Classe java.util.Properties

Classe java.awt.Dimension Interface java.util.Enumeration Classe java.awt.Event Classe java.io.File Classe java.io.FileDescriptor Interface java.io.FilenameFilter Classe java.awt.image.FilteredImageSource (implémente java.awt.image.ImageProducer) Classe java.awt.FlowLayout (implémente java.awt.LayoutManager) Classe java.awt.Font Classe java.awt.FontMetrics Classe java.awt.Graphics Classe java.awt.GridBagConstraints (implémente java.lang.Cloneable) Classe java.awt.GridBagLayout (implémente java.awt.LayoutManager) Classe java.awt.GridLayout (implémente java.awt.LayoutManager) Classe java.awt.Image Interface java.awt.image.ImageConsumer Classe java.awt.image.ImageFilter (implémente java.awt.image.ImageConsumer,java.lang.Cloneable)

Classe java.awt.image.CropImageFilter Classe java.awt.image.RGBImageFilter

Interface java.awt.image.ImageObserver Interface java.awt.image.ImageProducer Classe java.net.InetAddress Classe java.io.InputStream

Classe java.io.ByteArrayInputStream Classe java.io.FileInputStream Classe java.io.FilterInputStream

Classe java.io.BufferedInputStream Classe java.io.DataInputStream (implémente java.io.DataInput) Classe java.io.LineNumberInputStream Classe java.io.PushbackInputStream

Classe java.io.PipedInputStream Classe java.io.SequenceInputStream Classe java.io.StringBufferInputStream

Classe java.awt.Insets (implémente java.lang.Cloneable) Interface java.awt.LayoutManager Classe java.lang.Math Classe java.awt.MediaTracker Classe java.awt.image.MemoryImageSource (implémente java.awt.image.ImageProducer) Classe java.awt.MenuComponent

Classe java.awt.MenuBar (implémente java.awt.MenuContainer) Classe java.awt.MenuItem

Classe java.awt.CheckboxMenuItem Classe java.awt.Menu (implémente java.awt.MenuContainer)

Interface java.awt.MenuContainer Classe java.lang.Number

Classe java.lang.Double Classe java.lang.Float Classe java.lang.Integer Classe java.lang.Long

Classe java.util.Observable Interface java.util.Observer

Page 120: CJava

vendredi 11 février 2000 Du C/C++ à Java : La bibliothèque Java Page: 4

Classe java.io.OutputStream Classe java.io.ByteArrayOutputStream Classe java.io.FileOutputStream Classe java.io.FilterOutputStream

Classe java.io.BufferedOutputStream Classe java.io.DataOutputStream (implémente java.io.DataOutput) Classe java.io.PrintStream

Classe java.io.PipedOutputStream Classe java.awt.image.PixelGrabber (implémente java.awt.image.ImageConsumer) Classe java.awt.Point Classe java.awt.Polygon Classe java.lang.Process Classe java.util.Random Classe java.io.RandomAccessFile (implémente java.io.DataOutput, java.io.DataInput) Classe java.awt.Rectangle Interface java.lang.Runnable Classe java.lang.Runtime Classe java.lang.SecurityManager Classe java.net.ServerSocket Classe java.net.Socket Classe java.net.SocketImpl Interface java.net.SocketImplFactory Classe java.io.StreamTokenizer Classe java.lang.String Classe java.lang.StringBuffer Classe java.util.StringTokenizer (implémente java.util.Enumeration) Classe java.lang.System Classe java.lang.Thread (implémente java.lang.Runnable) Classe java.lang.ThreadGroup Classe java.lang.Throwable

Classe java.lang.Error Classe java.awt.AWTError Classe java.lang.LinkageError

Classe java.lang.ClassCircularityError Classe java.lang.ClassFormatError Classe java.lang.IncompatibleClassChangeError

Classe java.lang.AbstractMethodError Classe java.lang.IllegalAccessError Classe java.lang.InstantiationError Classe java.lang.NoSuchFieldError Classe java.lang.NoSuchMethodError

Classe java.lang.NoClassDefFoundError Classe java.lang.UnsatisfiedLinkError Classe java.lang.VerifyError

Classe java.lang.ThreadDeath Classe java.lang.VirtualMachineError

Classe java.lang.InternalError Classe java.lang.OutOfMemoryError Classe java.lang.StackOverflowError Classe java.lang.UnknownError

Classe java.lang.Exception Classe java.awt.AWTException Classe java.lang.ClassNotFoundException Classe java.lang.CloneNotSupportedException Classe java.lang.IllegalAccessException Classe java.lang.InstantiationException Classe java.lang.InterruptedException Classe java.io.IOException

Classe java.io.EOFException

Page 121: CJava

vendredi 11 février 2000 Du C/C++ à Java : La bibliothèque Java Page: 5

Classe java.io.FileNotFoundException Classe java.io.InterruptedIOException Classe java.net.MalformedURLException Classe java.net.ProtocolException Classe java.net.SocketException Classe java.io.UTFDataFormatException Classe java.net.UnknownHostException Classe java.net.UnknownServiceException

Classe java.lang.RuntimeException Classe java.lang.ArithmeticException Classe java.lang.ArrayStoreException Classe java.lang.ClassCastException Classe java.util.EmptyStackException Classe java.lang.IllegalArgumentException

Classe java.lang.IllegalThreadStateException Classe java.lang.NumberFormatException

Classe java.lang.IllegalMonitorStateException Classe java.lang.IndexOutOfBoundsException

Classe java.lang.ArrayIndexOutOfBoundsException Classe java.lang.StringIndexOutOfBoundsException

Classe java.lang.NegativeArraySizeException Classe java.util.NoSuchElementException Classe java.lang.NullPointerException Classe java.lang.SecurityException

Classe java.awt.Toolkit Classe java.net.URL Classe java.net.URLConnection Classe java.net.URLEncoder Classe java.net.URLStreamHandler Interface java.net.URLStreamHandlerFactory Classe java.util.Vector (implémente java.lang.Cloneable)

Classe java.util.Stack

(Les classes du package java.awt.peer ne sont pas citées)

Page 122: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 1

Les classes de bases

Les classes de gestion des objetsLes classes d'emballage

Calcul mathématique : la classe java.lang.MathLes classes de gestion des threadsLes classes de gestion du système

Ce chapitre décrit le package java.lang de Java 1.0 qui rassemble les classes de base de Java.Les principales classes de ce package ayant déjà été étudiées (Class, Object, String, StringBuffer,System, Thread, Throwable et ses dérivées), voici la description des autres classes et interfaces fourniespar ce package.

Rappel : Toutes les classes et interfaces de java.lang sont automatiquement importées par lecompilateur.

Gestion des objets

La classe java.lang.Object

Cette classe est à la racine de la hiérarchie des classes Java, donc toute classe hérite implicitement de laclasse Object. Elle est détaillée au chapitre sur les objets.

L'interface java.lang.Cloneable

Cette interface ne déclare ni constantes, ni méthodes. Elle doit être implémentée par toute classe quiveut outrepasser et utiliser la méthode clone () de la classe Object, qui permet de créer une copie d'unobjet.

La classe java.lang.Class

Cette classe final permet de représenter chacune des classes chargées par la Machine Virtuelle Java.Elle est détaillée au chapitre sur les objets.

La classe java.lang.ClassLoader

La création d'une classe dérivée de cette classe abstract permet de créer un chargeur de classespécifique.Par défaut, chaque classe est chargée dynamiquement à sa première utilisation à partir du fichier .class demême nom que la classe qui provient de la machine locale ou à travers un réseau. Mais vous pouvezcharger vous-même une ou plusieurs classes pour qu'elles existent et soient utilisables dans la MachineVirtuelle Java.Ceci permet par exemple de protéger l'ensemble des fichiers .class d'une application, pour éviter qu'ilsoit repris par d'autres personnes. Il suffit de coder ces fichiers et de créer une classe de chargeur declasses capable de les décoder. Au chargement d'une classe, les fichiers seront décodés puis transmis àla Machine Virtuelle Java.

Constructeur

protected ClassLoader () throws SecurityException

Méthodes

Page 123: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 2

protected abstract Class loadClass (String name, boolean resolve) throws ClassNotFoundException

Cette méthode doit être outrepassée pour charger et renvoyer la classe de nom name. Si resolve est égalà true, les classes qu'utilise cette classe doivent être résolues. Si la classe n'est pas trouvée uneexception de classe ClassNotFoundException doit être déclenchée.Les trois autres méthodes sont final et protected et sont des outils utilisés pour créer ou préparer lesclasses.

protected final Class defineClass (byte data [ ], int offset, int length) throws IndexOutOfBoundsException, ClassFormatError

Permet de créer une instance de la classe Class à partir des length octets du tableau data pris à partir del'indice offset. Si cet ensemble d'octets ne représente pas une classe Java valide, une exceptionClassFormatError est déclenchée.

protected final void resolveClass (Class c)

Permet de résoudre et charger les classes qu'utilise la classe c. Cette opération doit être effectuée avantd'utiliser la classe c et entraîne que la méthode loadClass () sera appelée pour chacune des classes queréférencent les variables de la classe c.

protected final Class findSystemClass (String name) throws ClassNotFoundException

Charge la classe de nom name avec le chargeur de classe par défaut.

Le constructeur de la classe ClassLoader peut éventuellement déclencher une exception de classeSecurityException, si le gestionnaire de sécurité interdit de créer d'autres chargeurs de classes, commele font par exemple les navigateurs. Donc, si vous créez des applets pour Internet vous ne pourrez paschanger le chargeur de classe par défaut.

La classe java.lang.Compiler

Cette classe final fournit un ensemble de méthodes relatives à la compilation des classes Java en codemachine du système sur lequel fonctionne la Machine Virtuelle Java.

Méthodes

public static Object command (Object any)public static boolean compileClass (Class class)public static boolean compileClasses (String string)public static void disable ()public static void enable ()

La classe java.lang.Throwable

Cette classe est à la racine de toutes les classes d'exceptions. Throwable et toutes ses classes dérivéessont détaillées au chapitre traitant des exceptions.

Les classes d'emballage

La bibliothèque Java fournit un ensemble de classes qui permettent de manipuler les types de base sousforme d'objets, comme par exemple la classe Boolean pour le type boolean. Chacune de ces classes nemémorisant qu'une variable du type de base donné associé, on appelle ce type de classe une classed'emballage (wrapper en anglais).Ces classes peuvent être utile pour les classes ne manipulant que des objets, comme par exemple laclasse java.util.Vector, qui permet de créer un ensemble d'objets quelconques.Une classe d'emballage existant pour tous les types de base (sauf pour les types byte, short et void sousJava 1.0), il est donc possible de programmer du "pur objet" en Java, où toutes les variables ne seraientque des objets et uniquement cela.

Page 124: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 3

Les classes d'emballage de Java ne permettent pas de modifier la valeur qu'elles mémorisent.

La classe java.lang.Boolean

Cette classe final est la classe d'emballage qui correspond au type boolean.

Variables

public final static Boolean TRUEpublic final static Boolean FALSE

TRUE et FALSE sont deux constantes qui correspondent aux valeurs true et false du type boolean.

Constructeurs

public Boolean (boolean value)public Boolean (String s)

Ces constructeurs permettent de créer une instance de la classe Boolean à partir de la valeur booléenevalue ou de la chaîne de caractères s.

Méthodes

public boolean booleanValue ()

Renvoie la valeur booléenne mémorisée.

public static Boolean valueOf (String s)

Renvoie une instance de la classe Boolean à partir de la chaîne de caractères s. s est considérée égale àtrue si et seulement si elle est égale à "true" en minuscules ou en majuscules.

public static boolean getBoolean (String s)

Renvoie true ou false si la propriété name du système est égale à "true". Si cette propriété n'existe pas,cette méthode renvoie false.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet booléen à un objet ou renvoyer une chaîne de caractères décrivant la valeur booléenne.

La classe java.lang.Character

Cette classe final est la classe d'emballage qui correspond au type char. Elle déclare un grand nombrede méthodes static permettant de reconnaître le type de lettres (majuscule, minuscule, chiffre,...) etd'effectuer des conversions.

Variables

public final static int MIN_RADIXpublic final static int MAX_RADIX

Ces constantes sont les bases de conversion minimum (= 2) et maximum (= 36) des nombres entiers.

public final static char MIN_VALUEpublic final static char MAX_VALUE

Valeurs minimum ('\u0000') et maximum ('\ffff') d'un caractère Unicode.

Constructeur

public Character (char value)

Page 125: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 4

Construit une instance de la classe Character à partir du caractère value.

Méthodes

public char charValue ()

Renvoie le caractère mémorisé.

public static boolean isLowerCase (char ch)public static boolean isUpperCase (char ch)public static boolean isTitleCase (char ch)

Ces méthodes renvoient true si le caractère ch est une minuscule, une majuscule ou une lettre de titre.

public static boolean isDefined (char ch)

Ces méthodes renvoient true si le caractère ch est défini dans l'ensemble des caractères Unicode.

public static boolean isDigit (char ch)

Renvoie true si le caractère ch est un chiffre.

public static boolean isLetter (char ch)

Renvoie true si le caractère ch est une lettre.

public static boolean isLetterOrDigit (char ch)

Renvoie true si le caractère ch est un chiffre ou une lettre.

public static boolean isJavaLetter (char ch)

Renvoie true si le caractère ch est une lettre Java, c'est-à-dire qu'elle est permise comme première lettred'un identifiant Java.

public static boolean isJavaLetterOrDigit (char ch)

Renvoie true si le caractère ch est une lettre ou un chiffre Java, c'est-à-dire qu'elle est permise commelettre d'un identifiant Java différente de la première.

public static boolean isSpace (char ch)

Renvoie true si le caractère ch est un espace c'est-à-dire un des caractères ' ', '\t', '\f', '\n' ou '\r'.

public static char toLowerCase (char ch)public static char toUpperCase (char ch)public static char toTitleCase (char ch)

Ces méthodes renvoient le caractère ch converti en minuscule, en majuscule ou en lettre de titre.

public static int digit (char ch, int radix)

Renvoie le nombre correspondant au caractère ch en base radix ou -1 si le caractère ch est incorrect enbase radix.

public static char forDigit (int digit, int radix)

Renvoie le caractère correspondant au nombre digit en base radix, ou le caractère '\0' si le nombreest négatif ou plus grand que la base radix.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet caractère à un objet ou renvoyer une chaîne de caractères avec le caractère mémorisé.

Page 126: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 5

Exemples

Applet Unicode .Classe ToUpperCaseInputStream.

La classe java.lang.Number

Cette classe abstract est la super classe des classes d'emballage Integer, Long, Float et Double quipermettent de traiter des nombres de type int, long, float et double sous forme d'objets.

Constructeur

public Number ()

Méthodes

public abstract int intValue ()public abstract long longValue ()public abstract float floatValue ()public abstract double doubleValue ()

Ces méthodes doivent renvoyer le nombre mémorisé dans l'un des types de base int, long, float oudouble.

La classe java.lang.Integer

Cette classe final qui dérive de la classe Number est la classe d'emballage qui correspond au type int.

Variables

public final static int MIN_VALUEpublic final static int MAX_VALUE

Valeurs minimum (-2147483648) et maximum (21474836487) d'un entier de type int.

Constructeurs

public Integer (int value)public Integer (String s) throws NumberFormatException

Ces constructeurs permettent de créer une instance de la classe Integer à partir de la valeur entièrevalue ou du nombre contenu dans la chaîne de caractères s.

Méthodes

public int intValue ()public long longValue ()public float floatValue ()public double doubleValue ()

Implémentation des méthodes de la classe Number.

public static String toString (int i, int radix)

Renvoie la chaîne de caractères correspondant au nombre i en base radix.

public static String toHexString (int i)public static String toOctalString (int i)public static String toBinaryString (int i)public static String toString (int i)

Renvoie la chaîne de caractères correspondant au nombre i en base 16 (hexadécimal), en base 8 (octal),en base 2 (binaire) ou en base 10 (décimal).

public static int parseInt (String s, int radix) throws NumberFormatExceptionpublic static int parseInt (String s) throws NumberFormatException

Page 127: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 6

Ces méthodes renvoient le nombre contenu dans la chaîne de caractères s en base radix (radix = 10par défaut). Si s contient des caractères invalides ou si le nombre contenu dans s est plus grand queMAX_VALUE ou plus petit que MIN_VALUE, une exception NumberFormatException est déclenchée.

public static Integer valueOf (String s, int radix) throws NumberFormatExceptionpublic static Integer valueOf (String s) throws NumberFormatException

Ces méthodes renvoient une instance de la classe Integer mémorisant le nombre contenu dans la chaînede caractères s en base radix (radix = 10 par défaut).

public static Integer getInteger (String name)public static Integer getInteger (String name, int val)public static Integer getInteger (String name, Integer val)

Ces méthodes renvoient la propriété name du système. Si cette propriété n'existe pas ou n'est pas unentier, la valeur val (ou par défaut null) est renvoyée.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet entier à un objet ou renvoyer une chaîne de caractères décrivant la valeur entière.

Exemples

Applets PaperBoardClient , Unicode et ListePolices .Application LectureFichier .

La classe java.lang.Long

Cette classe final qui dérive de la classe Number est la classe d'emballage qui correspond au type long.

Variables

public final static int MIN_VALUEpublic final static int MAX_VALUE

Valeurs minimum (-9223372036854775808) et maximum (9223372036854775807) d'un entier de type long.

Constructeurs

public Long (long value)public Long (String s) throws NumberFormatException

Ces constructeurs permettent de créer une instance de la classe Long à partir de la valeur entière valueou du nombre contenu dans la chaîne de caractères s.

Méthodes

public int intValue ()public long longValue ()public float floatValue ()public double doubleValue ()

Implémentation des méthodes de la classe Number.

public static String toString (long i, int radix)

Renvoie la chaîne de caractères correspondant au nombre i en base radix.

public static String toHexString (long i)public static String toOctalString (long i)public static String toBinaryString (long i)public static String toString (long i)

Page 128: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 7

Renvoie la chaîne de caractères correspondant au nombre i en base 16 (hexadécimal), en base 8 (octal),en base 2 (binaire) ou en base 10 (décimal).

public static long parseLong (String s, int radix) throws NumberFormatExceptionpublic static long parseLong (String s) throws NumberFormatException

Ces méthodes renvoient le nombre contenu dans la chaîne de caractères s en base radix (radix = 10par défaut). Si s contient des caractères invalides une exception NumberFormatException est déclenchée.

public static Long valueOf (String s, int radix) throws NumberFormatExceptionpublic static Long valueOf (String s) throws NumberFormatException

Ces méthodes renvoient une instance de la classe Long mémorisant le nombre contenu dans la chaîne decaractères s en base radix (radix = 10 par défaut).

public static Long getLong (String name)public static Long getLong (String name, long val)public static Long getLong (String name, Long val)

Ces méthodes renvoient la propriété name du système. Si cette propriété n'existe pas ou n'est pas unentier, la valeur val (ou par défaut null) est renvoyée.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet entier à un objet ou renvoyer une chaîne de caractères décrivant la valeur entière.

La classe java.lang.Float

Cette classe final qui dérive de la classe Number est la classe d'emballage qui correspond au type float.

Variables

public final static float POSITIVE_INFINITYpublic final static float NEGATIVE_INFINITYpublic final static float NaN

Ces constantes permettent d'obtenir les valeurs correspondantes à l'infini positif, négatif ou représentantune valeur non significative.

public final static double MAX_VALUEpublic final static double MIN_VALUE

Valeurs minimum (1.40129846432481707e-45f) et maximum (3.40282346638528860e+38f) d'un nombreflottant de type float.

Constructeurs

public Float (float value)public Float (double value)public Float (String s) throws NumberFormatException

Ces constructeurs permettent de créer une instance de la classe Float à partir de la valeur flottantevalue ou du nombre contenu dans la chaîne de caractères s.

Méthodes

public int intValue ()public long longValue ()public float floatValue ()public double doubleValue ()

Implémentation des méthodes de la classe Number.

public boolean isInfinite ()

Page 129: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 8

public boolean isNaN ()

Ces méthodes renvoie true si le nombre mémorisé est infini ou si c'est une valeur non significative.

public static boolean isInfinite (float v)public static boolean isNaN (float v)

Ces méthodes renvoie true si v est une valeur infinie ou si c'est une valeur non significative.

public static String toString (float f)

Renvoie la chaîne de caractères correspondant au nombre f.

public static Float valueOf (String s) throws NumberFormatException

Renvoie une instance de la classe Float mémorisant le nombre contenu dans la chaîne de caractères s. Sis contient des caractères invalides une exception NumberFormatException est déclenchée.

public static int floatToIntBits (float value)public static float intBitsToFloat (int bits)

Ces méthodes convertissent la valeur value en son équivalent en int, ou inversement la valeur bits detype int en float. Elles sont utilisées par les méthodes writeFloat () et readFloat () de certaines desclasses d'entrée-sortie qui manipulent un nombre de type float sous forme de valeur 32 bits.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet de classe Float à un objet ou renvoyer une chaîne de caractères décrivant la valeur flottante.

Exemple

Applet CalculetteSimple .

La classe java.lang.Double

Cette classe final qui dérive de la classe Number est la classe d'emballage qui correspond au typedouble.

Variables

public final static double POSITIVE_INFINITYpublic final static double NEGATIVE_INFINITYpublic final static double NaN

Ces constantes permettent d'obtenir les valeurs correspondantes à l'infini positif, négatif ou représentantune valeur non significative (par exemple, Math.sqrt (-1) renvoie Double.NaN).

public final static double MAX_VALUEpublic final static double MIN_VALUE

Valeurs minimum (2.2250738585072014e-308) et maximum (1.79769313486231570e+308) d'un nombreflottant de type double.

Constructeurs

public Double (double value)public Double (String s) throws NumberFormatException

Ces constructeurs permettent de créer une instance de la classe Double à partir de la valeur flottantevalue ou du nombre contenu dans la chaîne de caractères s.

Méthodes

Page 130: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 9

public int intValue ()public long longValue ()public float floatValue ()public double doubleValue ()

Implémentation des méthodes de la classe Number.

public boolean isInfinite ()public boolean isNaN ()

Ces méthodes renvoie true si le nombre mémorisé est infini ou si c'est une valeur non significative.

public static boolean isInfinite (double v)public static boolean isNaN (double v)

Ces méthodes renvoie true si v est une valeur infinie ou si c'est une valeur non significative.

public static String toString (double d)

Renvoie la chaîne de caractères correspondant au nombre d.

public static Double valueOf (String s) throws NumberFormatException

Renvoie une instance de la classe Double mémorisant le nombre contenu dans la chaîne de caractères s.Si s contient des caractères invalides une exception NumberFormatException est déclenchée.

public static long doubleToLongBits (double value)public static double longBitsToDouble (long bits)

Ces méthodes convertissent la valeur value en son équivalent en long, ou inversement la valeur bits detype long en double. Elles sont utilisées par les méthodes writeDouble () et readDouble () de certainesdes classes d'entrée-sortie qui manipulent un nombre de type double sous forme de valeur 64 bits.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet de classe Double à un objet ou renvoyer une chaîne de caractères décrivant la valeur flottante.

Exemple

Application TestExpression .

La classe java.lang.String

Cette classe final permet de manipuler les chaînes de caractères constantes. Elle est détaillée auchapitre sur les chaînes de caractères.

La classe java.lang.StringBuffer

Cette classe permet de manipuler et modifier des chaînes de caractères. Elle est détaillée au chapitre surles chaînes de caractères.

Calcul mathématique : la classe java.lang.Math

Cette classe final rassemble l'ensemble des méthodes de calcul mathématique Java. Toutes sesméthodes sont static.

Variables

public final static double Epublic final static double PI

Ces variables permettent d'obtenir les nombres e (= 2.71828...) et Pi (π = 3.14159...).

Page 131: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 10

Méthodes

public static double sin (double a)public static double cos (double a)public static double tan (double a)

Ces méthodes permettent de calculer le sinus, le cosinus du nombre a exprimé en radian.

public static double asin (double a)

Renvoie l'arc sinus (sin-1) du nombre a, exprimé en radian et compris entre -PI/2 et PI/2.

public static double acos (double a)

Renvoie l'arc cosinus (cos-1) du nombre a, exprimé en radian et compris entre 0 et PI.

public static double atan (double a)

Renvoie l'arc tangente (tan-1) du nombre a, exprimé en radian et compris entre -PI/2 et PI/2.

public static double atan2 (double a, double b)

Renvoie l'arc tangente (tan-1) de b/a, exprimé en radian et compris entre -PI et PI.

public static double exp (double a)public static double log (double a)

Ces méthodes permettent de calculer l'exponentielle ou le logarithme népérien du nombre a.

public static double IEEEremainder (double f1, double f2)

Renvoie le reste de la division de f1 par f2 (par exemple Math.IEEEremainder (4.5, 2) = 0.5,Math.IEEEremainder (4.5, 2.2) = 0.1) .

public static double floor (double a)

Renvoie la plus grande valeur entière plus petite ou égale à a.

public static double ceil (double a)

Renvoie la plus petite valeur entière plus grande ou égale à a.

public static double sqrt (double a)

Renvoie la racine carrée du nombre a.

public static double pow (double a, double b)

Renvoie le nombre a à la puissance b (ab).

public static double rint (double a)public static int round (float a)public static long round (double a)

Ces méthodes renvoient la valeur arrondie au plus proche entier du nombre décimal a.

public static synchronized double random ()

Renvoie un nombre aléatoire compris entre 0. inclus et 1. exclu. Voir aussi la classe java.util.Random.

public static int abs (int a)public static long abs (long a)public static float abs (float a)public static double abs (double a)

Ces méthodes renvoient la valeur absolue du nombre a.

Page 132: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 11

public static int max (int a, int b)public static long max (long a, long b)public static float max (float a, float b)public static double max (double a, double b)public static int min (int a, int b)public static long min (long a, long b)public static float min (float a, float b)public static double min (double a, double b)

Ces méthodes renvoient la valeur maximum ou minimum des nombres a et b.

Les méthodes log (), sqrt (), pow (),... auxquelles sont envoyés des arguments interdits enmathématique (comme le logarithme népérien d'un nombre négatif) renvoie la valeur non significativeDouble.NaN sans déclencher d'exception.

Exemples

Applets AfficheurDeCalcul , ObservateurCalcul, DrawIt , ImageNoirEtBlanc , Compteur et Horloge .

Gestion des threads

L'interface java.lang.Runnable

Cette interface déclare uniquement la méthode run () :

public void run ()

Toute classe Classe1 peut implémenter l'interface Runnable, et implémenter une méthode run () quisera exécutée par les threads créés à partir de la classe Classe1.

Exemples

Application PaperBoardServer .Applets Chrono , AfficheurDeCalcul , ObservateurCalcul , PaperBoardClient , AnimationFleche , ScrollText etHorloge .

La classe java.lang.Thread

Cette classe permet de créer et de manipuler les threads. Elle est détaillée au chapitre sur les threads.

La classe java.lang.ThreadGroup

Cette classe permet de consulter ou créer des groupes de threads, pour rassembler vos threads parexemple par type. Voir aussi la classe Thread.

Constructeurs

public ThreadGroup (String name) throws SecurityExceptionpublic ThreadGroup (ThreadGroup parent, String name) throws SecurityException, IllegalThreadStateException

Méthodes

public String toString ()public final void checkAccess ()public final String getName ()public final ThreadGroup getParent ()public final boolean parentOf (ThreadGroup g)public final synchronized void stop () throws SecurityExceptionpublic final synchronized void suspend () throws SecurityExceptionpublic final synchronized void resume () throws SecurityExceptionpublic final synchronized void destroy () throws SecurityException, IllegalThreadStateExceptionpublic final int getMaxPriority ()public final synchronized void setMaxPriority (int newMaxPriority) throws SecurityException, IllegalArgumentException

Page 133: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 12

public final boolean isDaemon ()public final void setDaemon (boolean daemon) throws SecurityExceptionpublic synchronized int activeCount ()public synchronized int activeGroupCount ()public int enumerate (Thread list [ ])public int enumerate (Thread list [ ], boolean recurse)public int enumerate (ThreadGroup list [ ])public int enumerate (ThreadGroup list [ ], boolean recurse)public synchronized void list ()public void uncaughtException (Thread t, Throwable e)

Gestion du système

La classe java.lang.System

Cette classe final permet d'accéder à différentes fonctionnalités du système de la Machine VirtuelleJava. Elle est détaillée au chapitre sur les objets.

La classe java.lang.Runtime

Cette classe permet de manipuler le Runtime Java, renvoyé par la méthode getRuntime (). Les méthodesexit (), exec (), load () et loadLibrary () sont susceptibles de déclencher une exceptionSecurityException si le gestionnaire de sécurité interdit ces opérations.

Méthodes

public static Runtime getRuntime ()

Renvoie le Runtime Java.

public synchronized void load (String filename) throws SecurityException, UnsatisfiedLinkErrorpublic synchronized void loadLibrary (String libname) throws SecurityException, UnsatisfiedLinkErrorpublic void exit (int status) throws SecurityExceptionpublic void gc ()public void runFinalization ()

Ces méthodes ont le même effet que celles que de la classe java.lang.System.

public Process exec (String command) throws IOException, SecurityExceptionpublic Process exec (String command, String envp [ ]) throws IOException, SecurityExceptionpublic Process exec (String cmdarray [ ]) throws IOException, SecurityExceptionpublic Process exec (String cmdarray [ ], String envp [ ]) throws IOException, SecurityException

Ces méthodes permettent d'exécuter la commande du système command ou cmdarray [0]. envp [] est untableau contenant les paramètres à passer à la commande au format param=valeur (pour passer parexemple des paramètres à java ). exec () renvoie une instance de la classe Process qui permet decontrôler la commande exécutée.

public long freeMemory ()public long totalMemory ()

Ces méthodes renvoient la taille de la mémoire libre et la taille totale de la mémoire.

public void traceInstructions (boolean on)public void traceMethodCalls (boolean on)public InputStream getLocalizedInputStream (InputStream in)public OutputStream getLocalizedOutputStream (OutputStream out)

La classe java.lang.Process

Les objets dérivant de cette classe abstract sont retournés par les méthodes exec () de l a classe

Page 134: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les classes de bases Page: 13

Runtime. Ces méthodes permettent de contrôler l'état d'un process.

Constructeurs

public Process ()

Méthodes

public abstract OutputStream getOutputStream ()public abstract InputStream getInputStream ()public abstract InputStream getErrorStream ()

Ces méthodes renvoient les flux de sortie, d'entrée et d'erreur d'un process.

public abstract int waitFor () throws InterruptedExceptionpublic abstract void destroy ()

Ces méthodes permettent d'attendre la fin d'un process ou de le détruire.

public abstract int exitValue () throws IllegalThreadStateException

Renvoie la valeur renvoyée par le process.

La classe java.lang.SecurityManager

Une classe dérivée de cette classe abstract permet de définir un gestionnaire de sécurité dont l'instanceest passée en paramètre à la méthode setSecurityManager () de la classe System. Ce gestionnaire estutilisé par les navigateurs pour interdire aux applets en autre, l'accès au système de fichiers local.

Variables

protected boolean inCheck

Constructeurs

protected SecurityManager () throws SecurityException

Méthodes

protected Class [ ] getClassContext ()protected int classDepth (String name)protected boolean inClass (String name)protected ClassLoader currentClassLoader ()protected int classLoaderDepth ()protected boolean inClassLoader ()public boolean getInCheck ()public Object getSecurityContext ()public void checkAccept (String host, int port) throws SecurityExceptionpublic void checkAccess (Thread t) throws SecurityExceptionpublic void checkAccess (ThreadGroup g) throws SecurityExceptionpublic void checkConnect (String host, int port) throws SecurityExceptionpublic void checkConnect (String host, int port, Object context) throws SecurityExceptionpublic void checkCreateClassLoader () throws SecurityExceptionpublic void checkDelete (String file) throws SecurityExceptionpublic void checkExec (String cmd) throws SecurityExceptionpublic void checkExit (int status) throws SecurityExceptionpublic void checkLink (String libname) throws SecurityExceptionpublic void checkListen (int port) throws SecurityExceptionpublic void checkPackageAccess (String packageName) throws SecurityExceptionpublic void checkPackageDefinition (String packageName) throws SecurityExceptionpublic void checkPropertiesAccess () throws SecurityExceptionpublic void checkPropertyAccess (String key) throws SecurityExceptionpublic void checkRead (FileDescriptor fd) throws SecurityExceptionpublic void checkRead (String file) throws SecurityExceptionpublic void checkRead (String file, Object context) throws SecurityExceptionpublic void checkSetFactory () throws SecurityExceptionpublic boolean checkTopLevelWindow () throws SecurityExceptionpublic void checkWrite (FileDescriptor fd) throws SecurityExceptionpublic void checkWrite (String file) throws SecurityException

Page 135: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 1

Les outils Java

Gestion de collections de donnéesGestion des dates

Génération de nombres aléatoiresAutres classes d'outils

Gestion de collections de données

Le package java.util rassemble des classes d'utilitaires dont les plus intéressantes permettent de gérerles collections de données (classes Vector, Stack, Dictionary, Hashtable, BitSet et interfaceEnumeration).

L'interface java.util.Enumeration

Cette interface est implémentée par les classes désirant pouvoir faire une énumération des objetsmémorisés par une autre classe, comme par exemple la classe Vector. Les méthodes de cette interfacesont généralement utilisées dans une boucle while, comme dans l'exemple suivant (à recopier dans unfichier EssaiEnumeration.java que vous compilez avec l'instruction javac EssaiEnumeration.java pourensuite l'exécuter avec java ou Java Runner , grâce à l'instruction java EssaiEnumeration) :

import java.util.*; // Classe mémorisant des chaînes de caractèresclass CollectionChaines{ String [ ] tabChaines; int nbreChaines = 0; CollectionChaines (int max) { tabChaines = new String [max]; } public void ajouterChaine (String chaine) { tabChaines [nbreChaines++] = chaine; } public Enumeration chaînes () { return new EnumerationChaines (this); }} // Classe permettant d'énumérer les chaînes de CollectionChainesclass EnumerationChaines implements Enumeration{ CollectionChaines collection; int indice = 0; public EnumerationChaines (CollectionChaines collection) { this.collection = collection; } public boolean hasMoreElements () { return indice < collection.nbreChaines; } public Object nextElement () { if (indice < collection.nbreChaines)

Page 136: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 2

return collection.tabChaines [indice++]; else throw new NoSuchElementException (); }} // Classe d'essaipublic class EssaiEnumeration{ public static void main (String [ ] args) { // Création d'une collection de chaînes et ajout de 3 chaînes CollectionChaines donnees = new CollectionChaines (10); donnees.ajouterChaine ("Toto"); donnees.ajouterChaine ("Titi"); donnees.ajouterChaine ("Tutu"); // Enumération des éléments de la collection Enumeration enum = donnees.chaînes (); while (enum.hasMoreElements ()) System.out.println (enum.nextElement ()); }}

Méthodes

public boolean hasMoreElements ()

Cette méthode doit renvoyer true s'il reste encore un ou plusieurs éléments à énumérer.

public Object nextElement () throws NoSuchElementException

Cette méthode doit retourner l'élément suivant à énumérer ou déclencher une exception de classeNoSuchElementException si le dernier élément a déjà été énuméré.

La classe java.util.Vector

Cette classe qui implémente l'interface Cloneable, permet de créer un vecteur. Ce type d'ensemblepermet de mémoriser un ensemble d'objets de classe quelconque dans un tableau de taille variable (ceséléments peuvent être éventuellement égal à null). Comme pour les tableaux, l'accès aux éléments sefait par un indice. La classe Vector comporte de nombreuses méthodes qui permettent d'ajouter,d'insérer, de supprimer ou de rechercher des éléments. Toutes les méthodes de Vector sont final saufclone ().

Variables

protected Object [ ] elementDataprotected int elementCountprotected int capacityIncrement

Ces variables correspondent aux éléments mémorisés, au nombre d'éléments mémorisés et à l'incrémentà appliquer au tableau elementData quand il est rempli. Ces classes étant protected ne sont accessiblesque dans les classes dérivées de Vector.

Constructeurs

public Vector ()public Vector (int initialCapacity)public Vector (int initialCapacity, int capacityIncrement)

Ces constructeurs permettent de créer un vecteur de capacité initiale initialCapacity (égal à 10 pardéfaut) et d'incrément capacityIncrement (égal à 0 par défaut). Si l'incrément est nul, la taille du tableaumémorisant les éléments du vecteur sera doublée à chaque fois que ce tableau a besoin d'être agrandi.

Méthodes

public final synchronized void addElement (Object obj)

Ajoute l'élément obj en fin de vecteur. Si le tableau du vecteur est trop petit, il est automatiquement

Page 137: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 3

agrandi.

public final synchronized void insertElementAt (Object obj, int index) throws IndexOutOfBoundsException

Insère l'élément obj à l'indice index. Si le tableau du vecteur est trop petit, il est automatiquementagrandi.

public final synchronized Object elementAt (int index) throws IndexOutOfBoundsExceptionpublic final synchronized void setElementAt (Object obj, int index) throws IndexOutOfBoundsException

Ces méthodes permettent d'interroger ou de modifier l'élément mémorisé à l'indice index. Si index estplus grand que le nombre d'éléments du vecteur, une exception IndexOutOfBoundsException estdéclenchée.

public final synchronized boolean removeElement (Object obj)public final synchronized void removeElementAt (int index) throws IndexOutOfBoundsExceptionpublic final synchronized void removeAllElements ()

Ces méthodes permettent de retirer du vecteur, soit l'élément obj, soit l'élément mémorisé à l'indiceindex, soit tous les éléments mémorisés. Les deux premières méthodes décalent les éléments qui suiventl'élément retiré du tableau du vecteur à un indice inférieur.

public final boolean isEmpty ()

Renvoie true si le vecteur est vide.

public final int size ()

Renvoie le nombre d'éléments mémorisés dans le vecteur.

public final synchronized void setSize (int newSize)

Modifie la taille du vecteur. Si newSize est plus petit que le nombre d'éléments courant du vecteur, lesderniers éléments sont perdus, sinon un ensemble d'éléments égaux à null sont ajoutés pour atteindre lataille newSize.

public final int capacity ()public final synchronized void ensureCapacity (int minCapacity)

Ces méthodes permettent d'interroger ou de modifier la capacité courante du vecteur. La capacité duvecteur est le nombre maximum que son tableau peut contenir avant que celui-ci est besoin d'êtreagrandi.

public final synchronized void trimToSize ()

Réduit la capacité du tableau du vecteur aux nombres d'éléments mémorisés par le vecteur.

public final synchronized Object firstElement () throws NoSuchElementExceptionpublic final synchronized Object lastElement () throws NoSuchElementException

Ces méthodes renvoient le premier ou le dernier élément mémorisé par le vecteur.

public final synchronized void copyInto (Object array [ ]) throws IndexOutOfBoundsException

Recopie dans le tableau array l'ensemble des éléments mémorisés par le vecteur. Si array est top petit,une exception IndexOutOfBoundsException est déclenchée.

public final synchronized Enumeration elements ()

Permet d'énumérer les éléments du vecteur.

Page 138: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 4

public final boolean contains (Object elem)

Renvoie true si le vecteur contient un élément égal à elem. La méthode equals () de la classe de l'objetelem est utilisée pour comparer les objets.

public final int indexOf (Object elem)public final synchronized int indexOf (Object elem, int index) throws IndexOutOfBoundsExceptionpublic final int lastIndexOf (Object elem)public final synchronized int lastIndexOf (Object elem, int index) throws IndexOutOfBoundsException

Ces méthodes renvoient l'indice du premier ou du dernier élément égal à elem, ou -1 si elem n'est pastrouvé. La méthode equals () de la classe de l'objet elem est utilisée pour comparer les objets. indexpermet d'éventuellement spécifier le premier indice à partir duquel commencer la recherche.

public synchronized Object clone ()

Renvoie un clone du vecteur. Les éléments du vecteur ne sont pas clonés eux-mêmes. Cette méthodeoutrepasse la méthode clone () de la classe Object.

public final synchronized String toString ()

Cette méthode outrepasse la méthode toString () de la classe Object, pour renvoyer une chaîne decaractères décrivant la liste des éléments mémorisés par le vecteur.

Exemples

Application ConcatenationFichiers .Applet PaperBoardClient .

La classe java.util.Stack

Cette classe qui dérive de Vector permet de créer des piles, où vous pouvez empiler un objet avec laméthode push (), retirer l'élément en haut de la pile avec pop (), ou consulter sans le retirer l'élémenten haut de la pile avec peek ().

Méthodes

public Object push (Object item)public Object pop () throws EmptyStackExceptionpublic Object peek () throws EmptyStackExceptionpublic boolean empty ()public int search (Object o)

La classe java.util.Dictionary

Cette classe abstract permet de créer un dictionnaire représenté par un ensemble d'entrées associant unélément et une clé. Chaque clé du dictionnaire est unique et est associé au plus à un élément, mais unmême élément peut avoir plusieurs clés d'accès. Les éléments et les clés devant être de la classe Object,le cast de références permet donc d'utiliser n'importe quel type de classe pour les clés et les éléments(chaînes de caractères, classes d'emballage des nombres ou d'autres classes).Un dictionnaire peut être comparé à un tableau : Dans un tableau tab, vous mémorisez un ensembled'éléments accessible grâce à un indice entier i, par l'expression tab [i]. Il est possible de mémoriserplusieurs fois le même objet dans tab à des indices différents, mais par contre chaque indice i est uniqueet vous permet d'accéder aux différents éléments du tableau grâce à tab [i]. Dans un dictionnaire dict,vous mémorisez de la même manière des éléments auquel vous accédez grâce à une clé plutôt que parun indice entier. Cette clé peut être de n'importe quelle classe, ce qui permet de mémoriser les élémentsd'une manière plus riche qu'avec un simple indice entier. Pour faire un parallèle entre l'utilisation d'untableau tab et d'un dictionnaire dict, l'expression tab [i] = element a pour équivalent dict.put (cle,element) et l'expression element = tab [i] a pour équivalent element = dict.get (cle).Voici toutes les méthodes que doit implémenter une classe dérivant de Dictionary, pour pouvoir être

Page 139: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 5

instanciée (comme la classe Hashtable) :

Constructeur

public Dictionary ()

Méthodes

abstract public int size ()

size () doit renvoyer le nombre d'entrées dans le dictionnaire. Chaque clé devant être unique cenombre est égal au nombre de clés.

abstract public boolean isEmpty ()

isEmpty () renvoie true si le dictionnaire ne contient aucune entrée.

abstract public Object get (Object key)

Cette méthode doit renvoyer l'élément associé à la clé key, ou null si la clé key n'existe pas.

abstract public Object put (Object key, Object element)

Cette méthode doit ajouter dans le dictionnaire une entrée associant la clé key avec l'élément element. Siune entrée avec une clé égale à key existe déjà (par la méthode equals ()), l'élément de cette entrée estrenvoyé par put () après avoir été remplacé par element. Sinon put () renvoie null, après avoir ajoutéune nouvelle entrée.

abstract public Object remove (Object key)

Cette méthode doit supprimer du dictionnaire l'entrée ayant comme clé key. Si une entrée avec une cléégale à key existe déjà (par la méthode equals ()), l'élément de cette entrée est renvoyé par remove ()après que cette entrée ait été supprimée. Sinon, remove () renvoie null.

abstract public Enumeration keys ()abstract public Enumeration elements ()

Ces méthodes doivent renvoyer un objet d'une classe implémentant Enumeration permettant d'énumérerles clés et les éléments du dictionnaire respectivement.

La classe java.util.Hashtable

Cette classe implémente l'interface Cloneable et dérive de la classe Dictionary dont elle implémentetoutes les méthodes, en y ajoutant certaines méthodes. Les tables de hash utilise la valeur que retournela méthode hashCode () des clés, pour organiser le rangement des entrées de la table afin que get ()fonctionne avec efficacité. Les objets utilisés comme clés dans une table de hash devraient avoir leurclasse qui outrepassent les méthodes equals () et hashCode () pour un fonctionnement correct (voir laclasse Object).

Constructeurs

public Hashtable (int initialCapacity, float loadFactor)

Crée une table de hash avec une capacité initiale de initialCapacity entrées. La table est réorganiséeavec la méthode rehash (), à chaque fois que le nombre d'entrées atteint loadFactor multiplié par lacapacité de la table (0 < loadFactor < 1) . Plus loadFactor est petit, plus souvent la table seraréorganisée, mais attention cette opération prend du temps ! Si c'est possible, Il vaut mieux prévoir unetable de hash avec une capacité initiale proche du nombre d'éléments à mémoriser dans la table, pouréviter que la table ait trop souvent à se réorganiser.

public Hashtable (int initialCapacity)public Hashtable ()

Méthodes

Page 140: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 6

public int size ()public boolean isEmpty ()public synchronized Object get (Object key)public synchronized Object put (Object key, Object element)public synchronized Object remove (Object key)public synchronized Enumeration keys ()public synchronized Enumeration elements ()

Ces méthodes outrepassent celles de la classe Dictionary. Pour plus d'informations, consultez la classeDictionary.

public synchronized boolean contains (Object element)public synchronized boolean containsKey (Object key)

Ces méthodes renvoient true si respectivement un élément ou une clé existe dans la table.

public synchronized void clear ()

clear () supprime toutes les entrées (clés et éléments) de la table.

protected void rehash ()

Cette méthode agrandit et réorganise la table pour plus d'efficacité.

public synchronized Object clone ()

Renvoie un clone de la table de hash. Cette méthode outrepasse la méthode clone () de la classeObject.

public synchronized final String toString ()

Cette méthode outrepasse la méthode toString () de la classe Object, pour renvoyer une chaîne decaractères décrivant l'ensemble des entrées (clé + élément) de la table.

La classe java.util.Properties

Cette classe dérivant de Hashtable désigne une table de hash ne pouvant mémoriser que des chaînes decaractères et comportant des fonctionnalités de sauvegarde/lecture dans un fichier.Cette classe ressemble un peu à la gestion des fichiers profile Windows (.INI ), et la classe Systeml'utilise pour mémoriser les propriétés associés à un programme Java.

Variable

protected Properties defaults

Constructeurs

public Properties ()public Properties (Properties defaults)

Méthodes

public String getProperty (String property)public String getProperty (String property, String defaultValue)

Ces méthodes renvoient la propriété de nom property, ou defaultValue si cette propriété n'est pasdéfinie.

public Enumeration propertyNames ()

Permet d'énumérer l'ensemble des noms de propriétés.

public void list (PrintStream out)

Ecrit sur le flux de données out la liste des propriétés et de leur valeur.

Page 141: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 7

public synchronized void load (InputStream in) throws IOExceptionpublic synchronized void save (OutputStream out, String header)

Ces méthodes permettent d'écrire ou de lire un ensemble de propriétés à patir des flux de données in ouout. Le format des données est ensemble de couples property=value.

La classe java.util.BitSet

Cette classe final qui implémente l'interface Cloneable permet de manipuler aisément un ensemble debits. Les objets de cette classe ont leur nombre de bits mémorisés qui croit automatiquement à l'appeldes méthodes set () et clear (). Les méthodes and (), or () et xor () permettent d'effectuer lesopérations ET, OU et OU Exclusif bit à bit sur les ensembles de bits des objets de cette classe.

Constructeurs

public BitSet ()public BitSet (int nbits)

Les nbits bits qu'une instance de la classe BitSet mémorise sont stockés dans un tableau dont leséléments sont de type long (64 bits).

Méthodes

public boolean get (int bitIndex)public void set (int bitIndex)public void clear (int bitIndex)public void and (BitSet set)public void or (BitSet set)public void xor (BitSet set)public int size () public boolean equals (Object obj)public int hashCode ()public Object clone ()public String toString ()

Gestion des dates

La classe java.util.Date

Cette classe permet de manipuler les dates. Les objets de cette classe représente un moment donné à laseconde près. La classe Date fournit des méthodes permettant d'obtenir ou de modifier l'année, le mois,le jour, l'heure, la minute ou la seconde d'une date et de comparer des dates.

L'année est un int égal à 0 pour l'année 1900. Le mois est un int allant de 0 pour le mois de Janvier à 11 pour le mois de décembre. Le jour du mois est un int allant de 1 à 31. L'heure est un int allant de 0 à 23. La minute est un int allant de 0 à 59. La seconde est un int allant de 0 à 59.

Les objets de la classe Date ne sont pas des horloges. A chaque fois que vous voulez obtenir le tempscourant, utilisez la méthode currentTimeMillis () de la classe System, ou créez un nouvel objet declasse Date avec le constructeur par défaut.

Constructeurs

public Date ()public Date (long time)public Date (int year, int month, int date)public Date (int year, int month, int date, int hours, int minutes)public Date (int year, int month, int date, int hours, int minutes, int seconds)public Date (String s) throws IllegalArgumentException

Page 142: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 8

Méthodes

public int getYear ()public void setYear (int year)public int getMonth ()public void setMonth (int month)public int getDate ()public void setDate (int date)public int getHours ()public void setHours (int hours)public int getMinutes ()public void setMinutes (int minutes)public int getSeconds ()public void setSeconds (int seconds)

Ces méthodes permettent d'interroger ou de modifier l'année, le mois, le jour du mois, l'heure, la minuteou la seconde d'une date.

public int getDay ()

Renvoie le jour de la semaine sachant que le nombre 0 correspond à dimanche.

public long getTime ()public void setTime (long time)

Ces méthodes permettent d'interroger ou de modifier le temps en millisecondes

public boolean before (Date when)public boolean after (Date when)

Ces méthodes renvoient true si une date est inférieure ou supérieure à la date when.

public int getTimezoneOffset ()public static long UTC (int year, int month, int date, int hours, int minutes, int seconds) public static long parse (String s) throws IllegalArgumentException

Renvoie le temps à partir d'une chaîne de caractère respectant le format IETF.

public String toLocaleString ()

Renvoie une chaîne de caractères décrivant la date courante respectant la notation locale.

public String toGMTString ()

Renvoie une chaîne de caractères décrivant la date courante respectant la notation GMT.

public boolean equals (Object obj)public int hashCode ()public String toString ()

Exemples

Applets TraitementTexte , MiseAJourHorloge et Horloge .

Génération de nombres aléatoires

La classe java.util.Random

Les méthodes de la classe Random permettent de générer des nombres aléatoires, comme la méthoderandom () de la classe java.lang.Math. Ces méthodes peuvent générer des nombres entiers, décimaux(entre 0. inclus et 1. exclus) ou respectant la courbe de Gauss (entre -1. et 1.).

Constructeurs

public Random ()public Random (long seed)

Page 143: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 9

Le second constructeur permet de créer un générateur dont on fournit la base de départ. Pour une mêmebase, la série de nombres aléatoires générées sera toujours la même à chaque exécution d'un programme.Le premier constructeur crée un générateur dont la base est égale au temps courant. Ce temps étanttoujours différent d'une exécution à l'autre, chaque série sera différente à chaque exécution.

Méthodes

public synchronized void setSeed (long seed)public int nextInt ()public long nextLong ()public float nextFloat ()public double nextDouble ()public synchronized double nextGaussian ()

Exemples

Applets ObservateurCalcul , DrawIt et ImageNoirEtBlanc .

Autres classes d'outils

La classe java.util.StringTokenizer

Cette classe permet d'énumérer à partir d'une chaîne de caractères str un ensemble de sous-chaînesséparées par des délimiteurs (voir aussi la classe java.io.StreamTokenizer).

Constructeurs

public StringTokenizer (String str, String delim, boolean returnTokens)public StringTokenizer (String str, String delim)public StringTokenizer (String str)

Permet de spécifier la chaîne str dans laquelle on recherche des sous-chaînes. Les sous-chaînes sontséparées par des délimiteurs qui peuvent être n'importe quel caractère de delim. Si returnTokens esttrue, l'énumération rendra les sous-chaînes et les délimiteurs. Par défaut, le délimiteur est un espace etreturnTokens est égal à false.

Méthodes

public boolean hasMoreElements ()public boolean hasMoreTokens ()

Ces deux méthodes renvoient vraies si la chaîne str a encore des sous-chaînes à énumérer.

public Object nextElement () throws NoSuchElementExceptionpublic String nextToken () throws NoSuchElementExceptionpublic String nextToken (String delim) throws NoSuchElementException

Ces trois méthodes renvoient la sous-chaîne suivante de str (ou le délimiteur si returnTokens est true),et avance la position de recherche dans str au caractère suivant la sous-chaîne renvoyée. La troisièmeméthode permet de remplacer les délimiteurs recherchés.

public int countTokens ()

Renvoie le nombre de sous-chaînes restant à énumérer.

L'interface java.util.Observer

Toute classe qui implémente cette interface peut instancier un observateur d'un objet observé . Cette objetobservé dont la classe est Observable ou ses dérivées, peut prévenir tous ses observateurs d'unchangement en appelant automatiquement la méthode update () de chacun d'eux. Voir la classeObservable.

Méthode

Page 144: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 10

public void update (Observable o, Object arg)

Exemple

Applet ObservateurCalcul .

La classe java.util.Observable

Cette classe permet de créer des objets observés par des observateurs , ces derniers étant des objets dont laclasse implémente l'interface Observer. Quand, à la suite d'un changement, un objet observé appelle laméthode notifyObservers (), chacun de ses observateurs voit sa méthode update () appelée.

Constructeur

public Observable ()

Méthodes

public synchronized void addObserver (Observer o)public synchronized void deleteObserver (Observer o)public synchronized void deleteObservers ()public synchronized int countObservers ()

Ces méthodes permettent d'ajouter, de supprimer ou de compter les observateurs d'un objet.

public void notifyObservers ()public synchronized void notifyObservers (Object arg)

Ces méthodes provoqueront l'appel de la méthode update () de chacun des observateurs, si l'objet aappelé setChanged () pour spécifier que l'objet a été modifié.

protected synchronized void setChanged ()protected synchronized void clearChanged ()public synchronized boolean hasChanged ()

Ces méthodes permettent de valider, d'annuler ou d'interroger un flag indiquant si l'objet a changé.

Voici un exemple illustrant l'utilisation de la classe Observable et de l'interface Observer, avec uneapplet affichant des sinusoïdes, dérivée de l'exemple du chapitre sur les threads :

et le programme Java correspondant (à copier dans un fichier dénommé ObservateurCalcul.java et invoquéà partir d'un fichier HTML) :

import java.awt.*;import java.applet.Applet;import java.util.*; public class ObservateurCalcul extends Applet implements Observer{ CalculateurObservable calculateur; public void start () { // Création d'un calculateur que l'applet observe (calculateur = new CalculateurObservable (this)).addObserver (this); } public void stop () { calculateur.stop (); } public void update (Observable calculateur, Object arg)

Page 145: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les outils Java Page: 11

{ ((CalculateurObservable)calculateur).dessinerCourbe (getGraphics ()); }} class CalculateurObservable extends Observable implements Runnable{ private int [ ] courbe; private Component fenetre; private Random generateur = new Random (); private Thread threadCalculateur; public CalculateurObservable (Component fenetre) { this.fenetre = fenetre; // Démarrage d'un thread de calcul (threadCalculateur = new Thread (this)).start (); } public void stop () { threadCalculateur.stop (); } public void calculerCourbe () { courbe = new int [fenetre.size ().width]; // Calcul d'une sinusoïde avec fréquence aléatoire double pasCalcul = 2 * Math.PI / courbe.length / Math.random (); for (int i = 0; i < courbe.length; i++) courbe [i] = (int)( (Math.sin (i * pasCalcul) + 1) * fenetre.size ().height / 2); // Nouveau calcul setChanged(); } public void dessinerCourbe (Graphics gc) { gc.setColor (Color.white); gc.fillRect (0, 0, fenetre.size ().width, fenetre.size ().height); // Création d'une couleur aléatoire gc.setColor (new Color (generateur.nextFloat (), generateur.nextFloat (), generateur.nextFloat ())); if (courbe != null) // Dessin de la courbe en reliant les points un à un for (int i = 1; i < courbe.length; i++) gc.drawLine (i - 1, courbe [i - 1], i, courbe [i]); } public void run () { try { while (threadCalculateur.isAlive ()) { // Calculer une courbe puis prévenir d'un nouveau calcul calculerCourbe (); notifyObservers (); Thread.sleep (200); } } catch (InterruptedException e) { } }}

Page 146: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 1

La gestion des fichierset des flux de données

Gestion des entrées-sortiesManipulation des fichiers

Gestion des flux de donnéesAccès à un flux de données en lectureAccès à un flux de données en écritureGestion de l'accès aléatoire aux fichiers

Ce chapitre décrit le package java.io de Java 1.0 qui rassemble les classes permettant de manipuler lesfichiers et de gérer les entrées-sorties.

Gestion des entrées-sorties

En observant la hiérarchie des classes de Java, vous serez peut-être étonné par le nombre de classesdévolues à la gestion des entrées-sorties (package java.io), et particulièrement celles de gestion des fluxde données (stream ). Ne vous inquiétez pas : une fois que vous aurez cerner le principe defonctionnement de la gestion des flux de données, vous verrez que toutes les classes dérivant desclasses InputStream et OutputStream s'utilisent de manière intuitive.

Mode d'accès aux données

Comme dans la plupart des langages informatiques, Java permet de manipuler les fichiers soit en accèspar flux de données (Stream ), soit en accès aléatoire (Random access ) :

Le mode d'accès par flux de données permet d'accéder aux données sous la forme d'un flux séquentiel.Pour faire un parallèle, imaginez un lecteur de CD sans les touches d'avance et de retour rapides >> et << :Vous pouvez accéder à un morceau de musique grâce aux touches >>| et |<< et l'écouter, mais quand lemorceau est en train d'être lu, vous ne pouvez que l'écouter de manière continu sans revenir en arrière nisauter une partie.Similairement quand vous accédez à un flux de données, une fois que vous commencez à accéder auxdonnées, vous devez traiter les données au fur et à mesure qu'elles vous sont délivrées.

Ce système permet d'accéder à toute sorte de sources de données comme : un fichier (classes FileInputStream et FileOutputStream) une chaîne de caractères (classe StringBufferInputStream) un tableau d'octets (classes ByteArrayInputStream et ByteArrayOutputStream) un pipeline (classes PipedInputStream et PipedOutputStream) l'entrée et les sorties standards (variables System.in, System.out et System.err ou FileDescriptor.in,FileDescriptor.out et FileDescriptor.err) une URL un socket.

Quel est l'intérêt d'utiliser un flux de données pour accéder à une chaîne de caractères ou à un tableaud'octets, alors qu'il sera impossible d'accéder aux données dans un ordre quelconque ?La programmation orientée objet utilisée par Java permet de manipuler les données entrantes ou sortantes avecles mêmes classes, quelque soit le type de source de données : Pour lire les données d'un flux vous utilisezles méthodes des classes InputStream, FilterInputStream ou de ses classes dérivées, et pour écrire dans unflux de données, vous utilisez les méthodes des classes OutputStream, FilterOutputStream ou de ses classesdérivées.

Page 147: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 2

Grâce à ceci, si vous créez une méthode qui effectue des traitements sur des données provenant d'un flux,elle acceptera n'importe quelle source de données, qu'elle soit en mémoire, dans un fichier ou sur Internet.

Contrairement au C où il existe des fonctions différentes suivant le type de source de données (commescanf (), fscanf (), sscanf ()), Java permet d'accéder aux différents types de flux de données par lesmêmes méthodes.

Le mode d'accès aléatoire permet d'accéder aux données dans n'importe quel ordre. Vous pouvez à toutmoment aller en avant ou en arrière pour lire ou écrire une partie des données. Ce mode d'accès estcomparable à celui utilisé pour la mémoire vive (Random Access Memory elle aussi !). Du fait que certains typesde source de données, comme les pipelines ou les URL ne peuvent supporter ce mode d'accès, son usage estplus spécifique et Java fournit uniquement la classe RandomAccessFile qui permet d'accéder à une positionquelconque dans un fichier.

En C, la différence entre les deux types d'accès par flux de données (fonctions f... () de stdio.h ) et àaccès aléatoire (open (), read (), ...) n'apparaît pas toujours de manière évidente. En effet, lesméthodes ftell () et fseek () permettent de se déplacer à une position quelconque dans un fichier,ce qui rend possible l'accès aléatoire !En Java, la différence est franche : Les classes InputStream et OutputStream et leurs classes dérivéesne permettent d'accéder que sous forme de flux de données continus (avec éventuellement un retouren arrière quand c'est possible), au contenu d'un fichier ou d'une source de donnée d'un autre type, etla classe RandomAccessFile permet d'accéder aléatoirement au contenu d'un fichier.

Gestion de l'accès aux données avec les exceptions

Les exceptions en Java permettent de programmer de manière plus simple et surtout plus maintenable uneséquence d'instructions devant effectuer des entrées/sorties. Ce type de programme effectue habituellementun grand nombre de contrôles puisqu'il faut vérifier à chaque accès à un flux de données ou un fichier si touts'est bien déroulé. Une programmation n'utilisant pas les exceptions est donc truffée de contrôles aprèschaque instruction, ce qui en réduit la lisibilité.En Java, la plupart des méthodes d'entrée/sortie déclenche une exception de classe IOException ou de sesdérivées EOFException, FileNotFoundException, InterruptedIOException ou UTFDataFormatException. Parexemple, une méthode qui va effectuer une lecture à l'intérieur d'un fichier respectera généralement le schémasuivant :

import java.io.*; class Classe1{ void lireFichier (String fichier) { try { // Suite d'instructions accédant au fichier et // ne s'occupant pas de la gestion des erreurs // Tentative d'ouvrir un fichier // Lecture dans le fichier } catch (FileNotFoundException e) { // Exception déclenchée si le fichier n'existe pas } catch (EOFException e) { // Exception déclenchée si la fin du fichier est atteinte } catch (IOException e) { // Exception déclenchée si un autre problème survient // pendant l'accès au fichier } finally { // Le bloc finally est toujours exécuté ce qui permet d'être sûr

Page 148: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 3

// que la fermeture du fichier sera effectuée try { // Fermeture du fichier si le fichier a été ouvert } catch (IOException e) { // Exception déclenchée si un problème survient pendant la fermeture } } }}

Manipulation des fichiers

Java permet de manipuler les fichiers situés sur le système local (par opposition à ceux auquel on accèdevia une URL), grâce à l'interface FilenameFilter et les classes File et FileDescriptor. On peut ajouterà cette liste la classe java.awt.FileDialog, qui permet de choisir interactivement un fichier avec uneboite de dialogue.

L'interface java.io.FilenameFilter

Cette interface est utilisée pour permettre d'accepter ou de rejeter un fichier issu d'une liste. Uneinstance d'une classe implémentant cette interface est requise par les méthodes list () de la classe Fileet setFilenameFilter () de la classe FileDialog.

Méthode

public boolean accept (File dir, String name)

Cette méthode doit renvoyer true si le fichier name se trouvant dans le répertoire dir est accepté.

La classe java.io.File

Cette classe est utilisée pour représenter un chemin d'accès au système de fichiers local et effectuer desopérations sur celui-ci (autorisation d'accès en lecture/écriture, liste des fichiers d'un répertoire,...). Cechemin d'accès peut désigner un fichier ou un répertoire.Les méthodes de cette classe peuvent éventuellement déclenchée une exception SecurityException, sile gestionnaire de sécurité actif leur interdit d'être exécutée. Les applets fonctionnant dans un navigateurempêchent généralement notamment tout accès au système de fichiers local donc n'imaginez pas uneapplet qui puisse accéder aux fichiers du système dans ce contexte.La description des chemins d'accès (séparateurs, description des disques,...) utilise les conventions dusystème sur lequel est exécutée la Machine Virtuelle.

Variables

public static final String separatorpublic static final char separatorChar

La chaîne ou le caractère utilisé comme séparateur de fichier (égal généralement à / ou \).

public static final String pathSeparatorpublic static final char pathSeparatorChar

La chaîne ou le caractère utilisé comme séparateur de plusieurs chemins d'accès (égal généralement à ;).

Constructeurs

public File (String path)

Construit une instance de la classe File, à partir d'un chemin d'accès path pouvant être absolu ou relatifau répertoire courant. path peut représenter un répertoire ou un fichier suivant l'utilisation que vousvoulez faire de cette nouvelle instance.

public File (String dir, String name)

Page 149: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 4

public File (File dir, String name)

Ces constructeurs permettent de créer une instance de la classe File, à partir d'un répertoire dir (chemind'accès absolu ou relatif au répertoire courant), et d'un nom de fichier ou de répertoire name accessible àpartir du répertoire dir.

Méthodes

public String getName ()

Renvoie le nom du fichier ou du répertoire d'un chemin d'accès.

public String getPath ()

Renvoie le chemin d'accès d'un objet de classe File.

public String getAbsolutePath ()

Renvoie le chemin d'accès absolu.

public String getParent ()

Renvoie le chemin d'accès du répertoire parent au chemin d'accès de l'objet de classe File, ou null s'iln'existe pas.

public boolean exists () throws SecurityExceptionpublic boolean isFile () throws SecurityExceptionpublic boolean isDirectory () throws SecurityExceptionpublic boolean isAbsolute ()

Ces méthodes renvoient true, si le chemin d'accès existe, s'il correspond à un fichier ou à un répertoire,ou si le chemin d'accès est absolu.

public boolean canRead () throws SecurityExceptionpublic boolean canWrite () throws SecurityException

Ces méthodes renvoient true, si le chemin d'accès est accessible en lecture ou en écriture.

public long lastModified () throws SecurityException

Renvoie la date de dernière modification du fichier. Cette date n'étant pas exprimé dans la même échelleque celle utilisée par la classe Date, elle ne peut être utilisée que pour comparer des dates de différentsfichiers.

public long length () throws SecurityException

Renvoie la taille du chemin d'accès représentant un fichier.

public boolean delete () throws SecurityExceptionpublic boolean renameTo (File dest) throws SecurityException

Ces méthodes permettent de supprimer ou de renommer un chemin d'accès, et renvoient true sil'opération s'est effectuée correctement.

public boolean mkdir () throws SecurityExceptionpublic boolean mkdirs () throws SecurityException

Ces méthodes permettent de créer le répertoire ou les répertoires représentés par le chemin d'accès etrenvoient true si l'opération s'est effectuée correctement.

public String [ ] list () throws SecurityExceptionpublic String [ ] list (FilenameFilter filter) throws SecurityException

Ces méthodes renvoient un tableau de chaînes de caractères dont les éléments sont les fichiers et lesrépertoires contenus dans le répertoire représenté par un chemin d'accès. Les répertoires . et .. sontexclus de cette liste.La seconde méthode permet d'appliquer le filtre filter pour ne récupérer que les fichiers et les

Page 150: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 5

répertoires autorisés par la méthode accept () de la classe de l'objet filter implémentant l'interfaceFilenameFilter.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unchemin d'accès à un objet ou renvoyer une chaîne de caractères égale au chemin d'accès.

La classe java.io.FileDescriptor

Cette classe final représente un descripteur de fichier. Une instance de cette classe permet demanipuler un fichier ouvert ou l'entrée et les sorties standards.Les méthodes getFD () des classes FileInputStream, FileOutputStream et RandomAccessFile permettentd'obtenir une instance de la classe FileDescriptor et les variables static in, out et err permettant demanipuler l'entrée standard, la sortie standard et la sortie standard d'erreurs sont de cette classe.

Variables

public static final FileDescriptor inpublic static final FileDescriptor outpublic static final FileDescriptor err

Ces variables représentent l'entrée standard, la sortie standard ou la sortie standard des erreurs. Lesvariables de même nom de la classe System sont construites à partir de ces variables.Vous pouvez les utiliser pour accéder à l'entrée et les sorties standards avec d'autres classes de gestiondes flux de données.

Constructeur

public FileDescriptor ()

Méthodes

public boolean valid ()

Gestion des flux de données

En Java, les classes dévolues aux flux de données permettent d'accéder aux données soit en lecturegrâce aux classes qui dérivent de la classe abstract InputStream, soit en écriture grâce aux classes quidérivent de la classe abstract OutputStream.

A chaque type de flux de données (fichier, chaîne de caractères, tableau d'octets, pipeline) correspondune classe permettant de le manipuler, mais il existe aussi un ensemble de classes de filtres dérivées desclasses abstract FilterInputStream et FilterOutputStream qui peuvent s'utiliser ensemble poursimplifier ou optimiser l'accès aux flux.

Accès à un flux de données en lecture

L'accès en lecture à un flux de données s'effectue grâce aux classes qui dérivent de la classeInputStream. Ces classes se divisent en deux catégories :

Les classes qui permettent de se lier à un type de source de données spécifique : la classe FileInputStream pour accéder en lecture à un fichier la classe StringBufferInputStream pour parcourir une chaîne de caractères sous forme de flux dedonnées la classe ByteArrayInputStream pour parcourir un tableau d'octets sous forme de flux de données la classe PipedInputStream pour accéder à un flux de données sous forme de pipeline la classe SequenceInputStream pour accéder aux données de plusieurs flux de données les uns après lesautres.

Page 151: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 6

La création d'une instance d'une de ces classes permet d'accéder sous forme d'un flux à la source de donnéesà laquelle elle est dédiée. En particulier, la création d'un objet de classe FileInputStream permet d'ouvrir unfichier et d'en lire le contenu.En regardant les constructeurs de ces classes vous verrez qu'ils prennent en paramètre une instance de laclasse représentant le type de sources de données qu'il manipule, comme le résume le tableau suivant :

Classes Paramètres des constructeurs

FileInputStream Chemin d'accès à un fichier (classe String) Fichier décrit par une instance de la classe File Descripteur de fichier (classe FileDescriptor)

StringBufferInputStream Chaîne de caractères (classe String)

ByteArrayInputStream Tableau d'octets (de type byte [])

PipedInputStream Aucun pour créer un pipeline d'entrée Sortie d'un pipeline (classe PipedOutputStream)

SequenceInputStream Une énumération de flux de données de classe InputStream Deux flux de données de classe InputStream

Une fois que vous avez créé une instance d'une de ces classes, vous pouvez appeler les méthodes de la classeInputStream, puisque toutes ces classes en héritent, comme dans l'application suivante qui permet d'écrire surla sortie standard les n premiers caractères d'un fichier. Recopiez-la dans un fichier LectureFichier.java , quevous compilez avec l'instruction javac LectureFichier.java pour ensuite l'exécuter avec java ou JavaRunner , grâce à l'instruction java LectureFichier nomFichier nombreCaracteres (par exemple javaLectureFichier LectureFichier.java 100) :

import java.io.*; public class LectureFichier{ // Méthode lancée à l'appel de l'instruction : // java LectureFichier nomFichier nombreCaracteres public static void main (String [ ] args) { try { // Ouverture du fichier passé en paramètre dans la ligne de commande InputStream fluxFichier = new FileInputStream (args [0]); // Lecture des n premiers octets du fichier. n est passé en paramètre byte contenuFichier [ ] = new byte [Integer.parseInt (args [1])]; fluxFichier.read (contenuFichier); // Ecriture sur la sortie standard des octets lus convertis // en une chaîne de caractères System.out.println (new String (contenuFichier, 0)); // Fermeture du fichier fluxFichier.close (); } catch (IOException e) { // Exception déclenchée si un problème survient pendant l'accès au fichier System.out.println (e); } }}

L'accès aux trois autres types de sources de données restantes (l'entrée standard, les sockets et un fichier viaune URL) s'effectue différemment :

L'entrée standard est accessible soit directement par la variable static in de la classe System, qui est declasse InputStream, soit par la variable static in de la classe FileDescriptor. Cette dernière variableétant elle-même de classe FileDescriptor, la lecture sur l'entrée standard peut démarrer en créant uneinstance de classe FileInputStream, avec l'instruction new FileInputStream (FileDescriptor.in)(l'entrée standard n'est pas disponible sous MacOS).

Page 152: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 7

L'accès en lecture aux sockets et à un fichier accessible via une URL s'effectue grâce à la méthodegetInputStream () des classes Socket et URLConnection, qui renvoie une instance d'une classe dérivéede InputStream.

Cette architecture est très pratique : elle permet de créer par exemple des méthodes de traitement qui peuventaccéder à n'importe quel flux de données via une référence de classe InputStream qui leur est passé enparamètre. Mais les méthodes de lecture de cette classe paraissent d'un intérêt très limité : elle permettent delire un ou plusieurs octets, c'est tout ! C'est là qu'intervient la seconde catégorie de classes dérivant deInputStream, afin d'enrichir les méthodes de lecture des flux de données. Les classes de filtre sur un flux de données qui dérivent de la classe FilterInputStream :

La classe BufferedInputStream pour accéder à un flux de données en utilisant une zone mémoiretampon (buffer ) La classe DataInputStream pour lire dans un flux de données des données d'un des types de base deJava ou des chaînes de caractères La classe LineNumberInputStream pour permettre de compter les lignes d'un flux de données La classe PushBackInputStream pour permettre d'accéder à un flux de données avec la possibilité derevenir en arrière d'un octet.

Contrairement aux classes dédiées à un type de source de données, les constructeurs de ces classes prennenttous en paramètre un objet de classe InputStream, qui est le flux de données sur lequel elles font une lectureavant d'effectuer des traitements supplémentaires. La classe InputStream étant la super classe de toutes lesclasses d'accès aux flux de données, vous pouvez donc passer en paramètre une instance de n'importe quelleclasse qui en dérive.Grâce à ce système vous pouvez utiliser n'importe quel filtre sur une source de données, et même cumulerles filtres les uns derrière les autres, comme le montre le schéma suivant :

figure 11. Utilisation cumulée de filtres

L'application suivante utilise ce schéma de filtres pour numéroter les lignes lues dans un fichier. Recopiez ladans un fichier NumerotationLigne.java , que vous compilez avec l'instruction javac NumerotationLigne.javapour ensuite l'exécuter avec java ou Java Runner , grâce à l'instruction java NumerotationLigne nomFichier(par exemple java NumerotationLigne NumerotationLigne.java) :

import java.io.*; public class NumerotationLigne{ // Méthode lancée à l'appel de l'instruction : // java LectureFichier nomFichier public static void main (String [ ] args) { try { // Ouverture du fichier passé en paramètre dans la ligne de commande // avec un filtre utilisant un buffer InputStream fluxFichier = new BufferedInputStream ( new FileInputStream (args [0])); // Numérotation des lignes numeroterLigne (fluxFichier); fluxFichier.close (); } catch (IOException e) { // Exception déclenchée si un problème survient pendant l'accès au fichier System.out.println (e);

Page 153: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 8

} } public static void numeroterLigne (InputStream flux) throws IOException { // Création d'un filtre de décompte des lignes LineNumberInputStream fluxLignes = new LineNumberInputStream (flux); // Ajout d'un filtre pour lire de manière plus pratique les caractères DataInputStream fluxLecture = new DataInputStream (fluxLignes); // Lecture des lignes du flux jusqu'à la fin du flux String ligne; for (ligne = fluxLecture.readLine (); ligne != null; ligne = fluxLecture.readLine ()) // Ecriture sur la sortie standard de la ligne lue avec son numéro de ligne System.out.println (String.valueOf (fluxLignes.getLineNumber ()) + " : " + ligne); }}

En poursuivant dans cette logique, il est simple de créer et d'utiliser vos propres filtres sur des flux dedonnées en dérivant vos nouvelles classes de la classe FilterInputStream ou d'une de ses classes dérivées.

La classe java.io.InputStream

Cette classe abstract est la super classe de toutes les classes qui permettent d'accéder à d'un flux de donnéesen lecture (voir aussi le paragraphe précédent).

Méthodes

public abstract int read () throws IOException

Lit un octet dans le flux de données. Renvoie -1 si la fin est atteinte.

public int read (byte [ ] tab) throws IOException

Lit tab.length octets dans le tableau tab. Si la fin est atteinte pendant la lecture, tab est remplit avec lesoctets lus. Renvoie le nombre d'octets lus ou -1 si la fin est atteinte.

public int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsException

Lit length octets dans le tableau tab, en le remplissant à partir de l'indice offset. Si la fin est atteinte pendantla lecture, tab est remplit avec les octets lus. Renvoie le nombre d'octets lus ou -1 si la fin est atteinte.

public long skip (long n) throws IOException

Saute n octets plus loin dans la lecture du flux de données. Renvoie le nombre d'octets effectivement sautés.

public int available () throws IOException

Renvoie le nombre d'octets que les méthodes read () peuvent actuellement lire sans bloquer le threadcourant.

public void close () throws IOException

Ferme l'accès au flux de données.

public synchronized void mark (int readlimit)

Marque la position courante dans le flux de données, pour qu'un appel à la méthode reset () provoque unretour en arrière à cette position. readlimit permet de préciser le nombre d'octets maximum que l'on peut lireavant que la marque soit invalide, c'est-à-dire la taille maximum du retour en arrière qu'il est possible de faire.

public synchronized void reset () throws IOException

Repositionne la position courante dans le flux de données sur la dernière marque positionnée par la méthode

Page 154: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 9

mark (). Si aucune marque n'a été positionnée ou si la marque est invalide, une exception IOException estdéclenchée.

public boolean markSupported ()

Renvoie true si le flux de données autorise l'utilisation des méthodes mark () et reset ().

Exemples

Applications LectureFichier , NumerotationLigne , ConcatenationFichiers et EchoServeur .

La classe java.io.FileInputStream

Cette classe qui dérive de la classe InputStream permet d'ouvrir et d'accéder à un fichier en lecture, sousforme de flux de données.

Constructeurs

public FileInputStream (String path) throws SecurityException, FileNotFoundExceptionpublic FileInputStream (File file) throws SecurityException, FileNotFoundException

Ces constructeurs permettent de créer une instance de classe FileInputStream à partir du chemin d'accès à unfichier path ou d'une instance de classe File.

public FileInputStream (FileDescriptor fdObj) throws SecurityException

Construit une instance de classe FileInputStream à partir d'un descripteur de fichier fdObj.

Méthodes

public int read () throws IOExceptionpublic int read (byte [ ] tab) throws IOExceptionpublic int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic long skip (long n) throws IOExceptionpublic int available () throws IOExceptionpublic void close () throws IOException

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à la lecture d'un fichier.

public final FileDescriptor getFD () throws IOException

Permet d'obtenir un descripteur de fichier.

protected void finalize () throws IOException

Méthode de la classe Object outrepassée pour que le fichier ouvert à la création d'une instance de la classeFileInputStream soit fermé avant que le Garbage Collector n'intervienne pour détruire cet objet. Le momentoù intervient le Garbage Collector n'étant généralement pas prévisible, il vaut mieux fermer soi-même lefichier avec la méthode close (), pour éviter d'en bloquer l'accès à d'autres programmes.

Exemples

Applications LectureFichier , NumerotationLigne et ConcatenationFichiers .

La classe java.io.StringBufferInputStream

Cette classe qui dérive de la classe InputStream permet d'accéder à une chaîne de caractères en lecture, sousforme de flux de données.

Variables

protected String buffer

Page 155: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 10

protected int posprotected int count

Constructeur

public StringBufferInputStream (String s)

Construit une instance de classe StringBufferInputStream à partir de la chaîne de caractères s.

Méthodes

public synchronized int read ()public synchronized int read (byte [ ] tab, int offset, int length) throws IndexOutOfBoundsExceptionpublic synchronized long skip (long n)public synchronized int available ()public synchronized void reset ()

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à l'accès à une chaîne decaractères.

Exemple

Applet PaperBoardClient .

La classe java.io.ByteArrayInputStream

Cette classe qui dérive de la classe InputStream permet d'accéder à un tableau d'octets en lecture, sous formede flux de données.

Variables

protected byte [ ] bufprotected int posprotected int count

Constructeurs

public ByteArrayInputStream (byte [ ] buf)

Construit une instance de classe ByteArrayInputStream à partir du tableau d'octets buf.

public ByteArrayInputStream (byte [ ] buf, int offset, int length)

Construit une instance de classe ByteArrayInputStream à partir du tableau d'octets buf, où length octetsseront lus à partir de l'indice offset.

Méthodes

public synchronized int read () throws IndexOutOfBoundsExceptionpublic synchronized int read (byte [ ] tab, int offset, int length) throws IndexOutOfBoundsExceptionpublic synchronized long skip (long n)public synchronized int available ()public synchronized void reset ()

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à l'accès à un tableau d'octets.

La classe java.io.PipedInputStream

Cette classe qui dérive de la classe InputStream permet d'accéder à un pipeline en lecture, sous forme de fluxde données.

Constructeurs

public PipedInputStream ()public PipedInputStream (PipedOutputStream src) throws IOException

Page 156: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 11

Méthodes

public void connect (PipedOutputStream src) throws IOException

Crée une connexion avec la sortie du pipeline src.

public synchronized int read () throws IOExceptionpublic synchronized int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic void close () throws IOException

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à l'accès à un pipeline.

La classe java.io.SequenceInputStream

Cette classe qui dérive de la classe InputStream permet d'accéder en lecture à un ensemble de flux dedonnées les uns après les autres.

Constructeurs

public SequenceInputStream (InputStream s1, InputStream s2)

Construit une instance de classe SequenceInputStream à partir des flux de données s1 et s2. Les méthodesread () de cette classe liront le contenu des flux s1 et s2 l'un à la suite de l'autre, comme s'il forme un seulflux.

public SequenceInputStream (Enumeration e)

Construit une instance de classe SequenceInputStream à partir d'une énumération de flux de données e. Lesméthodes read () de cette classe liront le contenu de tous les flux énumérés par e, comme s'il forme un seulflux. Chacun des objets énumérés par e doit donc être de classe InputStream ou d'une de ses classes dérivées.

Méthodes

public int read () throws IOExceptionpublic int read (byte [ ] buf, int pos, int length) throws IOException, IndexOutOfBoundsExceptionpublic void close () throws IOException

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à l'accès à un ensemble de flux dedonnées.

Exemple

Application ConcatenationFichiers .

La classe java.io.FilterInputStream

Cette classe qui dérive de la classe InputStream est la super classe de toutes les classes utilisées pour filtrer lalecture d'un flux de données. Vous pouvez utiliser les classes BufferedInputStream, DataInputStream,LineNumberInputStream ou PushBackInputStream qui en dérivent mais aussi créer vos propres classes de filtredérivant de cette classe.

Variable

protected InputStream in

Le flux de données sur lequel la lecture est faite. Utilisez cette variable dans vos classes dérivées pour liredes données sur le flux à filtrer.

Constructeur

protected FilterInputStream (InputStream in)

Page 157: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 12

Le constructeur de cette classe est protected ce qui vous empêche de l'instancier (cette classe n'a de toutefaçon aucun effet sur le flux de données ). Il est utilisé par les classes dérivées.

Méthodes

public int read () throws IOExceptionpublic int read (byte [ ] tab) throws IOExceptionpublic int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic long skip (long n) throws IOExceptionpublic int available () throws IOExceptionpublic void close () throws IOExceptionpublic synchronized void mark (int readlimit)public synchronized void reset () throws IOExceptionpublic boolean markSupported ()

Méthodes de la classe InputStream outrepassées pour qu'elles s'appliquent à l'accès à un flux de donnéesfiltré en lecture.

Voici un exemple d'une classe de filtre dérivée de FilterInputStream qui a pour effet de mettre en majusculetoutes les lettres qui sont lus sur un flux de données :

class ToUpperCaseInputStream extends FilterInputStream{ // Constructeur : appel du constructeur de la super classe public ToUpperCaseInputStream (InputStream flux) { super (flux); } public int read () throws IOException { // Lecture sur le flux d'un byte int car = (char)in.read (); // Si la fin du fichier n'est pas atteinte et si le caractère // lu est une minuscule renvoyer la majuscule correspondante if ( car != -1 && Character.isLowerCase ((char)car)) return Character.toUpperCase ((char)car); return car; } public int read (byte tab [], int offset, int length) throws IOException { // Lecture sur le flux : read () renvoie le nombre d'octets lus int nbreOctetsLus = in.read (tab, offset, length); // Conversion de toutes les minuscules lues en majuscules for (int i = 0; i < nbreOctetsLus; i++) if (Character.isLowerCase ((char)tab [offset + i])) tab [offset + i] = (byte)Character.toUpperCase ((char)tab [offset + i]); return nbreOctetsLus; }}

Si dans l'application NumerotationLigne vous remplacez la ligne :

DataInputStream fluxLecture = new DataInputStream (fluxLignes);

par les lignes :

DataInputStream fluxLecture = new DataInputStream ( new ToUpperCaseInputStream (fluxLignes));

vous pourrez vous rendre compte du résultat. Bien sûr ce filtre ne peut s'appliquer qu'à des fichiers textes.

La classe java.io.BufferedInputStream

Cette classe qui dérive des classes FilterInputStream et InputStream permet de lire sur un flux de donnéesen utilisant une zone mémoire tampon (buffer ). Cette classe se charge de lire sur le flux de données un grande

Page 158: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 13

nombre d'octets qu'elle garde dans un buffer. Tous les appels à la méthode read () ultérieurs sur uneinstance de cette classe renvoient du coup le contenu de ce buffer tant qu'il y reste des octets à lire. Ceciévite de faire une lecture physique sur le flux de données à chaque appel de la méthode read () c'estpourquoi ce filtre est très souvent utilisé.

Variables

protected byte [ ] bufprotected int countprotected int posprotected int markposprotected int marklimit

Constructeurs

public BufferedInputStream (InputStream in)public BufferedInputStream (InputStream in, int size)

Ces constructeurs permettent de créer une instance de la classe BufferedInputStream dont la lecture seraeffectuée sur le flux de données in. size est la taille utilisée pour créer le buffer (égal à 2048 par défaut).

Méthodes

public synchronized int read () throws IOExceptionpublic synchronized int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic synchronized long skip (long n) throws IOExceptionpublic synchronized int available () throws IOExceptionpublic synchronized void mark (int readlimit)public synchronized void reset () throws IOExceptionpublic boolean markSupported ()

Méthodes de la classe FilterInputStream outrepassées pour qu'elles s'appliquent à ce filtre.

Exemples

Applications NumerotationLigne , ConcatenationFichiers et PaperBoardServer .Applet PaperBoardClient .

L'interface java.io.DataInput

Cette interface implémentée par les classes DataInputStream et RandomAccessFile déclare un ensemble deméthodes qui permettent de lire à partir d'un flux de données ou d'un fichier des données de différents types :Soit un ensemble d'octets grâce aux méthodes readFully (), soit une donnée binaire représentant un type debase Java, soit une chaîne de caractères.

Méthodes

public void readFully (byte [ ] tab) throws IOException

Cette méthode doit permettre de lire tab.length octets dans le tableau tab. Une exception EOFException estdéclenchée si la fin du fichier est atteinte, et une exception IOException est déclenchée en cas d'autre erreur.

public void readFully (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsException

Cette méthode doit permettre de lire length octets dans le tableau tab, en le remplissant à partir de l'indiceoffset. Une exception EOFException est déclenchée si la fin du fichier est atteinte, et une exceptionIOException est déclenchée en cas d'autre erreur.

public boolean readBoolean () throws IOExceptionpublic byte readByte () throws IOExceptionpublic int readUnsignedByte () throws IOExceptionpublic short readShort () throws IOExceptionpublic int readUnsignedShort () throws IOExceptionpublic char readChar () throws IOExceptionpublic int readInt () throws IOException

Page 159: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 14

public long readLong () throws IOExceptionpublic float readFloat () throws IOExceptionpublic double readDouble () throws IOException

Ces méthodes doivent permettre de lire une valeur booléenne, un octet, un octet non signé (codé sur 8 bits etcompris en 0 et 255), un short, un short non signé, un int, un long, un float ou un double. Une exceptionEOFException est déclenchée si la fin du fichier est atteinte, et une exception IOException est déclenchée encas d'autre erreur.

public String readLine () throws IOException

Cette méthode doit permettre de lire tous les caractères jusqu'au premier symbole de retour à la ligne. Ellemanipule des caractères codés sur 8 bits et non sur 16 bits (Unicode). Renvoie la chaîne de caractères lue sansle caractère de retour à la ligne à la fin, ou null si la fin du fichier est atteinte.

public String readUTF () throws IOException

Cette méthode doit permettre de lire une chaîne de caractères qui est codée au format UTF. Renvoie la chaînede caractères lue ou null si la fin du fichier est atteinte.

public int skipBytes (int n) throws IOException

Cette méthode doit permettre de sauter n octets. Une exception EOFException est déclenchée si la fin dufichier est atteinte, et une exception IOException est déclenchée en cas d'autre erreur.

La classe java.io.DataInputStream

Cette classe qui dérive des classes FilterInputStream et InputStream implémente l'interface DataInput, cequi permet de lire à partir d'un flux de données autres chose que des octets.

Constructeur

public DataInputStream (InputStream in)

Construit une instance de la classe DataInputStream dont la lecture sera effectuée sur le flux de données in.

Méthodes

public final void read (byte [ ] tab) throws IOExceptionpublic final void read (byte [ ] tab, int offset, int length) throws IOException,

Méthodes de la classe FilterInputStream outrepassées pour qu'elles s'appliquent à ce filtre.

public final void readFully (byte [ ] tab) throws IOExceptionpublic final void readFully (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic final boolean readBoolean () throws IOExceptionpublic final byte readByte () throws IOExceptionpublic final int readUnsignedByte () throws IOExceptionpublic final short readShort () throws IOExceptionpublic final int readUnsignedShort () throws IOExceptionpublic final char readChar () throws IOExceptionpublic final int readInt () throws IOExceptionpublic final long readLong () throws IOExceptionpublic final float readFloat () throws IOExceptionpublic final double readDouble () throws IOExceptionpublic final String readLine () throws IOExceptionpublic final String readUTF () throws IOExceptionpublic final static String readUTF (DataInput in) throws IOExceptionpublic final int skipBytes (int n) throws IOException

Implémentation des méthodes de l'interface DataInput.

Exemple

Applications NumerotationLigne et PaperBoardServer .

Page 160: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 15

Applet PaperBoardClient .

La classe java.io.LineNumberInputStream

Cette classe qui dérive des classes FilterInputStream et InputStream permet de compter le nombre de ligneslors de la lecture d'un flux de données. Une ligne se termine par le caractère '\n'. L'applicationNumerotationLigne utilise cette classe de filtre.

Constructeur

public LineNumberInputStream (InputStream in)

Construit une instance de la classe LineNumberInputStream dont la lecture sera effectuée sur le flux dedonnées in. Le numéro de ligne est initialisé à 0.

Méthodes

public int read () throws IOExceptionpublic int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic long skip (long n) throws IOExceptionpublic int available () throws IOExceptionpublic void mark (int readlimit)public void reset () throws IOException

Méthodes de la classe FilterInputStream outrepassées pour qu'elles s'appliquent à ce filtre.

public int getLineNumber ()public void setLineNumber (int lineNumber)

Ces méthodes permettent d'interroger ou de modifier le numéro de ligne courant.

Exemple

Application NumerotationLigne .

La classe java.io.PushBackInputStream

Cette classe qui dérive des classes FilterInputStream et InputStream permet de simuler un retour en arrièred'un octet pendant la lecture d'un flux de données. La méthode unread () qui est utilisée pour revenir enarrière d'un octet prend en paramètre l'octet à renvoyer à la lecture suivante. Cette classe est surtout utiliséepour les analyseurs lexicaux et syntaxiques.

Variable

protected int pushBack

Constructeur

public PushbackInputStream (InputStream in)

Méthodes

public int read () throws IOExceptionpublic int read (byte [ ] bytes, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic int available () throws IOExceptionpublic boolean markSupported ()

Méthodes de la classe FilterInputStream outrepassées pour qu'elles s'appliquent à ce filtre.

public void unread (int ch) throws IOException

Permet de simuler un retour en arrière d'un octet. L'octet ch est le prochain octet qui sera renvoyé par unappel à une méthode read (). Cette méthode déclenche une exception de classe IOException si deux appels àunread () sont effectués à la suite sans appel à une des méthodes read () entre temps.

Page 161: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 16

La classe java.io.StreamTokenizer

Cette classe permet d'énumérer à partir d'un flux de données un ensemble de sous-chaînes ou de nombresséparées en spécifiant différents délimiteurs de manière plus riche que la classe java.util.StringTokenizer.Cette classe peut être utilisée par exemple pour écrire un compilateur.Seuls les caractères dont le code est compris entre 0 et 255 sont utilisables.

Variables

public static final int TT_EOFpublic static final int TT_EOLpublic static final int TT_NUMBERpublic static final int TT_WORD

Ces constantes représentent le type d'une sous-chaîne lue : la fin du flux de données, la fin d'une ligne, unnombre ou un mot.

public int ttype

Cette variable mémorise le type de la dernière sous-chaîne lue (avec pour valeur TT_EOF, TT_EOL, TT_NUMBER ouTT_WORD). Voir aussi la description des méthodes qui suivent.

public String svalpublic double nval

Ces variables mémorisent le dernier nombre (si ttype = TT_NUMBER) ou le dernier mot lu (si ttype = TT_WORD).

Constructeur

public StreamTokenizer (InputStream in)

Construit une instance de la classe StreamTokenizer avec comme flux de données d'entrée in.

Méthodes

public void wordChars (int low, int high)

Permet d'ajouter tous les caractères dont le code est compris entre low et high à l'ensemble des caractèresutilisés pour construire un mot. La lecture d'un mot s'arrête quand un des caractères utilisés comme espace ouun caractère ordinaire sont lus. Quand un mot est lu, la variable ttype est égale à TT_WORD et la variable svalcontient le mot lu.

public void whitespaceChars (int low, int high)

Permet d'ajouter tous les caractères dont le code est compris entre low et high à l'ensemble des caractèresutilisés comme espace.

public void commentChar (int ch)

Permet d'ajouter le caractère de code ch à l'ensemble des caractères délimitant le début d'un commentaire defin de ligne.

public void ordinaryChar (int ch)public void ordinaryChars (int low, int high)

Permet d'ajouter le caractère de code ch ou tous les caractères dont le code est compris entre low et high àl'ensemble des caractères ordinaires. Un caractère ordinaire n'appartient ni à l'ensemble des caractères utiliséspour construire un mot ou un nombre, ni à l'ensemble des caractères utilisés comme espace ou commedélimiteurs de commentaire.Quand un caractère ordinaire est lu, la variable ttype est égale à ce caractère.

public void quoteChar (int ch)

Permet d'ajouter le caractère de code ch à l'ensemble des caractères utilisés pour entourer une chaîne de

Page 162: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 17

caractères constante. Quand une chaîne de caractères constante est lue, la variable ttype est égale audélimiteur et la variable sval contient la chaîne lue sans les délimiteurs.

public void parseNumbers ()

Permet de spécifier que les nombres doivent être lus en tant que tels, c'est-à-dire que l'appel de cette méthodemémorise que les chiffres 0 à 9, les caractères '.' et '-' appartiennent à l'ensemble des caractères utiliséspour construire un nombre. Quand un nombre est lu, la variable ttype est égale à TT_NUMBER et la variablenval contient le nombre lu.

public void resetSyntax ()

Remet à zéro la syntaxe définie avec les méthodes précédentes.

public void eolIsSignificant (boolean flag)

Permet de spécifier que les caractères de fin de ligne sont significatifs ou non. Si flag est égal à true, lavariable ttype vaudra TT_EOL chaque fois qu'une fin de ligne est lue, sinon les caractères de fin de ligne serontconsidérés comme un espace.

public void slashStarComments (boolean flag)

Permet de spécifier si les commentaires Java /* ... */ sont significatifs ou non.

public void slashSlashComments (boolean flag)

Permet de spécifier si les commentaires Java de fin de ligne // ... sont significatifs ou non.

public void lowerCaseMode (boolean flag)

Permet de spécifier si tous les mots lus sont convertis en minuscules ou non.

public int nextToken () throws IOException

Lit dans le flux d'entrée la sous-chaîne suivante en respectant la syntaxe définie grâce aux méthodesprécédentes. Renvoie la valeur de la variable ttype.

public void pushBack ()

Permet de revenir d'une sous-chaîne en arrière une fois.

public int lineno ()

Renvoie le numéro de ligne courant.

public String toString ()

Méthode de la classe Object, outrepassée pour qu'elle renvoie une description de la dernière sous-chaîne lue.

Exemple

Applet PaperBoardClient .

Accès à un flux de données en écriture

De manière similaire à l'accès à un flux de données en lecture, l'accès à un flux de données en écritures'effectue grâce aux classes qui dérivent de la classe OutputStream. Ces classes elles aussi se divisent en deuxcatégories : Les classes qui permettent de se lier à un type de source de données spécifique :

la classe FileOutputStream pour accéder en écriture à un fichier la classe ByteArrayOutputStream pour écrire dans un tableau d'octets sous forme de flux de données la classe PipedOutputStream pour accéder à un flux de données sous forme de pipeline

La création d'une instance d'une de ces classes permet d'accéder sous forme d'un flux à la source de données

Page 163: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 18

à laquelle elle est dédiée. En particulier, la création d'un objet de classe FileOutputStream permet d'ouvrir unfichier et d'y écrire.En regardant les constructeurs de ces classes vous verrez qu'ils prennent en paramètre une instance de laclasse représentant le type de sources de données qu'il manipule, comme le résume le tableau suivant :

Classes Paramètres des constructeurs

FileOutputStream Chemin d'accès à un fichier (classe String) Fichier décrit par une instance de la classe File Descripteur de fichier (classe FileDescriptor)

ByteArrayOutputStream Aucun pour créer un tableau d'octets par défaut Taille minimum du tableau d'octets

PipedOutputStream Aucun pour créer un pipeline de sortie Entrée d'un pipeline (classe PipedInputStream)

Une fois que vous avez créé une instance d'une de ces classes, vous pouvez appeler les méthodes de la classeOutputStream, puisque toutes ces classes en héritent.L'accès aux trois autres types de sources de données restantes (les sorties standards, les sockets et un fichiervia une URL) s'effectue différemment :

Les sorties standard et d'erreur sont accessibles soit directement par les variables static out et err de laclasse System, qui sont de classe PrintStream, soit par les variables static out et err de la classeFileDescriptor. Ces dernières variables étant elles-même de classe FileDescriptor, l'écriture sur lessorties standard peut démarrer en créant une instance de classe FileOutputStream, par exemple avecl'instruction new FileOutputStream (FileDescriptor.out). L'accès en écriture aux sockets et à un fichier accessible via une URL s'effectue grâce à la méthodegetOutputStream () des classes Socket et URLConnection, qui renvoie une instance d'une classe dérivéede InputStream.

Comme pour la classe InputStream, les méthodes d'écriture de la classe OutputStream paraissent d'unintérêt très limité : elle permettent d'écrire un ou plusieurs octets, c'est pourquoi il existe aussi uneseconde catégorie de classes dérivant de OutputStream, afin d'enrichir les méthodes d'écriture sur lesflux de données.

Les classes de filtre sur un flux de données qui dérivent de la classe FilterOutputStream : La classe BufferedOutputStream pour écrire sur un flux de données en utilisant une zone mémoiretampon (buffer ) La classe DataOutputStream pour écrire dans un flux de données des données d'un des types de base deJava ou des chaînes de caractères La classe PrintStream pour d'écrire au format texte les types de base Java

Contrairement aux classes dédiées à un type de source de données, les constructeurs de ces classesprennent tous en paramètre un objet de classe OutputStream, qui est le flux de données sur lequel elleseffectuent des traitements supplémentaires avant d'y écrire. La classe OutputStream étant la super classede toutes les classes d'écriture sur les flux de données, vous pouvez donc passer en paramètre uneinstance de n'importe quelle classe qui en dérive.

L'application suivante utilise les classes FileInputStream, SequenceInputStream, FileOutputStream etBufferedOutputStream pour effectuer la concaténation de plusieurs fichiers dans un fichier destination.Recopiez la dans un fichier ConcatenationFichiers.java , que vous compilez avec l'instruction javacConcatenationFichiers.java pour ensuite l'exécuter avec java ou Java Runner , grâce à l'instruction javaConcatenationFichiers nomFichier1 ... nomFichierN fichierDest (par exemple javaConcatenationFichiers ConcatenationFichiers.java NumerotationLigne.java resultat.java) :

import java.io.*;import java.util.Vector; public class ConcatenationFichiers{ // Méthode lancée à l'appel de l'instruction : // java ConcatenationFichiers nomFichier1 ... nomFichierN nomFichierDest public static void main (String [ ] args)

Page 164: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 19

{ try { Vector ensembleFichiers = new Vector (); // Ajout à ensembleFichiers de tous les flux de données avec buffer // correspondant à chaque fichier d'entrée passé en paramètres // (sauf le dernier paramètre) for (int i = 0; i < args.length - 1; i++) ensembleFichiers.addElement (new BufferedInputStream ( new FileInputStream (args [i]))); // Création d'un ensemble de flux d'entrée InputStream fluxEntree = new SequenceInputStream (ensembleFichiers.elements ()); // Ouverture en écriture avec un buffer du fichier // passé en dernier paramètre dans la ligne de commande OutputStream fluxDestination = new BufferedOutputStream ( new FileOutputStream (args [args.length -1])); byte donnees [ ] = new byte [1000]; int nbreOctetsLus; // Lecture puis écriture des données while ((nbreOctetsLus = fluxEntree.read (donnees)) != -1) fluxDestination.write (donnees, 0, nbreOctetsLus); // Fermeture des flux fluxDestination.close (); fluxEntree.close (); } catch (IOException e) { // Exception déclenchée si un problème survient pendant l'accès aux fichiers System.out.println (e); } }}

La classe java.io.OutputStream

Cette classe abstract est la super classe de toutes les classes qui permettent d'écrire sur un flux de donnéesen lecture (voir aussi le paragraphe précédent).

Méthodes

public abstract void write (int b) throws IOException

Ecrit un octet sur le flux de données.

public void write (byte [ ] tab) throws IOException

Ecrit les octets du tableau tab sur le flux de données.

public void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsException

Ecrit length octets du tableau tab sur le flux de données, à partir de l'indice offset.

public void flush () throws IOException

Ecrit physiquement sur le flux de données quand une zone tampon (buffer ) est utilisée.

public void close () throws IOException

Ferme l'accès au flux de données.

Exemple

Application ConcatenationFichiers et EchoServeur .

Page 165: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 20

La classe java.io.FileOutputStream

Cette classe qui dérive de la classe OutputStream permet d'ouvrir un fichier et d'y écrire, sous forme de fluxde données.

Constructeurs

public FileOutputStream (String path) throws SecurityException, FileNotFoundExceptionpublic FileOutputStream (File file) throws SecurityException, FileNotFoundException

Ces constructeurs permettent de créer une instance de classe FileOutputStream à partir du chemin d'accès àun fichier path ou d'une instance de classe File. Si le fichier n'existe pas il est créé.

public FileOutputStream (FileDescriptor fdObj) throws SecurityException

Construit une instance de classe FileInputStream à partir d'un descripteur de fichier fdObj.

Méthodes

public void write (int b) throws IOExceptionpublic void write (byte [ ] tab) throws IOExceptionpublic void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic void close () throws IOException

Méthodes de la classe OutputStream outrepassées pour qu'elles s'appliquent à l'écriture dans un fichier.

public final FileDescriptor getFD () throws IOException

Permet d'obtenir un descripteur de fichier.

protected void finalize () throws IOException

Méthode de la classe Object outrepassée pour que le fichier ouvert à la création d'une instance de la classeFileOutputStream soit fermé avant que le Garbage Collector n'intervienne pour détruire cet objet. Le momentoù intervient le Garbage Collector n'étant généralement pas prévisible, il vaut mieux fermer soi-même lefichier avec la méthode close (), pour éviter d'en bloquer l'accès à d'autres programmes.

Exemple

Application ConcatenationFichiers .

La classe java.io.PipedOutputStream

Cette classe qui dérive de la classe OutputStream permet d'accéder à un pipeline en écriture, sous forme deflux de données.

Constructeurs

public PipedOutputStream (PipedInputStream snk) throws IOExceptionpublic PipedOutputStream ()

Méthodes

public void connect (PipedInputStream snk) throws IOException

Crée une connexion avec l'entrée du pipeline snk.

public void write (int b) throws IOExceptionpublic void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic void close () throws IOException

Méthodes de la classe OutputStream outrepassées pour qu'elles s'appliquent à l'écriture sur un pipeline.

Page 166: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 21

La classe java.io.ByteArrayOutputStream

Cette classe qui dérive de la classe OutputStream permet d'écrire dans un tableau d'octets, sous forme de fluxde données. Ce tableau est créé par la classe et automatiquement agrandi s'il est plein.

Variables

protected byte [ ] bufprotected int count

Constructeurs

public ByteArrayOutputStream ()public ByteArrayOutputStream (int size)

Ces constructeurs permettent de créer une instance de classe ByteArrayOutputStream, dont le tableau sera auminimum de size octets (égal à 32 par défaut).

Méthodes

public synchronized void write (int b)public synchronized void write (byte [ ] tab, int offset, int length) throws IndexOutOfBoundsException

Méthodes de la classe OutputStream outrepassées pour qu'elles s'appliquent à l'écriture dans un tableaud'octets.

public int size ()

Renvoie le nombre courant d'octets écrits dans le tableau.

public synchronized void reset ()

Remet l'index courant dans le tableau à 0 sans allouer un nouveau tableau.

public synchronized byte [ ] toByteArray ()

Renvoie un tableau d'octets copie des octets écrits dans le tableau interne.

public String toString ()

Méthode de la classe Object, outrepassée pour qu'elle renvoie les octets écrits dans le tableau sous forme dechaîne de caractères.

public String toString (int hibyte)

Renvoie les octets écrits dans le tableau sous forme de chaîne de caractères, dont chaque caractère Unicode ahibyte pour partie haute.

public synchronized void writeTo (OutputStream out) throws IOException

Ecrit sur le flux de données out les octets écrits dans le tableau.

La classe java.io.FilterOutputStream

Cette classe qui dérive de la classe OutputStream est la super classe de toutes les classes utilisées pour filtrerl'écriture sur un flux de données. Vous pouvez utiliser les classes BufferedOutputStream, DataOutputStreamou PrintStream qui en dérivent mais aussi créer vos propres classes de filtre dérivant de cette classe (voiraussi la classe ToUpperCaseInputStream comme exemple de filtre).

Variable

protected OutputStream out

Constructeur

Page 167: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 22

public FilterOutputStream (OutputStream out)

Méthodes

public void write (int b) throws IOExceptionpublic void write (byte [ ] tab) throws IOExceptionpublic void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic void flush () throws IOExceptionpublic void close () throws IOException

Méthodes de la classe OutputStream outrepassées pour qu'elles s'appliquent à l'accès à un flux de donnéesfiltré en écriture.

La classe java.io.BufferedOutputStream

Cette classe qui dérive des classes FilterOutputStream et OutputStream permet d'écrire sur un flux dedonnées en utilisant une zone mémoire tampon (buffer ). Lors d'un appel à la méthodes write (), les octetssont stockés dans le buffer. Le buffer est écrit finalement sur le flux de données une fois qu'il est plein oulors d'un appel à la méthode flush (). Ceci évite de faire une écriture physique sur le flux de données àchaque appel de la méthode write () c'est pourquoi ce filtre est très souvent utilisé.

Variables

protected byte [ ] bufprotected int count

Constructeurs

public BufferedOutputStream (OutputStream out)public BufferedOutputStream (OutputStream out, int size)

Ces constructeurs permettent de créer une instance de la classe BufferedOutputStream dont l'écriture seraeffectuée sur le flux de données out. size est la taille utilisée pour créer le buffer (égal à 512 par défaut).

Méthodes

public synchronized void write (int b) throws IOExceptionpublic synchronized void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic synchronized void flush () throws IOException

Méthodes de la classe FilterOutputStream outrepassées pour qu'elles s'appliquent à ce filtre.

Exemple

Application ConcatenationFichiers et PaperBoardServer .Applet PaperBoardClient .

L'interface java.io.DataOutput

Cette interface implémentée par les classes DataOutputStream et RandomAccessFile déclare un ensemble deméthodes qui permettent d'écrire dans un flux de données ou dans un fichier des données de différents types :Soit un ensemble d'octets grâce aux méthodes write (), soit une donnée binaire représentant un type de baseJava, soit une chaîne de caractères.Les données écrites grâce à ces méthodes sont lisibles grâce aux méthodes de l'interface DataInput, quelquesoit le système sur lequel les données ont été écrites. Le codage binaire des nombres étant souventdifféremment d'un système à l'autre, ceci permet de créer des flux de données portables.

Méthodes

public void write (int b) throws IOException

Cette méthode doit permettre d'écrire un octet.

Page 168: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 23

public void write (byte [ ] tab) throws IOException

Cette méthode doit permettre d'écrire les octets du tableau tab.

public void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsException

Cette méthode doit permettre d'écrire length octets du tableau tab, à partir de l'indice offset.

public void writeBoolean (boolean v) throws IOExceptionpublic void writeByte (int v) throws IOExceptionpublic void writeShort (int v) throws IOExceptionpublic void writeChar (int v) throws IOExceptionpublic void writeInt (int v) throws IOExceptionpublic void writeLong (long v) throws IOExceptionpublic void writeFloat (float v) throws IOExceptionpublic void writeDouble (double v) throws IOException

Ces méthodes doivent permettre d'écrire une valeur booléenne, un octet, un short, un caractère Unicode, unint, un long, un float ou un double.

public void writeBytes (String s) throws IOException

Cette méthode doit permettre d'écrire la chaîne de caractères s. Elle écrit les caractères en les codant sur 8bits et non sur 16 bits (Unicode).

public void writeChars (String s) throws IOException

Cette méthode doit permettre d'écrire la chaîne de caractères s, comme une suite de caractères Unicode.

public void writeUTF (String s) throws IOException

Cette méthode doit permettre d'écrire au format UTF la chaîne de caractères s.

La classe java.io.DataOutputStream

Cette classe qui dérive des classes FilterOutputStream et OutputStream implémente l'interface DataOutput, cequi permet d'écrire sur un flux de données autres chose que des octets.

Variable

protected int written

Constructeur

public DataOutputStream (OutputStream out)

Construit une instance de la classe DataOutputStream dont l'écriture sera effectuée sur le flux de données out.

Méthodes

public synchronized void write (int b) throws IOExceptionpublic synchronized void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic final void writeBoolean (boolean v) throws IOExceptionpublic final void writeByte (int v) throws IOExceptionpublic final void writeShort (int v) throws IOExceptionpublic final void writeChar (int v) throws IOExceptionpublic final void writeInt (int v) throws IOExceptionpublic final void writeLong (long v) throws IOExceptionpublic final void writeFloat (float v) throws IOExceptionpublic final void writeDouble (double v) throws IOExceptionpublic final void writeBytes (String s) throws IOExceptionpublic final void writeChars (String s) throws IOExceptionpublic final void writeUTF (String str) throws IOException

Implémentation des méthodes de l'interface DataOutput. La méthode write (byte [ ] tab) est implémentéepar la classe FilterOutputStream.

Page 169: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 24

public void flush () throws IOException

Méthodes de la classe FilterOutputStream outrepassées pour qu'elles s'appliquent à ce filtre.

public final int size ()

Renvoie le nombre d'octets écrits sur le flux de données depuis la création du filtre.

La classe java.io.PrintStream

Cette classe qui dérive des classes FilterOutputStream et OutputStream permet d'écrire au format texte lestypes de base Java. Elle est très souvent utilisée via la variable System.out qui est justement de classePrintStream.Contrairement aux méthodes des autres classes écrivant sur un flux de données, les méthodes de la classePrintStream ne déclenchent jamais d'exceptions de classe IOException. Sur une erreur survient pendantl'écriture sur le flux de données, une variable private prend la valeur true et la méthode checkError ()renvoie cette valeur. Ce système qui peut paraître peu contraignant pour l'utilisateur de la classe PrintStreamet laisser passer des erreurs plus facilement, comporte malgré tout un avantage majeur : il permet par exempled'écrire sur la sortie standard avec la variable System.out sans être obligé d'utiliser un bloc try ... catch.

Constructeurs

public PrintStream (OutputStream out)public PrintStream (OutputStream out, boolean autoflush)

Ces constructeurs permettent de créer une instance de la classe PrintStream dont l'écriture sera effectuée surle flux de données out. autoflush permet de préciser si un appel à la méthode flush () doit être effectué àchaque retour à la ligne (égal à false par défaut).

Méthodes

public void write (int b)public void write (byte [ ] tab, int offset, int length) throws IndexOutOfBoundsExceptionpublic void flush ()public void close ()

Méthodes de la classe FilterOutputStream outrepassées pour qu'elles s'appliquent à ce filtre.

public boolean checkError ()

Appelle la méthode flush () et renvoie true si une erreur est survenue pendant un appel aux autresméthodes de cette classe.

public void print (Object obj)public synchronized void print (String s)public synchronized void print (char [ ] tab)public void print (boolean b)public void print (char c)public void print (int i)public void print (long l)public void print (float f)public void print (double d)

Ces méthodes permettent d'écrire au format texte un objet, une chaîne de caractère, un tableau de caractères,une valeur booléenne, un caractère, un int, un long, un float ou un double, sur le flux de données. Le texteécrit pour l'objet obj est la chaîne de caractère renvoyée par l'appel obj.toString ().

public synchronized void println (Object obj)public synchronized void println (String s)public synchronized void println (char [ ] tab)public synchronized void println (boolean b)public synchronized void println (char c)public synchronized void println (int i)public synchronized void println (long l)public synchronized void println (float f)

Page 170: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 25

public synchronized void println (double d)

Ces méthodes effectuent les mêmes opérations que le groupe précédent, puis écrivent un retour à la ligne surle flux de données.

public void println ()

Ecrit un retour à la ligne sur le flux de données.

Cette classe est l'équivalent des fonctions printf () du C, mais ne comporte pas toute la richesse desformats de données disponibles avec printf ().

Exemples

Les applications Banque , LectureFichier , NumerotationLigne , ConcatenationFichiers , TestExpression etPaperBoardServer utilisent la variable System.out et la méthode println ().Applet PaperBoardClient .

Gestion de l'accès aléatoire aux fichiers

Java fournit la classe RandomAccessFile pour accéder aléatoirement au contenu d'un fichier en lecture ouen écriture (voir aussi le début de ce chapitre).

La classe java.io.RandomAccessFile

Cette classe qui implémente les interfaces DataInput et DataOuput, permet d'accéder aléatoirement à un fichieren mode lecture/écriture, ou uniquement en mode lecture.

Constructeurs

public RandomAccessFile (String path, String mode) throws SecurityException, IOException, IllegalArgumentExceptionpublic RandomAccessFile (File file, String mode) throws SecurityException, IOException, IllegalArgumentException

Ces constructeurs permettent d'ouvrir le fichier représenté par son chemin d'accès path ou par une instancede la classe File. Si mode est égal à "rw" (read/write ) il est possible d'écrire ou de lire dans le fichier ouvertet le fichier est créé s'il n'existe pas.Si mode est égal à "r" (read ), le fichier est accessible uniquement en lecture et par conséquent l'utilisation desméthodes d'écriture write...() de cette classe déclenchera une exception de classe IOException.

Méthodes

public final FileDescriptor getFD () throws IOException

Permet d'obtenir un descripteur de fichier.

public long getFilePointer () throws IOException

Renvoie la position courante dans le fichier.

public void seek (long pos) throws IOException

Déplace la position courante en pos dans le fichier.

public long length () throws IOException

Renvoie la taille courante du fichier.

public void close () throws IOException

Ferme l'accès au fichier.

public abstract int read () throws IOException

Page 171: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion des fichiers et des flux de données Page: 26

Lit un octet dans le flux de données. Renvoie -1 si la fin est atteinte.

public int read (byte [ ] tab) throws IOException

Lit tab.length octets dans le tableau tab. Si la fin est atteinte pendant la lecture, tab est remplit avec lesoctets lus. Renvoie le nombre d'octets lus ou -1 si la fin est atteinte.

public int read (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsException

Lit length octets dans le tableau tab, en le remplissant à partir de l'indice offset. Si la fin est atteinte pendantla lecture, tab est remplit avec les octets lus. Renvoie le nombre d'octets lus ou -1 si la fin est atteinte.

public int skipBytes (int n) throws IOException

Méthode de l'interface DataInput implémentée pour qu'elle déplace de n octets la position courante dans lefichier. n peut être positif ou négatif (pour revenir en arrière). Renvoie n.

public final void readFully (byte [ ] tab) throws IOExceptionpublic final void readFully (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic final boolean readBoolean () throws IOExceptionpublic final byte readByte () throws IOExceptionpublic final int readUnsignedByte () throws IOExceptionpublic final short readShort () throws IOExceptionpublic final int readUnsignedShort () throws IOExceptionpublic final char readChar () throws IOExceptionpublic final int readInt () throws IOExceptionpublic final long readLong () throws IOExceptionpublic final float readFloat () throws IOExceptionpublic final double readDouble () throws IOExceptionpublic final String readLine () throws IOExceptionpublic final String readUTF () throws IOException

Implémentation des autres méthodes de l'interface DataInput.

public void write (int b) throws IOExceptionpublic void write (byte [ ] tab) throws IOExceptionpublic void write (byte [ ] tab, int offset, int length) throws IOException, IndexOutOfBoundsExceptionpublic final void writeBoolean (boolean v) throws IOExceptionpublic final void writeByte (int v) throws IOExceptionpublic final void writeShort (int v) throws IOExceptionpublic final void writeChar (int v) throws IOExceptionpublic final void writeInt (int v) throws IOExceptionpublic final void writeLong (long v) throws IOExceptionpublic final void writeFloat (float v) throws IOExceptionpublic final void writeDouble (double v) throws IOExceptionpublic final void writeBytes (String s) throws IOExceptionpublic final void writeChars (String s) throws IOExceptionpublic final void writeUTF (String str) throws IOException

Implémentation des méthodes de l'interface DataOutput.

Page 172: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 1

Les accès au réseau

Accès via une URLL'architecture client-serveur

Accès via les socketsAccès via les datagrams

Ce chapitre décrit le package java.net de Java 1.0 qui rassemble les classes permettant de gérer les accèsréseau via une URL ou par les sockets.

Accès via une URL

Les accès au réseau peuvent se faire à plusieurs niveaux en Java.Le niveau le plus simple permet d'accéder à un fichier sur le réseau grâce à son URL (Uniformed ResourceLocator ) : Contrairement au chemin d'accès classique à un fichier dont la notation varie d'un système àl'autre (c:\fichier.txt, /usr/unCompte/fichier.txt), une URL permet de désigner un fichier demanière uniforme quelque que soit le système qui héberge ce fichier.Même si vous ne la connaissiez pas sous ce nom, l'adresse d'un site Internet est une URL :http://www.javasoft.com/index.html, http://www.eteks.com/coursjava/net10.html# AccesURL sontdes exemples d'URL.De quoi est composée une URL ?

Une chaîne représentant le protocole à utiliser pour accéder au fichier (http, ftp, file, mailto,...),suivi du symbole :. Le nom de l'hôte qui fournit le service recherché (www.yahoo.fr). Cet hôte correspond à unemachine. Eventuellement un numéro de port sur la machine de l'hôte précédé du symbole :. Le chemin d'accès au fichier recherché sur l'hôte. Les répertoires éventuels de ce chemin d'accèssont séparés par le symbole /. Pour les fichiers HTML, le nom du fichier peut être suivi d'une référence à une ancre à l'intérieurdu fichier précédé du symbole #.

Une URL peut représenter un fichier mais aussi de manière plus générale une ressource. Par exemple,une ressource peut être un programme renvoyant une image ou le résultat d'un accès à une base dedonnées. La plupart des programmes auxquels on accède sur un site Internet via une URL utilise lemodèle CGI (Common Gateway Interface ). Ce modèle définit comment appeler un programme et luitransmettre ses paramètres, de manière standard.Par exemple, http://www.hit-parade.com/hp.asp?site=a15740 est un programme CGI appelé avec lavaleur a15740 pour le paramètre site. Ce programme renvoie l'image du site hit-parade.com.

Java permet d'accéder au fichier ou à la ressource représentés par une URL sous forme de flux dedonnées, grâce aux deux classes URL et URLConnection.

La classe java.net.URL

Cette classe final permet de manipuler une URL sous forme d'un objet constant. Les constructeurs decette classe pouvant éventuellement déclencher une exception de classe MalformedURLException, lacréation d'une nouvelle instance de classe URL doit être programmée dans un bloc try ... catch. L'objetcréé ne garantit pas que le fichier existe mais seulement que l'URL mémorisée par l'objet estcorrectement formée et que le protocole spécifié est géré par la Machine Virtuelle Java.Les objets de cette classe sont utilisés pour accéder sous forme de flux de données au fichiercorrespondant, mais aussi par certaines méthodes de la classe Applet pour obtenir l'URL d'un document

Page 173: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 2

HTML, lire une image ou un fichier son.

Constructeurs

public URL (String protocol, String host, int port, String file) throws MalformedURLExceptionpublic URL (String protocol, String host, String file) throws MalformedURLException

Ces constructeurs permettent de créer un objet de classe URL à partir du protocole protocol, l'hôte host,le port port et le chemin d'accès file d'une URL.

public URL (String spec) throws MalformedURLException

Construit une instance de classe URL à partir de la chaîne de caractères spec représentant une URL.

public URL (URL context, String spec) throws MalformedURLException

Construit une instance de classe URL à partir d'une URL existante context et de la chaîne de caractèresspec. Si spec décrit entièrement une URL (avec protocole, hôte, fichier,...) , l'URL context est ignorée etl'objet créé correspond à l'URL spec. Sinon, context est utilisé comme base complétée par lesinformations fournies dans spec, pour construire le nouvel objet de classe URL (spec peut par exempledésigné un fichier dans un sous répertoire différent).

Méthodes

public String getProtocol ()public String getHost ()public int getPort ()public String getFile ()public String getRef ()

Ces méthodes permettent d'interroger le protocole, l'hôte, le port, le chemin d'accès au fichier et laréférence mémorisée dans une instance de la classe URL. Si le port n'a pas été précisé en paramètre duconstructeur, la valeur -1 est renvoyée.

public boolean sameFile (URL other)

Renvoie true si other désigne la même URL que l'objet sur lequel est invoquée cette méthode. Lesréférences mémorisées par les objets ne sont pas prises en compte pour la comparaison.

public String toExternalForm ()

Renvoie une chaîne de caractères correspondant à l'URL mémorisée par un objet de classe URL.

public final InputStream openStream () throws IOException

Ouvre en lecture la connexion avec une URL, et renvoie une instance de la classe InputStream pouraccéder aux données sous forme de flux de données.

public final Object getContent () throws IOException

Renvoie un objet correspondant au contenu du fichier représenté par un objet de classe URL. Parexemple, si le fichier est une image, cette méthode renverra une instance d'une classe dérivée de laclasse Image.

public URLConnection openConnection () throws IOException

Ouvre une connexion avec une URL, et renvoie une instance de la classe URLConnection qui permetd'obtenir toute sorte de renseignements (dates, en-tête,...) sur le fichier correspondant à l'URL.

public static synchronized void setURLStreamHandlerFactory (URLStreamHandlerFactory fac) throws SecurityException

Page 174: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 3

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de créationde flux de données pour chacun des protocoles reconnus. Cette méthode static ne peut être appeléequ'une seule fois. Par défaut, la Machine Virtuelle Java reconnaît un certain nombre de protocoles (voirl'exemple qui suit).

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet de classe URL à un objet ou renvoyer une chaîne de caractères correspondant à l'URL.

L'application suivante permet de tester si la Machine Virtuelle Java accepte ou non les 4 protocoles lesplus communément utilisés : http, ftp, file et mailto. Recopiez-la dans un fichier TestProtocole.java , quevous compilez avec l'instruction javac TestProtocole.java pour ensuite l'exécuter avec java ou JavaRunner , grâce à l'instruction java TestProtocole :

import java.net.*; public class TestProtocole{ public static void main (String [] args) { // Tableau avec 4 URL à tester String urlTest [] = {"http://wwwusers.imaginet.fr/~puybaret/learnjava/index.html", "ftp://wwwusers.imaginet.fr/~puybaret/learnjava/index.html", "file://C//java/bin/java.exe", "mailto:[email protected]"}; for (int i = 0; i < urlTest.length; i++) try { // Création d'une URL URL url = new URL (urlTest [i]); System.out.println ("URL : " + url + " correctement form\u00e9e\n" + " et protocole " + url.getProtocol () + " reconnu."); } catch (MalformedURLException e) { // URL incorrect ou protocole inconnu System.out.println ("URL : " + urlTest [i] + " incorrect\n" + " ou protocole non reconnu\n" + "(Exception " + e + ")."); } } }

Autre exemple

Applets HelloFromNet et BoutonsNavigation .

La classe java.net.URLConnection

Cette classe abstract gère la connexion avec une URL. Une instance d'une classe dérivant de cetteclasse peut être obtenue grâce à la méthode openConnection () de la classe URL.Les méthodes de cette classe permettent de créer un flux de données pour lire et/ou d'écrire dans lefichier désigné par une URL, mais aussi d'obtenir toute sorte d'information sur ce fichier (sa date dedernière modification, sa taille, son type,...).

Variables

protected URL urlprotected boolean doInputprotected boolean doOutputprotected boolean allowUserInteractionprotected boolean useCachesprotected long ifModifiedSinceprotected boolean connected

Page 175: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 4

Ces variables protected sont utilisées par les classes dérivées de la classe URLConnection.

Constructeur

protected URLConnection (URL url)

Méthodes

public URL getURL ()

Renvoie l'URL avec laquelle la connexion est faite.

public InputStream getInputStream () throws IOExceptionpublic OutputStream getOutputStream () throws IOException

Ces méthodes renvoient un flux de données en lecture ou en écriture à partir d'une connexion à uneURL. Une exception de classe UnknownServiceException (dérivant de la classe IOException) estdéclenchée si le protocole interdit l'accès en lecture ou en écriture à cette URL.

public int getContentLength ()

Renvoie la taille du fichier avec lequel la connexion est faite ou 0 si cette taille n'est pas connue.

public String getContentType ()public String getContentEncoding ()

Renvoie le type du contenu et son codage ou null si ces renseignements ne sont pas connus

public Object getContent () throws IOException

Renvoie un objet correspondant au contenu du fichier.

public long getDate ()public long getLastModified ()public long getExpiration ()

Renvoie la date à laquelle le fichier a été envoyé, sa date de dernière modification et sa date d'expirationou 0 si ces renseignements ne sont pas connus.

public String getHeaderField (String name)public int getHeaderFieldInt (String name, int default)public long getHeaderFieldDate (String name, long default)public String getHeaderFieldKey (int n)public String getHeaderField (int n)

Ces méthodes renvoient les renseignements correspondant aux clés contenues dans l'entête d'un fichier

public boolean getDoInput ()public boolean getDoOutput ()public boolean getUseCaches ()public boolean getAllowUserInteraction ()

Ces méthodes renvoient true, s'il est possible de lire ou d'écrire sur une connexion, si la connexionutilise le cache ou si elle autorise d'interagir avec l'utilisateur (pour lui demander par exemple un mot depasse). Par défaut, une connexion est ouverte en lecture.

public long getIfModifiedSince ()

Renvoie la durée de validité du fichier sur la connexion est faite.

public String getRequestProperty (String key)

Renvoie la valeur associée au mot-clé key par lequel une requête est reconnue.

public abstract void connect () throws IOException

Les classes dérivées de la classe URLConnection doivent implémenter cette méthode pour réaliser laconnexion avec une URL.

Page 176: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 5

public void setDoInput (boolean doinput)public void setDoOutput (boolean dooutput)public void setUseCaches (boolean usecaches)public void setAllowUserInteraction (boolean allowuserinteraction)public void setIfModifiedSince (long ifmodifiedsince)public void setRequestProperty (String key, String value)

Ces méthodes permettent d'autoriser l'accès en lecture ou en écriture à un fichier, l'utilisation du cache,...Elles ne peuvent pas être appelées quand la connexion est déjà ouverte.

public boolean getDefaultUseCaches ()public void setDefaultUseCaches (boolean defaultusecaches)public static boolean getDefaultAllowUserInteraction ()public static void setDefaultAllowUserInteraction (boolean defaultallowuserinteraction)public static String getDefaultRequestProperty (String key)public static void setDefaultRequestProperty (String key, String value)protected static String guessContentTypeFromName (String fname)protected static String guessContentTypeFromStream (InputStream is) throws IOException public static synchronized void setContentHandlerFactory (ContentHandlerFactory fac) throws SecurityException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de créationd'objets représentés dans un fichier suivant leur type mime, différent de celui fourni par défaut. Cetteméthode static ne peut être appelée qu'une seule fois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant la connexion.

Voici un exemple simple d'applet qui lit le texte contenu dans le fichier accessible à l'URLhttp://www.eteks.com/classes/hello.txt pour l'afficher à l'écran :

et le programme Java correspondant (à copier dans un fichier dénommé HelloFromNet.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.Graphics;import java.net.*;import java.io.*; public class HelloFromNet extends Applet{ String texteLu; // Méthode appelée par le système à l'initialisation de l'applet public void init () { try { // Création de l'URL http://www.eteks.com/classes/hello.txt URL urlFichierHello = new URL ("http", "www.eteks.com", "/classes/hello.txt"); // Ouverture d'une connexion et récupération d'un flux d'entrée URLConnection connexion = urlFichierHello.openConnection (); InputStream fluxFichier = connexion.getInputStream (); // Lecture du contenu du flux d'entrée byte contenuFichier [ ] = new byte [connexion.getContentLength ()]; int octetsLus = fluxFichier.read (contenuFichier); texteLu = new String (contenuFichier, 0, 0, octetsLus); // Fermeture de la connexion fluxFichier.close ();

Page 177: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 6

} catch (Exception e) { texteLu = "Probleme..."; } } // Méthode appelée par le système pour mettre à jour le dessin de l'applet public void paint (Graphics gc) { if (texteLu != null) // Affichage du texte lu gc.drawString(texteLu, 10, 20); }}

La classe java.net.URLEncoder

L'unique méthode encode () de cette classe est utile si vous voulez créer un formulaire en Java et enenvoyer les résultats au serveur pour être traité par exemple par un programme CGI. Cette méthodetransforme une chaîne de caractères au format x-www-form-urlencoded, c'est-à-dire que tous les espacessont remplacés par le signe + et tous les caractères différents des lettres de l'alphabet, des chiffres et ducaractère _ par leur code hexadécimal précédé du symbole %.

Méthode

public static String encode (String s)

Vous n'aurez normalement pas à utiliser les interfaces et les classes qui suivent, car la Machine VirtuelleJava fournit et gère automatiquement un certain nombre de protocoles et la création d'objet en fonctiondu contenu d'un fichier. Ces classes sont utilisées indirectement par les méthodes de la classesURLConnection.

L'interface java.net.URLStreamHandlerFactory

Cette interface est implémentée par les classes désirant gérer l'accès sous forme de flux de données à unou plusieurs protocoles. Elle est utilisée comme paramètre de la méthode setURLStreamHandlerFactory() de la classe URL, pour modifier le gestionnaire par défaut.

Méthode

public URLStreamHandler createURLStreamHandler (String protocol)

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract URLStreamHandler ounull si le protocole protocol est refusé ou n'est pas reconnu par ce gestionnaire. L'objet renvoyé doitpouvoir créer un flux de données à partir du protocole protocol et d'une URL.

La classe java.net.URLStreamHandler

Cette classe abstract est la super classe de toutes les classes qui gère la création d'un flux de données àpartir d'un protocole donné et d'une URL.La Machine Virtuelle Java fournit un ensemble de classes pour un certain nombre de protocoles. Cesclasses sont utilisées par défaut si la méthode setURLStreamHandlerFactory () de la classe URL n'a pasété appelée pour changer de gestionnaire de création de flux de données.

Constructeur

public URLStreamHandler ()

Méthodes

protected abstract URLConnection openConnection (URL url) throws IOException

Page 178: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 7

Cette méthode doit ouvrir un connexion avec l'URL url et renvoyer une instance d'une classe dérivantde la classe abstract URLConnection pour permettre d'accéder à l'URL sous forme de flux de données.

protected void parseURL (URL url, String spec, int start, int limit)

Analyse la chaîne de caractères spec représentant une URL entre les caractères start et limit (exclu),pour compléter l'instance url de la classe URL. Cette méthode analyse la chaîne spec en respectant lasyntaxe du protocole http, et donc s'attend à ce que start désigne le caractère suivant le symbole : duprotocole, et limit le caractère # précédant la référence à une ancre.Outrepassez cette méthode si vous voulez qu'elle analyse différemment la chaîne spec.

protected String toExternalForm (URL url)

Renvoie une chaîne de caractères correspondant à l'URL mémorisée par url.

protected void setURL (URL url, String protocol, String host, int port, String file, String ref)

Permet de modifier le protocole protocol, l'hôte host, le port port, le chemin d'accès au fichier file etla référence ref mémorisés par l'objet url.

L'interface java.net.ContentHandlerFactory

Cette interface est implémentée par les classes désirant gérer le contenu d'un fichier suivant leur typemime (par exemple image/gif ou text/plain). Elle est utilisée comme paramètre de la méthodesetContentHandlerFactory () de la classe URLConnection, pour modifier le gestionnaire par défaut.

Méthode

public ContentHandler createContentHandler (String mimetype)

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract ContentHandler. Cetobjet doit pouvoir créer un objet correspondant au contenu d'un fichier de type mime mimetype.

La classe java.net.ContentHandler

Cette classe abstract est la super classe de toutes les classes qui gère la création d'un objetcorrespondant au contenu d'un fichier d'un type mime donné.La Machine Virtuelle Java fournit un ensemble de classes pour certains types mime. Ces classes sontutilisées par défaut si la méthode setContentHandlerFactory () de la classe URLConnection n'a pas étéappelée pour changer de gestionnaire de création d'objet.

Constructeur

public ContentHandler ()

Méthode

public abstract Object getContent (URLConnection urlc) throws IOException

Cette méthode doit renvoyer un objet correspondant au contenu du fichier avec lequel la connexionurlc a été établie.

L'architecture client-serveur

Grâce à une URL, l'accès à un fichier ou une ressource est géré de manière simple : que le fichier soitsur un disque local ou sur Internet, il vous suffit de respecter les règles de construction d'une URL et letour est joué.Mais Java permet aussi de gérer des accès réseau plus complexe, pour réaliser par exemple un dialogueentre deux ordinateurs d'un réseau. Ce dialogue est basé sur l'architecture client-serveur, dont voici unrappel des grands principes.

Page 179: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 8

Principe

Comme la programmation orientée objet, l'architecture client-serveur est une technologie informatiquetrès utilisée actuellement.Elle est surtout connue dans le monde des SGBD (Système de Gestion de Base de Données ), mais elles'applique aussi à d'autres domaines comme Internet, les terminaux X utilisés sous UNIX (que l'onappelle aussi serveurs X).Son principe est assez simple mais ce sont des exemples qui vous permettront de mieux comprendrecomment cette architecture s'applique concrètement.

Comme son nom l'indique, le client-serveur implique qu'il y ait au moins deux acteurs en jeu, un clientet un serveur , qui communiquent entre eux, souvent à travers un réseau.Un serveur est un programme ou par extension une machine programmée pour rendre toujours le mêmeservice , suite à une requête qui lui est adressée.Un client est un programme ou par extension une machine qui demande à un serveur un service , en luiadressant une requête .Gardez-bien toujours en tête ce mot service , car c'est souvent en pensant à qui rend service à l'autre quevous arriverez à déterminer qui est le client du serveur dans une architecture client-serveur.

Exemples d'utilisation

figure 12. Architecture client-serveur sur Internet

Internet que vous utilisez en ce moment, est un bon exemple d'architecture client-serveur : Les sites quevous consultez sont souvent appelés aussi des serveurs, car les programmes qui les gèrent rendenttoujours le même service au client qu'est votre navigateur.Quel service ? Le programme d'un serveur est en attente que vous lui demandiez une page du site quevous voulez visualiser. Quand votre requête lui parvient, il vous renvoie cette page. Votre navigateur deson côté est un client du serveur car il lui demande une page qu'il visualise une fois téléchargée.

Le client-serveur est souvent utilisé pour accéder à de grandes bases de données utilisées par plusieursutilisateurs. La base de données est stockée sur une machine utilisée comme serveur. Le programme surce serveur a pour mission de répondre à des requêtes SQL que lui adressent des clients. Les requêtesSQL que le serveur reçoit lui permettent de modifier ou d'interroger la base de données qu'il gère, et derenvoyer au client la réponse attendue. Le client est généralement une machine de type PC dont leprogramme est utilisé pour mettre en page les réponses reçues du serveur.

Le principale avantage de cette architecture est qu'elle permet de séparer complètement le serveur quigénéralement gère le stockage de données, du client qui cherche à y accéder.Ainsi, dans le cas d'Internet, il est possible d'avoir des navigateurs qui tournent sous différents systèmeset même des logiciels de navigation différents sur un même système. Tous ces navigateurs sont desclients du serveur d'un site Internet auquel ils peuvent accéder simultanément.A l'opposé, le serveur d'un site Internet peut fonctionner sur n'importe quel système, que vous n'avezd'ailleurs pas à connaître. Ce qu'il compte, c'est qu'il réponde correctement à vos requêtes, quand vousvoulez voir une page hébergée sur ce site.

Page 180: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 9

La clé de voûte qui permet à ce système de fonctionner sans que le client et le serveur n'aient à savoircomment ils fonctionnent l'un l'autre est l'utilisation d'un protocole commun. Ce protocole établit lanorme que doit respecter le client et le serveur pour communiquer entre eux : comment établir unecommunication, comment un client doit envoyer une requête à un serveur et comment un serveur doitrépondre à la requête du client.

Protocoles

Deux types de protocoles peuvent être utilisés sur Internet :

TCP (Transport Control Protocol ) : Sans que vous ayez à le savoir, ce protocole est utilisé pard'autres protocoles de plus haut niveau comme HTTP (HyperText Transfer Protocol ) et FTP (FileTransfer Protocol ).Ce protocole permet d'établir une connexion entre deux machines (un client et un serveur) : Unefois la connexion établie, les programmes client et serveur peuvent s'échanger des données, et ceprotocole garantit que les données émises d'une machine arriveront sur l'autre, et dans l'ordre oùelles ont été émises. Ainsi suite à une requête, le transfert d'un fichier peut être effectué en étantassuré de son intégrité à l'arrivée.Les classes URL et URLConnection utilisent TCP implicitement et permettent à un client d'accéder nemanière simple à un fichier ou une ressource d'un serveur Internet. Ces classes sont généralementsuffisantes pour les communications utilisant les protocoles comme HTTP ou FTP. Mais Javapermet aussi de programmer des communications quelconques entre un client et un serveur enutilisant TCP, grâce aux classes Socket et ServerSocket. UDP (User Datagram Protocol ) : A l'opposé de TCP, ce protocole est utilisé pour transmettre desdonnées entre deux machines sans garantir que ces données arriveront à destination et dans l'ordreoù elles ont été émises. Ces données sont envoyées par paquets appelés aussi des datagrammes.Ce protocole évite la contrainte d'avoir à établir et maintenir une connexion entre les deuxmachines.Il peut être utile par exemple pour un serveur envoyant les tics d'une horloge sur requête d'unclient. Si un datagramme contenant une heure donnée ne parvient pas au client ou sonacheminement est retardé, il est inutile de s'en inquiéter car au tic suivant le serveur renverra unnouveau datagramme contenant l'heure actualisée. Si ces datagrammes arrivent dans le désordre, ilsuffira au client de ne pas tenir compte des datagrammes contenant une heure obsolète.Les classes DatagramSocket et DatagramPacket permet d'utiliser UDP pour programmer ce type decommunication entre un client et un serveur.

Port

Les serveurs des sites auxquels vous vous connectez sur Internet sont accessibles grâce à unmnémonique qui est le nom de la machine hôte (par exemple java.sun.com, www.yahoo.fr). Chaquemnémonique est associé à un identifiant numérique représentant la machine hôte qui héberge un serveur.Cet identifiant est un nombre 32 bits appelé adresse IP que l'on note généralement sous la forme d'unesuite de 4 nombres séparés par des points (par exemple 194.51.83.2) : certains navigateurs affichentdans la barre d'état l'adresse IP de l'hôte d'un site, quand vous essayez de vous connectez à ce site.Chaque machine reliée à Internet possède une adresse IP différente qui permet de la désigner de manièreunique sur le réseau Internet.

Tous les systèmes d'exploitation permettent de faire fonctionner plusieurs programmes en même tempssur une machine. Si plusieurs serveurs sont hébergés sur une même machine, ils vont devoir partagerl'accès physique au réseau sur cette machine. Un deuxième niveau d'identification est donc nécessairepour désigner le programme avec lequel vous voulez vous connecter sur une machine donnée.A chaque programme désirant communiquer sur Internet est associé un port unique, qui est un nombre16 bits compris entre 0 et 65535. Les ports dont le nombre est compris entre 0 et 1023 sont réservés àdes services particuliers et ne doivent pas être utilisés par les serveurs que vous programmez.

Globalement, un programme est identifié sur Internet par l'adresse IP de la machine sur lequel ilfonctionne et le numéro du port auquel il est associé.

Page 181: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 10

Accès via les sockets

Chaque extrémité d'une connexion entre un client et un serveur est appelée un socket. Un socket estune représentation logique du point de branchement d'un programme au réseau.

Pour programmer une architecture client serveur utilisant le protocole TCP (Transport Control Protocol ), ilvous faut réaliser, grâce aux classes ServerSocket et Socket qui suivent, un programme faisant office deserveur sur une machine hôte et un autre utilisé comme client sur une autre machine.Pour vous permettre de tester les programmes serveur et client sur la même machine, le client peutessayer de se connecter à la machine localhost qui représente la machine locale.

figure 13. Utilisation des sockets en Java

Comme le montre la figure précédente, le programme serveur doit créer une instance de la classeServerSocket en précisant le numéro de port sur lequel il attend les demandes de connexion desprogrammes clients. Le serveur appelle ensuite la méthode accept () de cette classe pour se mettre enattente de demande de connexion.Une fois qu'un client s'est connecté, une instance de la classe Socket est renvoyée. Le serveur peut alorsgrâce au méthodes de cette classe obtenir des flux de données en lecture et en écriture pourcommuniquer avec le programme client.

Le programme client de son côté se connecte à un programme serveur en créant une instance de laclasse Socket, en précisant l'adresse Internet de la machine hôte et le numéro de port sur lequel leserveur attend les demandes de connexions.Comme pour le programme serveur, une fois qu'il a obtenu une instance cette classe, il peut obtenir desflux de données en lecture et en écriture.

Chacun des programmes serveurs et clients pouvant envoyer et lire des données, tout est alors prêt pourcommuniquer des données dans les deux sens entre les programmes.Pour un fonctionnement correct, il suffit que quand le client écrit sur le flux de données de sortie deson socket, le serveur soit en lecture sur le flux de données d'entrée de son socket et inversement.

La classe java.net.InetAddress

Cette classe final permet de manipuler l'adresse Internet d'une machine hôte. Elle est utilisée par lesclasses ServerSocket, Socket et DatagramPacket.

Méthodes

public static synchronized InetAddress getByName (String host) throws UnknownHostException

Renvoie une instance de la classe InetAddress représentant l'adresse Internet de la machine host.

public static synchronized InetAddress [ ] getAllByName (String host) throws UnknownHostException

Renvoie toutes les adresses Internet de la machine host.

public static InetAddress getLocalHost () throws UnknownHostException

Page 182: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 11

Renvoie une instance de la classe InetAddress représentant l'adresse Internet de la machine locale. Trèspratique pour tester sur une même machine les programmes client et serveur. Equivalent à getByName(null) ou getByName ("localhost").

public String getHostName ()

Renvoie le nom de la machine hôte.

public byte [ ] getAddress ()

Renvoie l'adresse IP mémorisée par une instance de la classe InetAddress. Le tableau renvoyé contientles 4 nombres d'une adresse IP qui sont séparées par des points (par exemple 194.51.83.2).

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unobjet de classe InetAddress à un objet ou renvoyer une chaîne de caractères décrivant une adresseInternet.

Exemples

Applets EchoClient et PaperBoardClient .

La classe java.net.Socket

Cette classe final permet de manipuler un socket. Vous pouvez en obtenir une instance de deuxmanières différentes, suivant que vous réalisez le programme client ou le serveur :

Quand un programme client essaye de se connecter à un serveur, il doit créer une instance de laclasse Socket grâce à l'un des constructeurs de cette classe (par exemple new Socket("www.eteks.com", 26197)). Chacun de ses constructeurs prend comme paramètres l'adresseInternet de la machine hôte du serveur et le numéro de port sur lequel le serveur est en attente deconnexion avec un client. Quand un programme serveur en attente sur la méthode accept () reçoit une demande deconnexion avec un programme client, cette connexion est créée puis accept () renvoie uneinstance de la classe Socket.

Une fois obtenue une instance de la classe Socket, il est possible d'obtenir côté client comme côtéserveur un flux de données d'entrée et un flux de données de sortie, grâce aux méthodesgetInputStream () et getOutputStream (). Ces méthodes renvoient des instances de classes dérivantdes classes InputStream et OutputStream dont les méthodes permettent de de lire et d'envoyer desdonnées entre le client et le serveur.

Constructeurs

public Socket (String host, int port) throws UnknownHostException, IOExceptionpublic Socket (String host, int port, boolean stream) throws IOException

Ces constructeurs permettent de créer une instance de la classe Socket et d'obtenir pour un programmeclient une connexion avec le programme serveur de la machine host en attente sur le port port. Sistream (égal à true par défaut) est égale à false, un socket de datagrammes est créé.

public Socket (InetAddress address, int port) throws IOExceptionpublic Socket (InetAddress address, int port, boolean stream) throws IOException

Ces constructeurs fonctionnent comme les deux premiers, mais prennent comme premier paramètre uneinstance de la classe InetAddress.

Page 183: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 12

Méthodes

public InputStream getInputStream () throws IOExceptionpublic OutputStream getOutputStream () throws IOException

Ces méthodes permettent d'obtenir un flux de données en lecture ou un flux de données en écriture,pour communiquer avec le socket distant.

public synchronized void close () throws IOException

Ferme la connexion avec le socket distant.

public InetAddress getInetAddress ()public int getPort ()

Ces méthodes renvoient l'adresse Internet et le port du socket distant auquel le socket est connecté.

public int getLocalPort ()

Renvoie le port local sur lequel le socket est connecté.

public static synchronized void setSocketImplFactory (SocketImplFactory fac) throws IOException, SecurityException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de créationde sockets, différent de celui fourni par défaut. Cette méthode static ne peut être appelée qu'une seulefois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant le socket.

Exemples

Applications EchoServer et PaperBoardServer .Applets EchoClient et PaperBoardClient .

La classe java.net.ServerSocket

Cette classe final est utilisée par un programme serveur pour gérer l'attente de demande de connexiond'un programme client sur un port de la machine hôte du serveur.

Constructeurs

public ServerSocket (int port) throws IOExceptionpublic ServerSocket (int port, int count) throws IOException

Ces constructeurs permettent de créer un socket de serveur en attente sur le port port. Pour autoriser laconnexion anonyme d'un client, utilisez un port est égal à 0. count (égal à 50 par défaut) permet despécifier le nombre maximum de demande de connexions en attente que le serveur termine d'exécuter laméthode accept ().

Méthodes

public Socket accept () throws IOException

Attend la demande de connexion d'un programme client, et renvoie un socket une fois la connexionétablie.

public void close () throws IOException

Ferme le socket du serveur.

public InetAddress getInetAddress ()public int getLocalPort ()

Page 184: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 13

Ces méthodes renvoient l'adresse Internet et le port local sur lequel le socket du serveur est connecté.

public static synchronized void setSocketFactory (SocketImplFactory fac) throws IOException

Si le gestionnaire de sécurité l'autorise, cette méthode permet de positionner un gestionnaire de créationde socket de serveur, différent de celui fourni par défaut. Cette méthode static ne peut être appeléequ'une seule fois.

public String toString ()

Méthode de la classe Object outrepassée pour renvoyer une chaîne de caractères décrivant le serveur.

Exemples

Applications EchoServer et PaperBoardServer .

Le client serveur d'écho

Ce premier exemple de client serveur se décompose en deux programmes : une application pour leserveur et une applet pour le client. Vous pouvez tester cet exemple sur votre ordinateur car l'applet seconnecte sur le serveur de la machine locale, où vous pouvez lancer l'application serveur.Cet exemple réalise une opération très simple d'écho : le serveur ne fait que renvoyer en l'état lesdonnées que le client lui envoie, jusqu'à ce qu'il rencontre un retour chariot.Il faut lancer l'application du serveur avant de lancer l'applet du client.

Voici le programme du serveur. Recopiez-le dans un fichier EchoServer.java , que vous compilez avecl'instruction javac EchoServer.java pour ensuite l'exécuter avec java ou Java Runner , grâce àl'instruction java EchoServer : :

import java.net.*;import java.io.*; public class EchoServer{ public static void main (String args []) { try { // Création d'un serveur sur le port 13267 ServerSocket server = new ServerSocket (13267); // Attente de la connexion d'un client Socket socket = server.accept (); System.out.println ("Connexion sur le socket : " + socket); // Récupération des flux d'entrés et de sortie InputStream fluxEntree = socket.getInputStream (); OutputStream fluxSortie = socket.getOutputStream (); char caractereLu; // Renvoie au client de chaque caractère lu // jusqu'à ce que ce caractère soit un retour chariot while ((caractereLu = (char)fluxEntree.read ()) != '\n') fluxSortie.write (caractereLu); server.close (); } catch (IOException e) { System.out.println (e); } }}

Une fois programmé le serveur, il faut réaliser un programme client. Celui-ci est une applet simple quienvoie au serveur tous les caractères saisis au clavier et affiche les caractères lus à partir du serveur sousla forme d'une chaîne de caractères (à mettre dans un fichier EchoClient.java ) :

Page 185: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 14

import java.applet.Applet;import java.awt.*;import java.net.*;import java.io.*; public class EchoClient extends Applet{ String texteLu = ""; InputStream fluxEntree; OutputStream fluxSortie; // Méthode appelée par le système à l'initialisation de l'applet public void init () { try { // Récupération de l'adresse de l'hôte local InetAddress adresse = InetAddress.getLocalHost (); // Ouverture d'une connexion sur le port 13267 de cet hôte Socket socket = new Socket (adresse, 13267); // Récupération des flux d'entrés et de sortie fluxEntree = socket.getInputStream (); fluxSortie = socket.getOutputStream (); } catch (IOException e) { texteLu = "Probleme de connexion"; } } // Méthode appelée par le système pour mettre à jour le dessin de l'applet public void paint (Graphics gc) { gc.drawString (texteLu, 10, 20); } // Méthode appelée le système quand une touche du clavier est enfoncée public boolean keyDown (Event evt, int key) { if (fluxSortie != null) try { // Envoie au serveur du caractère lu puis relecture fluxSortie.write(key); char caractereLu = (char)fluxEntree.read (); // Ajout du caractère et redessin de l'applet texteLu += caractereLu; repaint(); } catch (IOException e) { } return true; }}

Voici un exemple de code HTML qui vous permettre d'appeler cette applet (à mettre par exemple dansun fichier EchoClient.html et à exécuter avec appletviewer ou Applet Runner , grâce à l'instructionappletviewer EchoClient.html) :

<applet code="EchoClient" width=200 height=30> </applet>

Le paper board Internet

Ce deuxième exemple de client serveur beaucoup plus élaboré se décompose toujours en deuxprogrammes : une application pour le serveur et une applet pour le client.Chaque utilisateur visualisant cette applet peut partager un dessin qu'il dessine avec la souris, avec toutesles autres personnes connectées au serveur. Pour saisir un élément de dessin, il suffit de déplacer lasouris en maintenant son bouton enfoncé.Pour permettre plusieurs connexions simultanées de clients au serveur, ce dernier lance un thread gérantchaque connexion. Chacun de ces threads a pour mission d'attendre les requêtes de chacun des clients.Quatre types différents de requêtes sont gérées :

Page 186: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 15

AJOUT : Le client envoie cette requête pour indiquer au serveur que l'utilisateur de l'applet client asaisi une nouvelle suite de points (polyline ), avec la souris. Cette requête est suivie d'une liste devaleurs entières représentant les couples x y de chacun des points de la polyline. Le serveur ajoutecette liste à l'ensemble des polylines qu'il a déjà reçues. LISTE : Le client envoie cette requête pour demander au serveur l'ensemble des polylinesactuellement enregistrées sur le serveur. Le serveur lui renvoie chacune des listes de pointsséparée par des tabulations (caractère '\t'). Envoyée à intervalle régulier, cette requête permet àchacun des clients du serveur de mettre à jour sa zone d'affichage en affichant toutes les polylinesqu'ont saisies l'ensemble des utilisateurs de l'applet client connectée au serveur. CONNEXION : Le client envoie cette requête pour demander le nombre actuelle de clients connectésau serveur. Ce dernier renvoie ce nombre. FIN : Le client envoie cette requête pour indiquer au client son intention de se déconnecter duserveur.

Pour tester cette applet, il faut une connexion Internet active. Cette version du manuel étant prévuepour fonctionner off-line, vous pouvez éventuellement la tester surhttp://www.eteks.com/coursjava/net10.html#PaperBoard.

Voici le programme du serveur qui tourne sur www.eteks.com (A mettre dans un fichierPaperBoardServer.java , et exécuté avec java ou Java Runner ) :

import java.net.*;import java.io.*;import java.util.*; public class PaperBoardServer implements Runnable{ public static int port = 26197; public static String requeteFin = "FIN"; public static String requeteListe = "LISTE"; public static String requeteAjout = "AJOUT"; public static String requeteConnexion = "CONNEXION"; private static ServerSocket serveur; public static void main (String args []) { if (lancerServeur () == null) System.exit (-1); } // lancerServeur () peut être appelée par une servlet // pour éviter de lancer une Machine Virtuelle supplémentaire // sur le serveur où est hébergé le site public static ServerSocket lancerServeur () { if (serveur == null) try { // Création d'un serveur sur le port 26197 serveur = new ServerSocket (port); // Lancement d'un thread d'attente de connexion new Thread (new PaperBoardServer ()).start (); } catch (IOException e)

Page 187: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 16

{ System.out.println (e); return null; } return serveur; } public void run () { try { // Boucle sans fin d'attente de connexion while (true) { // Attente de la connexion d'un client Socket socket = serveur.accept (); // Démarrage d'un nouveau thread pour gérer la connexion new ThreadSocket (socket).start (); } } catch (IOException e) { System.out.println (e); } finally { try { // Fermeture du serveur serveur.close (); serveur = null; } catch (IOException e) { System.out.println (e); } } }} class ThreadSocket extends Thread{ static private Vector listePolylines = new Vector (100); static private int connexions; private Socket socket; public ThreadSocket (Socket socket) { this.socket = socket; } public void run () { try { // Récupération des flux d'entrés et de sortie DataInputStream fluxEntree = new DataInputStream ( new BufferedInputStream (socket.getInputStream ())); PrintStream fluxSortie = new PrintStream ( new BufferedOutputStream (socket.getOutputStream ()), true); // Augmentation du nombre de connexions au serveur connexions++; String chaineLue; // Lecture sur le flux d'entrée tant que la requête FIN n'est pas arrivée while ( (chaineLue = fluxEntree.readLine ()) != null && !chaineLue.equals (PaperBoardServer.requeteFin)) { if (chaineLue.startsWith (PaperBoardServer.requeteListe)) { // Si la liste des polylines est demandée, elles sont // renvoyées séparées par des tabulations for (Enumeration e = listePolylines.elements (); e.hasMoreElements (); ) fluxSortie.print (e.nextElement ().toString () + '\t'); fluxSortie.write ('\n');

Page 188: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 17

} else if (chaineLue.equals (PaperBoardServer.requeteConnexion)) { // Renvoi du nombre de connexions au serveur fluxSortie.print (String.valueOf (connexions)); fluxSortie.write ('\n'); } else if (chaineLue.startsWith (PaperBoardServer.requeteAjout)) { // Si le vecteur arrive à saturation, il est vidée // (ceci pour éviter que le dessin ne devienne trop dense) if (listePolylines.size () == listePolylines.capacity ()) listePolylines.removeAllElements (); // La nouvelle polyline reçue est ajoutée à la liste listePolylines.addElement ( chaineLue.substring (PaperBoardServer.requeteAjout.length ())); } } fluxEntree.close (); fluxSortie.close (); socket.close (); } catch (IOException e) { System.out.println (e); } connexions--; }}

Une fois programmé le serveur, il faut réaliser un programme client. Celui-ci est l'applet ci-dessus quienvoie au serveur les polylines saisies par l'utilisateur, et demande au serveur toutes les secondes la listecourante de toutes les polylines que celui-ci mémorise (à mettre dans un fichier PaperBoardClient.java ) :

import java.applet.Applet;import java.awt.*;import java.net.*;import java.io.*;import java.util.*; public class PaperBoardClient extends Applet implements Runnable{ private String message; private Socket socket; private DataInputStream fluxEntree; private PrintStream fluxSortie; private Vector listePolylines = new Vector (100); private Polygon polylineCourante; private int connexions; // Méthode appelée par le système à l'affichage de l'applet public void start () { setBackground (Color.white); try { // Récupération de l'adresse de l'hôte www.eteks.com InetAddress adresse = InetAddress.getByName ("www.eteks.com"); // Ouverture d'une connexion sur le port 26197 de cet hôte socket = new Socket (adresse, PaperBoardServer.port); // Récupération des flux d'entrés et de sortie fluxEntree = new DataInputStream ( new BufferedInputStream (socket.getInputStream ())); fluxSortie = new PrintStream ( new BufferedOutputStream (socket.getOutputStream ()), true); // Lancement d'un thread qui interroge à intervalle régulier // la liste des polylines enregistrées sur le serveur new Thread (this).start (); } catch (IOException e)

Page 189: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 18

{ message = "Probleme de connexion avec le serveur"; } } // Méthode appelée par le système à la disparition de l'applet public void stop () { try { // Envoi d'une requête FIN et fermeture des flux fluxSortie.println (PaperBoardServer.requeteFin); fluxSortie.close (); fluxEntree.close (); socket.close (); } catch (IOException e) { } fluxSortie = null; } public void run () { try { while (fluxSortie != null) { // Envoi d'une requête CONNEXION pour récupérer le // nombre de clients connectés au serveur fluxSortie.print (PaperBoardServer.requeteConnexion); fluxSortie.write ('\n'); message = fluxEntree.readLine () + " connexions"; // Envoi d'une requête LISTE pour récupérer // la liste de toutes les polylines du serveur fluxSortie.print (PaperBoardServer.requeteListe); fluxSortie.write ('\n'); String liste = fluxEntree.readLine (); // Vidange de la liste pour la remettre à jour listePolylines.removeAllElements (); StreamTokenizer tokens = new StreamTokenizer ( new StringBufferInputStream (liste)); tokens.parseNumbers (); tokens.ordinaryChar ('\t'); tokens.whitespaceChars (' ', ' '); // Décodage de la liste de points while (tokens.nextToken () != StreamTokenizer.TT_EOF) { Polygon polyline = new Polygon (); // Récupération des couples de valeurs (x,y) // d'une polyline jusqu'à la prochaine tabulation while (tokens.ttype != '\t') { int x = (int)tokens.nval; tokens.nextToken (); int y = (int)tokens.nval; tokens.nextToken (); polyline.addPoint (x, y); } // Ajout de la polyline à la liste listePolylines.addElement (polyline); } repaint (); // Arrête le thread pendant 1 s avant de lancer // une nouvelle demande de mise à jour Thread.sleep (1000); } } catch (InterruptedException e) { } catch (IOException e) { }

Page 190: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 19

} // Méthode appelée par le système pour mettre à jour le dessin de l'applet public void paint (Graphics gc) { if (message != null) gc.drawString (message, 10, 20); // Dessin de toutes les polylines // et de la polyline courante si elle existe for (Enumeration e = listePolylines.elements (); e.hasMoreElements (); ) drawPolyline (gc, (Polygon)e.nextElement ()); if (polylineCourante != null) drawPolyline (gc, polylineCourante); } private void drawPolyline (Graphics gc, Polygon polyline) { for (int i = 1; i < polyline.npoints; i++) gc.drawLine (polyline.xpoints [i - 1], polyline.ypoints [i - 1], polyline.xpoints [i], polyline.ypoints [i]); } // Les méthodes mouseDown (), mouseDrag (), mouseUp () sont // appelées par le système à l'enfoncement du bouton de la souris, // au déplacement du pointeur, et au relâchement du bouton public boolean mouseDown (Event evt, int x, int y) { polylineCourante = new Polygon (); polylineCourante.addPoint (x, y); return true; } public boolean mouseDrag (Event evt, int x, int y) { polylineCourante.addPoint (x, y); paint (getGraphics ()); return true; } public boolean mouseUp (Event evt, int x, int y) { polylineCourante.addPoint (x, y); // Construction d'une requête AJOUT avec la liste des points // de la nouvelle polyline fluxSortie.print (PaperBoardServer.requeteAjout); for (int i = 0; i < polylineCourante.npoints; i++) fluxSortie.print (String.valueOf (polylineCourante.xpoints [i]) + ' ' + polylineCourante.ypoints [i] + ' '); fluxSortie.write ('\n'); listePolylines.addElement (polylineCourante); paint (getGraphics ()); return true; }}

Vous pouvez tester éventuellement ce programme sur votre machine locale en lançant le serveurPaperBoardServer , et en remplaçant dans l'applet PaperBoardClient le nom du site Internet"www.eteks.com" par "localhost".Ce programme est inspiré du Groupboard disponible à l'adresse http://www.groupboard.com.

Vous n'aurez normalement pas à utiliser la classe et l'interface qui suivent, car elles sont utiles pourréaliser l'implémentation des sockets que la Machine Virtuelle Java fournit.

La classe java.net.SocketImpl

Cette classe abstract permet de gérer un socket et la connexion au socket d'un serveur. Elle est utilisée

Page 191: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 20

pour les sockets côté client comme côté serveur. Elle comporte des variables et des méthodesprotected qui sont utilisées pour réaliser les services des méthodes des classes précédentes Socket etServerSocket.

Variables

protected FileDescriptor fdprotected InetAddress addressprotected int portprotected int localport

Constructeur

public SocketImpl ()

Méthodes

protected abstract void create (boolean stream) throws IOExceptionprotected abstract void connect (String host, int port) throws IOExceptionprotected abstract void connect (InetAddress address, int port) throws IOExceptionprotected abstract void bind (InetAddress host, int port) throws IOExceptionprotected abstract void listen (int count) throws IOExceptionprotected abstract void accept (SocketImpl s) throws IOExceptionprotected abstract InputStream getInputStream () throws IOExceptionprotected abstract OutputStream getOutputStream () throws IOExceptionprotected abstract int available () throws IOExceptionprotected abstract void close () throws IOExceptionprotected FileDescriptor getFileDescriptor ()protected InetAddress getInetAddress ()protected int getPort ()protected int getLocalPort () public String toString ()

L'interface java.net.SocketImplFactory

Cette interface est implémentée par les classes désirant gérer la création de sockets. Elle est utiliséecomme paramètre des méthodes setSocketImplFactory () de la classe Socket et setSocketFactory ()de la classe ServerSocket, pour modifier le gestionnaire par défaut.

Méthode

public SocketImpl createSocketImpl ()

Cette méthode doit renvoyer un objet dont la classe dérive de la classe abstract SocketImpl.

Accès via les datagrammes

Pour programmer une architecture client serveur utilisant le protocole UDP (User Datagram Protocol ), ilfaut utiliser les classes DatagramPacket représentant un paquet de données (ou datagramme) à recevoirou envoyer, et DatagramSocket utilisé pour recevoir et envoyer des datagrammes.

Contrairement au protocole TCP, le protocole UDP ne maintient pas de connexion permanente entredeux machines. Chaque datagramme est indépendant l'un de l'autre : il comporte un tableau de données,l'adresse Internet et le port de la machine à laquelle il est destiné.

La classe java.net.DatagramPacket

Cette classe final représente un datagramme. Le premier constructeur est utilisé pour créer undatagramme à recevoir, le second pour créer un datagramme à envoyer à une machine.

Constructeurs

Page 192: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les accès au réseau Page: 21

public DatagramPacket (byte ibuf [ ], int ilength)

Construit une instance de la classe DatagramPacket utilisé pour recevoir un datagramme dont les paquetsde données de longueur ilength seront stockées dans le tableau ibuf. Si le datagramme reçu est pluslong que ilength, les données restantes ne sont pas recopiées dans ibuf.

public DatagramPacket (byte ibuf [ ], int ilength, InetAddress iaddr, int iport)

Construit une instance de la classe DatagramPacket utilisé pour envoyer un paquet de données ibuf delongueur ilength, au port iport d'une machine d'adresse Internet iaddr.

Méthodes

public InetAddress getAddress ()

Renvoie l'adresse Internet de la machine dont provient ou auquel est destiné ce datagramme.

public int getPort ()

Renvoie le port de la machine dont provient ou auquel est destiné ce datagramme.

public byte[] getData ()public int getLength ()

Ces méthodes renvoient le tableau où sont stockées les données d'un datagramme et la longueur desdonnées à recevoir (ou reçues) ou à envoyer.

La classe java.net.DatagramSocket

Cette classe permet de recevoir et envoyer des datagrammes, grâce aux méthodes receive () et send ().

Constructeurs

public DatagramSocket () throws SocketException

Construit une instance de la classe DatagramSocket. Le port utilisé pour recevoir ou envoyer desdatagrammes est le premier disponible sur la machine locale.

public DatagramSocket (int port) throws SocketException

Construit une instance de la classe DatagramSocket. Le port port sur la machine locale est utilisé pourrecevoir ou envoyer des datagrammes.

Méthodes

public int getLocalPort ()

Renvoie le port de la machine locale sur lequel l'envoi ou la réception de datagrammes s'effectue.

public void synchronized receive (DatagramPacket packet) throws IOException

Permet de recevoir un paquet de données dans le datagramme packet. Cette méthode met en attente lethread courant jusqu'à réception d'un datagramme.

public void send (DatagramPacket packet) throws IOException

Permet d'envoyer le datagramme packet.

public synchronized void close ()

Ferme le socket.

protected synchronized void finalize ()

Page 193: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 1

Les applications et les applets

Les applications JavaLes applets

L'intégration des applets dans les navigateursTransformer une applet en application

Ce chapitre décrit les applications Java et le package java.applet de Java 1.0 qui rassemble les classespermettant de programmer une applet Java et de l'intégrer dans un navigateur.

Les applications Java

Comme il est décrit au premier chapitre, l'environnement Java vous permet de développer principalementdeux types de programmes : des applications Java ou des applets Java.

Les applications sont comparables à tout programme écrit dans un autre langage. Le point d'entrée d'uneapplication Java est la méthode main () de la classe donnée en argument à la commande java etrespectant la déclaration suivante :

public static void main (String [ ] args)

Comme n'importe quelle classe public ClasseExec qui définit cette méthode peut être exécutée par laMachine Virtuelle Java, vous pouvez ajouter une méthode main () à une ou plusieurs classes utiliséesdans un même programme. Ceci permet de tester individuellement chacune de ces classes.Attention, cette méthode est static et la Machine Virtuelle Java ne crée donc aucune instance de laclasse ClasseExec.Les arguments passés après le nom de la classe, comme dans la ligne de commande java ClasseExecarg0 arg1 sont mémorisés dans le tableau args (args [0] mémorise la chaîne arg0).

La méthode main () peut être suivie d'une clause throws pour citer toutes les classes d'exceptionsqu'elle n'intercepte pas. Ceci est pratique quand vous voulez écrire de petits programmes de test sansvous soucier du traitement de certaines exceptions.

De manière comparable au C, le point d'entrée d'un programme Java, est la méthode static main ()définie par la classe passée en argument à l'interpréteur Java.

La Machine Virtuelle Java rend la main au système une fois terminée l'exécution de la méthode main(), si et seulement si plus aucun thread n'est vivant, excepté pour les threads en tâche de fond(daemon ).Vous pouvez aussi utiliser la méthode exit () de la classes System à tout moment pour forcer laMachine Virtuelle à rendre la main.Pour sa propre gestion, la bibliothèque AWT crée un ensemble de threads aussitôt qu'elle est utilisé.Comme ces thread ne sont pas des daemons , il faut donc se servir de la méthode exit () pour forcerla fin d'un programme utilisant AWT.

Les applets

Caractéristiques

Les applets sont des applications un peu spéciales et fonctionnent différemment des applications Java.En voici les principales caractéristiques :

Page 194: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 2

La classe d'une applet doit obligatoirement dérivé de la classe Applet. Une applet de classe ClasseApplet est lancée grâce à la balise (tag ) <APPLET CODE=ClasseApplet...> défini dans un fichier HTML . Différents paramètres peuvent être passés à une applet grâce aux balise <PARAM NAME="Param"VALUE="ValueParam"> inclus après la balise <APPLET ...>. Une instance de la classe de l'applet demandée est créée pour chaque balise <APPLET ...>. Une applet n'a pas un unique point d'entrée comme pour les applications : les méthodesoutrepassées init (), start (), stop () et destroy () d'une classe d'applet ClasseApplet sontappelées respectivement à la création de l'applet ClasseApplet, son affichage, son effacement et sadestruction.De plus, pour chaque balise <APPLET CODE=ClasseApplet ...>, une instance de la classeClasseApplet est créée. Une applet est une portion de fenêtre graphique : entendez par là que l'affichage d'informationsd'une applet est en mode graphique et pas en mode texte : On n'utilise pas la méthode println ()dans une applet pour afficher du texte, mais plutôt la méthode graphique drawString (). Comme pour une image, une applet s'affiche dans une zone de taille définie par la balise <APPLET...> de la page HTML dans laquelle elle est exécutée. La classe Applet dérive de la classe Panel et non de la classe Window, ce qui implique comme nousle verrons que les applets ne peuvent bénéficier de services que l'on retrouve sur les fenêtresisolées (menus, icone, titre,...). La classe Applet et celles du package java.applet définissent des méthodes utiles dans unnavigateur Internet (chargement d'un fichier HTML , récupération de l'URL courante et desparamètres passées à l'applet,...). Pour éviter toute intrusion dans le système où fonctionne le navigateur, le gestionnaire de sécurité(SecurityManager) défini par la Machine Virtuelle du navigateur est très restrictif :

Aucun accès au système de fichiers local. Possibilité d'accéder uniquement à l'hôte sur lequel est hébergée le fichier de la classe del'applet. Les fenêtres créées par une applet (de classe dérivée de la classe Window) comportent unbandeau indiquant que la fenêtre a été créée par l'applet. Impossibilité de lancer des applications locales. Impossibilité de définir des méthodes native et d'utiliser des librairies du système. Accès limité au propriétés du système de la Machine Virtuelle.

appletviewer et certains navigateurs permettent de modifier les paramètres du gestionnaire desécurité, pour autoriser certaines opérations. Mais si vous voulez réaliser des applets accessiblespubliquement sur Internet, concevez les en considérant que le niveau de sécurité des navigateursutilisés pour exécuter vos applets sera à son maximum.

Certaines caractéristiques qui précédent s'adressent à l'utilisation d'applet dans des pages HTMLaffichées par un navigateur. Si vous utilisez appletviewer (ou Applet Runner sous MacOS), la commandeappletviewer pageweb.html créera une fenêtre isolée pour chaque applet définie par la balise <APPLET...> du fichier pageweb.html.

On rencontre habituellement deux types d'applet :

Des applets dans lesquelles on dessine directement un dessin ou un texte en outrepassant laméthode paint () de la classe Component, comme l'applet HelloWorld décrite au premier chapitre,dont le résultat donne ceci : Des applets qui sont utilisées comme container pour y inclure différents composants, en appelantla méthode add () de la classe Container, comme l'applet AppletBouton décrite au chapitresuivant, dont le résultat donne ceci :

La classe java.applet.Applet

La classe Applet appartient au package java.applet, et dérive des classes Panel, Container, Component,du package java.awt. Ces dernières classes définissent beaucoup de méthodes utiles à la gestion defenêtres graphiques auxquelles la classe Applet ajoute des méthodes propres à la gestion des applets.

Page 195: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 3

Constructeur

public Applet ()

Méthodes

public void init ()

Cette méthode est appelée automatiquement une fois au chargement du fichier HTML dans lequel uneapplet est appelée. C'est le point d'entrée principal de l'applet (comparable à la méthode main () desapplications). Outrepassez cette méthode dans votre classe d'applet, pour initialiser votre applet.

public void start ()

Cette méthode est appelée à chaque fois qu'une applet est visualisée dans un navigateur ou dansappletviewer . Si vous devez effectuer des opérations à chaque visualisation de votre applet, outrepassezcette méthode dans votre classe d'applet.

public void stop ()

Cette méthode est appelée à chaque fois qu'une applet est effacée dans un navigateur ou dansappletviewer (la page HTML où est visualisée l'applet n'est plus la page courante). Si par exemple votreapplet utilise un thread qui tourne continuellement, c'est l'endroit idéal pour l'arrêter, en outrepassantcette méthode dans votre classe d'applet, comme dans l'exemple du chronomètre. En effet, n'oubliez pasque si le thread n'est pas arrêté, il effectuera des opérations dont le résultat peut être inutile, puisque lapage HTML n'est plus affichée dans le navigateur.

public void destroy ()

Cette méthode est appelée quand le fichier HTML dans lequel une applet est appelée est supprimé dela mémoire du navigateur. Si vous devez libérer certaines ressources utilisées par votre applet,outrepassez cette méthode dans votre classe d'applet.

public String getAppletInfo ()

Cette méthode renvoie une chaîne de caractères d'information sur une applet. Outrepasser cette méthodepour renvoyer une chaîne indiquant les renseignements concernant votre applet (Copyright, version,...) .

public String [ ][ ] getParameterInfo ()

Cette méthode renvoie un tableau de chaînes de caractères correspondant aux paramètres qu'il estpossible d'utiliser sur une applet. Outrepasser cette méthode pour renvoyer la liste des paramètresaccepter par votre applet. Le tableau doit être un ensemble de tableaux de 3 chaînes fournissant pourchaque paramètre son nom, le type de valeur attendue et sa description, comme par exemple : {"param","0-10", "Description de param"}.

public void resize (int width, int height)public void resize (Dimension d)

Permet de changer les dimensions d'une applet.

public URL getDocumentBase ()

Renvoie l'URL du fichier HTML dans lequel l'applet est incluse.

public URL getCodeBase ()

Renvoie l'URL du répertoire du fichier .class à partir duquel l'applet a été chargée (cette URL estconstruite grâce à l'attribut CODEBASE du tag APPLET).

public String getParameter (String name)

Cette méthode permet de récupérer la valeur ValueParam du paramètre name de l'applet donné par labalise <PARAM NAME="name" VALUE="ValueParam">. null est renvoyé si le paramètre name n'existe pas.

Page 196: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 4

public AppletContext getAppletContext ()

Renvoie l'instance de la classe AppletContext, représentant le contexte dans lequel l'applet tourne(fourni par le navigateur ou par appletviewer ).

public boolean isActive ()

Renvoie true si une applet est active. Une applet devient active à l'appel de sa méthode start ().

public void showStatus (String msg)

Cette méthode affiche le message msg dans la fenêtre d'état du navigateur (en général, cette fenêtre estune barre d'état située en bas des fenêtres des navigateurs).

public Image getImage (URL url)public Image getImage (URL url, String name)

Ces méthodes permettent d'obtenir l'image à l'URL url ou l'image name relative à url. L'image n'esteffectivement chargée qu'à sa première utilisation (voir le chargement des images). Les images peuventêtre aux formats GIF animé ou non, ou JPEG.

public AudioClip getAudioClip (URL url)public AudioClip getAudioClip (URL url, String name)public void play (URL url)public void play (URL url, String name)

Ces méthodes permettent d'obtenir ou de jouer directement le fichier son à l'URL url ou le fichier sonname relatif à url.

public final void setStub (AppletStub stub)

Permet de donner à l'applet une instance stub de la classe implémentant AppletStub. Cette méthode estappelée par le navigateur ou par appletviewer pour lier l'applet aux fonctionnalités fournies par lesinterfaces AppletContext, AppletStub et AudioClip.

Les méthodes start () et stop () des classes Applet et Thread n'ont aucun lien entre elles. Uneapplet n'est pas un thread, mais par contre, il est vrai que la plupart des navigateurs crée un thread pourchaque applet d'une page HTML.

Exemples

Vous avez l'embarras du choix dans la liste des applets fournie dans la table des matières !

L'intégration des applets dans les navigateurs

La plupart des méthodes de la classe Applet font appel aux méthodes des interfaces suivantes. Lesclasses implémentant ces interfaces sont fournies avec les navigateurs ou avec appletviewer .

L'interface java.awt.AppletContext

L'interface AppletContext représente le contexte dans lequel l'applet tourne.

Méthodes

public AudioClip getAudioClip (URL url)public Image getImage (URL url)public void showStatus (String status)

Voir la classe Applet.

public Applet getApplet (String name)public Enumeration getApplets ()

Page 197: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 5

Ces méthodes renvoient soit une applet en fonction de son nom (donné par la valeur de NAME dans labalise <APPLET ...>), soit une énumération de toutes les applets du contexte dans lequel une applettourne. Par exemple, une fois que vous avez trouvé une applet, il est possible de communiquer avec elle(voir l'exemple qui suit).

public void showDocument (URL url)public void showDocument (URL url, String target)

Ces méthodes permettent de charger dans le navigateur ou dans appletviewer un nouveau document àl'adresse url. target peut être égal à une des valeurs suivantes :

"_self" : le document est chargé dans le frame courant. "_parent" : le document est chargé dans le frame parent. "_top" : le document est chargé dans le frame de niveau le plus élevé. "_blank" : le document est chargé dans une nouvelle fenêtre sans nom. Une autre chaîne "Titre" : le document est chargé dans le cadre (frame ) dénommé Titre.

showDocument () est utilisé typiquement pour charger un document quand un utilisateur clique sur unbouton défini dans une applet.

Exemples

Applets PlayApplet et BoutonsNavigation .

L'interface java.applet.AppletStub

L'interface AppletStub est utilisée pour intégrer une applet dans un navigateur ou dans appletviewer .

Méthodes

public boolean isActive ()public URL getDocumentBase ()public URL getCodeBase ()public String getParameter (String name)public AppletContext getAppletContext ()

Voir la classe Applet pour la définition de ces méthodes.

public void appletResize (int width, int height)

Cette méthode est appelée par les méthodes resize () de la classe Applet pour redimensionner uneapplet dans la fenêtre d'un navigateur.

Voici un exemple d'utilisation des méthodes getParameter () et getApplet (), qui permet de retrouverune applet appletControlee dont le nom est donné en paramètre. Une fois trouvée cette applet, on luiassocie un bouton qui appelle alternativement les méthodes start () ou stop () de l'appletappletControlee pour la démarrer ou l'arrêter. Ici, l'applet de la classe Observable est reprise pourillustrer cet exemple :

et le programme Java correspondant (à copier dans un fichier dénommé PlayApplet.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class PlayApplet extends Applet{ private Applet appletControlee = null; private Button boutonDemarrerArreter; public void init () {

Page 198: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 6

String nomApplet = getParameter ("Applet"); String action = getParameter ("Action"); if (nomApplet != null) try { Applet applet; do // Recherche de l'applet dont le nom égale nomApplet if ( (applet = getAppletContext () .getApplet (nomApplet)) == null || !applet.isActive ()) // Si l'applet recherchée n'existe pas, attendre 1 seconde // (l'applet n'est peut-être pas encore chargée) Thread.sleep (1000); else appletControlee = applet; while (appletControlee == null); // L'applet a été trouvée, ajouter un bouton pour la contrôler add (boutonDemarrerArreter = new Button (action)); // Si le paramètre action indique de démarrer l'applet au départ, // arrêter l'applet pour l'utilisateur puisse la démarrer if (action.equals ("D\u00e9marrer")) appletControlee.stop (); } catch (InterruptedException e) { } } // Méthode appelée quand on clique sur le bouton public boolean action (Event event, Object arg) { if (event.target == boutonDemarrerArreter) { // Arrêter ou démarrer l'applet suivant le nom du bouton if ("Arr\u00eater".equals (arg)) appletControlee.stop (); else { appletControlee.start (); appletControlee.validate (); } // Changer le nom du bouton et le réafficher boutonDemarrerArreter.setLabel ("Arr\u00eater".equals (arg) ? "D\u00e9marrer" : "Arr\u00eater"); boutonDemarrerArreter.invalidate (); validate (); return true; } return super.action (event, arg); }}

Si vous consultez le source de ce fichier HTML , vous pourrez voir comment utiliser l'appletPlayApplet avec ses paramètres. Le paramètre de nom Applet vous permettant d'indiquer quel est le nomde la classe de l'applet que vous voulez contrôler :

<APPLET CODE="ObservateurCalcul" CODEBASE="../classes" NAME="calcul" ALT="ObservateurCalcul" WIDTH=250 HEIGHT=30 ALIGN=middle></APPLET><APPLET CODE="PlayApplet" CODEBASE="../classes" ALT="PlayApplet" WIDTH=80 HEIGHT=30 ALIGN=middle> <PARAM NAME="Applet" VALUE="calcul"> <PARAM NAME="Action" VALUE="D&eacute;marrer"></APPLET>

L'applet PlayApplet n'a pas qu'un intérêt didactique : elle permet de contrôler sans les modifier, desapplets qui utilisent des threads créés dans la méthode start () et arrêtés dans la méthode stop ().Quand, comme dans certains exemples de ce manuel, vous utilisez des applets gourmandes en temps decalcul, ceci permet de proposer à l'utilisateur que ces applets aient leur threads qui ne fonctionnent qu'àsa demande (malheureusement la méthode getParameter () ne fonctionne pas avec les premières

Page 199: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 7

versions de certains navigateurs sous Windows).

L'interface java.applet.AudioClip

L'interface AudioClip permet de jouer les fichiers sons chargés. Le seul type de son reconnu sous Java1.0 et 1.1 est le type de fichier Sun .au (8 bit, law, 8000 Hz, mono). Si vous voulez convertir desfichiers existants dans ce format, il existe des outils de conversion disponibles en shareware ou enfreeware sur Internet. Il est possible de mixer plusieurs sons ensemble (si vous exécutez les méthodesplay () ou loop () ensemble sur différents sons, les différents sons seront mélangés).

Méthodes

public void play ()

Cette méthode démarre le son de l'objet AudioClip. A chaque fois, que cette méthode est appelée, le sonredémarre.

public void loop ()

Démarre le son et le joue en boucle.

public void stop ()

Arrête le son. N'oubliez pas d'arrêter de jouer un son dans la méthode stop () d'une applet, si ce son nedoit être joué qu'avec cette applet et surtout s'il est joué en boucle.

Voici un exemple d'utilisation de l'interface AudioClip, qui joue le son correspondant à la note d'unoctave de piano sur lequel on clique (il faut bien sûr une carte son sur votre ordinateur !):

et le programme Java correspondant (à copier dans un fichier dénommé Piano.java et invoqué à partird'un fichier HTML) :

import java.applet.*;import java.awt.*; public class Piano extends Applet{ AudioClip [ ] octave = new AudioClip [12]; String [ ] notes = {"do.au", "dodiese.au", "re.au", "rediese.au", "mi.au", "fa.au", "fadiese.au", "sol.au", "soldiese.au", "la.au", "ladiese.au", "si.au"}; Rectangle [ ] rectNotes = new Rectangle [12]; boolean [ ] notesBlanches = {true, false, true, false, true, true, false, true, false, true, false, true}; public void init () { // Chargement des 12 fichiers de notes for (int i = 0; i < notes.length; i++) octave [i] = getAudioClip (getCodeBase (), notes [i]); // Changement de la couleur de fond setBackground (Color.white); } // Méthode appelée par la Machine Virtuelle quand l'applet change de taille public void reshape (int newx, int newy, int largeur, int hauteur) { int largeurBlanche = largeur / 7; int largeurNoire = largeurBlanche / 2; // Calcul des rectangles représentant les 12 notes (noires ou blanches) for (int x = 0, i = 0; i < notes.length; x += notesBlanches [i++] ? largeurBlanche : 0)

Page 200: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 8

if (notesBlanches [i]) rectNotes [i] = new Rectangle (x, 0, largeurBlanche - 1, hauteur - 1); else rectNotes [i] = new Rectangle (x - largeurNoire / 2, 0, largeurNoire - 1, 2 * hauteur / 3); // Rappel de la méthode de la super classe super.reshape (newx, newy, largeur, hauteur); } // Méthode appelée par la Machine Virtuelle quand l'applet doit être dessinée public void paint (Graphics gc) { gc.setColor (Color.black); // Dessin des blanches for (int i = 0; i < notes.length; i++) if (notesBlanches [i]) gc.drawRect (rectNotes [i].x, rectNotes [i].y, rectNotes [i].width, rectNotes [i].height); // Dessin des noires for (int i = 0; i < notes.length; i++) if (!notesBlanches [i]) gc.fillRect (rectNotes [i].x, rectNotes [i].y, rectNotes [i].width, rectNotes [i].height); } // Méthode recherchant la note à la position (x,y) private AudioClip rechercherNote (int x, int y) { // Recherche d'abord parmi les noires puis les blanches car les // rectangles des noires sont au-dessus de ceux des blanches for (int i = 0; i < notes.length; i++) if ( !notesBlanches [i] && rectNotes [i].inside (x, y)) return octave [i]; for (int i = 0; i < notes.length; i++) if (rectNotes [i].inside (x, y)) return octave [i]; return null; } // Méthode appelée par la Machine Virtuelle // quand le bouton de la souris est enfoncé public boolean mouseDown (Event evt, int x, int y) { AudioClip note = rechercherNote (x, y); if (note != null) note.play (); return true; }}

Les méthodes paint () et reshape () sont décrites dans le chapitre suivant. Les méthodes utilisées dansla méthode paint () ainsi que la méthode outrepassée mouseDown () sont décrites dans le chapitre sur lagestion de l'interface utilisateur.

Bien que le seul format reconnu actuellement réduise la taille (et la qualité) des fichiers sons, ceux-cisont très gourmands en octets. Rien que l'applet Piano qui utilise douze (petits) fichiers sons de 6 K enmoyenne, doit charger 72 K pour fonctionner. Donc faites attention à la taille de vos sons, si vousvoulez utiliser vos applets sur Internet.

Transformer une applet en application

Il est partiellement possible de créer une classe d'applet qui puisse aussi fonctionner comme applicationisolée, en définissant une méthode main () qui crée une fenêtre dans laquelle l'applet est ajoutée (voirl'exemple de la classe Frame).Les méthodes suivantes de la classe Applet sont en fait des appels indirects aux classes quiimplémentent les interfaces AppletContext, AppletStub et AudioClip. Ces classes fournies par lesnavigateurs ou Appletviewer , sont liées à une applet après sa création grâce à la méthode setStub () de laclasse Applet :

Page 201: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les applications et les applets Page: 9

getDocumentBase () interface AppletStub getCodeBase () interface AppletStub getParameter () interface AppletStub getAppletContext () interface AppletStub isActive () interface AppletStub getImage () interface AppletContext getAudioClip () interface AppletContext showStatus () interface AppletContext play () interface AudioClip

Si vous utilisez dans votre applet une de ces méthodes, pour éviter le déclenchement d'exception il vousfaut créer la ou les classes qui implémentent les méthodes des interfaces correspondantes, même si leurimplémentation ne fait rien (seule la méthode getImage () est aussi disponible dans la classe Toolkit).Une instance de la classe implémentant AppletStub est associée à chaque applet grâce à la méthodesetStub (), une instance de la classe implémentant AppletContext est associée à chaque fenêtre denavigateur et une instance de la classe implémentant AudioClip est associée à chaque son

Page 202: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 1

Les composants de l'interface utilisateur

Les composants JavaLa classe java.awt.Component

Les composants prédéfinisComment ça marche ?

Les composants Java

Le package java.awt (Abstract Window Toolkit) est le plus riche des packages Java. Il définit toutes lesclasses permettant de construire et de gérer l'interface utilisateur. Les classes les plus importantes de cepackage sont celles qui permettent de créer les différents composants d'une interface utilisateur. Lescomposants se répartissent en trois catégories :

1. Les composants prédéfinis sur lesquels l'utilisateur agit directement pour communiquer avec leprogramme (dans d'autres environnements comme Windows, on les appelle des contrôles). Voici laliste de ceux fournis avec le package java.awt :

Les boutons (de classe Button) : un programme déclenche une action quandl'utilisateur clique sur un bouton (on entend par cliquer enfoncer et relâcher lebouton de la souris avec le pointeur toujours positionné sur le bouton).

Les boites à cocher (de classe Checkbox) : ce sont des composants ayant deuxétats possibles (coché ou non coché), qui permettent de proposer à l'utilisateurd'activer ou désactiver une option par simple clic.

Les boutons radios (de classe Checkbox associés à un ensemble de classeCheckboxGroup). A un moment donné, un seul bouton radio ne peut être choisiparmi ceux de l'ensemble auquel il appartient. Ceci permet de proposer àl'utilisateur un choix parmi plusieurs options.

Les composants de classe Choice (appelés aussi Combo box ou Drop down listdans d'autres environnements) : Ce type de composant propose à l'utilisateur defaire un choix parmi un certains nombres de chaînes de caractères affichéesdans une liste déroulante. Cette liste apparaît quand l'utilisateur clique sur laflèche associée au composant et disparaît une fois que celui-ci clique sur unedes chaînes de la liste.

Les listes (de classe List) : ce sont des composants qui permettent par simpleclic, de sélectionner ou de déselectionner une ou plusieurs chaînes decaractères affichées dans une liste.Contrairement au composant de classeChoice, la liste reste toujours affichée. Les chaînes sélectionnées sont affichéesen inverse vidéo.

Les labels (de classe Label) : Ce sont les composants les plus simples ; un labelpermet d'afficher une chaîne de caractères (titre, message, information décrivantun composant juxtaposé,...).

Les zones de saisies de texte (composant avec une seule ligne TextField ouavec plusieurs lignes TextArea) : Ces composants permettent à l'utilisateur desaisir une chaîne de caractères.

Les ascenseurs (de classe Scrollbar) : ces composants sont utilisés enassociation avec un autre composant (en général un container), quand la zoned'affichage de celui-ci est trop petite pour contenir tout ce qu'il peut afficher.L'ascenseur (horizontal et/ou vertical) permet alors à l'utilisateur de déplacer lazone d'affichage sur d'autres portions du composant (comme on bouge des

Page 203: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 2

jumelles pour voir différents détails d'un paysage).

2. Les composants dérivés de la classe Canvas : Si les composants prédéfinis ne satisfont pas un de

vos besoins, vous devez utiliser cette classe comme super classe pour créer vos proprescomposants que vous dessinez en utilisant les méthodes de la classe Graphics.

3. Les containers : Contrairement aux autres composants, les containers sont utilisés pour contenird'autres composants de n'importe quelle catégorie ou pour afficher directement des dessinsfabriqués avec les méthodes de la classe Graphics. Les containers se subdivisent en deux souscatégories qui héritent toutes deux de la classe abstract Container :

Les containers de type fenêtre (de classe Window ou ses dérivées) : Les fenêtres sont deszones d'affichage indépendantes les unes des autres. Parmi les fenêtres, on distingue lesboites de dialogue (de classe Dialog) comportant un cadre et un titre, et les fenêtres de classeFrame comportant un cadre, un titre, un menu éventuel, un pointeur de souris propre,... (etcorrespondant aux fenêtres que vous avez l'habitude d'utiliser). Les containers de classe Panel : Ce type de containers est une zone d'affichage occupant toutou partie d'une fenêtre. Notamment, la classe Applet dérive de Panel et permet d'afficher descomposants ou un dessin dans une fenêtre d'un navigateur.

Toutes les classes de composants citées ci-dessus dérivent directement ou indirectement d'une uniqueclasse : la classe Component. Cette classe décrit tous les comportements communs à tous les composants.

Voici la hiérarchie des classes qui dérivent de la classe Component :

java.awt.Component java.awt.Button java.awt.Canvas java.awt.Checkbox java.awt.Choice java.awt.Container

java.awt.Panel java.applet.Applet

java.awt.Window java.awt.Dialog

java.awt.FileDialog java.awt.Frame

java.awt.Label java.awt.List java.awt.Scrollbar java.awt.TextComponent

java.awt.TextArea java.awt.TextField

Quand vous recherchez les méthodes disponibles sur une classe dérivée de Component, n'oubliez pasde consulter toutes les super classes dont elle hérite, pour connaître l'ensemble complet de sesfonctionnalités.

Tous ces composants prennent l'aspect de ceux du système sur lequel la Machine Virtuelle fonctionne.Et les menus dans tout ça ?! Les menus et sous-menus d'une fenêtre sont des instances des classesdérivant de la classe abstract MenuComponent qui n'a pas de lien d'héritage avec la classe Component,c'est pourquoi ils sont traités dans le paragraphe sur les menus.

Page 204: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 3

Contrairement à d'autres systèmes (Windows, MacOS,...), il n'existe pas en Java 1.0 de concept defichier ressource utilisé pour décrire et créer l'interface utilisateur, et séparé du programme qui s'ensert. Vous devez créer vous-même tous les composants et les ajouter au container qui les contient. Parcontre, leur disposition (position et taille) peut être gérée automatiquement par un layout associé àchaque container.

La classe java.awt.Component

Cette classe abstract est la super classe de toutes les classes de composants citées ci-dessus, etimplémente l'interface ImageObserver. Elle comporte un très grand nombre de méthodes, qui sontsouvent outrepassées par les classes dérivées de Component.Si vous devez créer une applet ou un programme avec une interface graphique, vous utiliserez lesclasses de composants ou vous créerez de nouvelles classes qui en dérivent (de la classe Appletnotamment). Comme vous aurez à outrepasser ces méthodes ou vous les invoquerez directement ouindirectement, il vous faut bien maîtriser l'utilité de la plupart d'entre elles.

Méthodes

public Container getParent ()public ComponentPeer getPeer ()public Toolkit getToolkit ()

Ces méthodes permettent d'obtenir le composant parent (par exemple le container auquel appartient unbouton), le peer d'un composant et le kit d'outils (Toolkit ) gérant la création des composants à l'écran.

public boolean isValid ()public boolean isVisible ()public boolean isShowing ()public boolean isEnabled ()

Ces méthodes permettent de savoir si un composant est valide, s'il est visible, s'il est affiché et s'il estutilisable.Un composant est invalide, quand son image à l'écran ne correspond pas aux valeurs de ses variables,par exemple quand on change sa taille et que l'image du composant n'a pas encore mis à jour.Tous les composants sont visibles par défaut sauf les fenêtres dont la classe est Window ou ses dérivées.Attention, pour un composant qui n'est pas une fenêtre, visible n'implique pas que l'objet est à l'écran,cela veut dire qu'il faudra l'afficher quand son container sera créé à l'écranUn composant est affiché quand il est à écran, c'est-à-dire qu'il est visible ET que son container est àl'écran.Un composant est utilisable (enabled ), quand l'utilisateur peut s'en servir ; un composant qui n'est pasutilisable (disabled ) est généralement grisé.

public Point location ()public Dimension size ()public Rectangle bounds ()

Ces méthodes renvoient la position, la taille et le rectangle englobant d'un composant. Les coordonnéessont exprimées dans le système de coordonnées du parent du composant, sachant que le point (0,0) esten haut à gauche et que l'axe des y descend vers le bas.

public synchronized void enable ()public synchronized void disable ()public void enable (boolean cond)

Vous pouvez rendre utilisable ou inutilisable un composant grâce à ces méthodes. Un composantinutilisable (disabled ) est généralement grisé.

public synchronized void show ()public synchronized void hide ()public void show (boolean cond)

Ces méthodes permettent d'afficher ou d'effacer un composant. Ces méthodes sont surtout utilisées pourafficher ou effacer une fenêtre à l'écran.

Page 205: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 4

public Color getForeground ()public synchronized void setForeground (Color c)public Color getBackground ()public synchronized void setBackground (Color c)public Font getFont ()public synchronized void setFont (Font f)public synchronized ColorModel getColorModel ()

Utilisez ces méthodes pour obtenir ou modifier la couleur d'un composant, sa couleur de fond et lapolice de caractères qu'il utilise pour afficher son texte (voir aussi la classe Graphics).

public void move (int x, int y)public void resize (int width, int height)public void resize (Dimension d)public synchronized void reshape (int x, int y, int width, int height)

Ces méthodes sont utilisées pour déplacer et modifier la taille d'un composant. Généralement, on ne lesappelle pas directement pour placer un composant dans un container : ces composants sont disposésautomatiquement par le layout associé au container. Par contre, vous devez donner une dimension auxfenêtres que vous créez.Si vous voulez utiliser les nouvelles dimensions d'un composant comme dans l'applet Piano, outrepassezla méthode reshape () car les trois autres méthodes appellent cette méthode.

public Dimension preferredSize ()public Dimension minimumSize ()

Ces méthodes renvoient la taille préférée et la taille minimum d'un composant, pour que son affichage sefasse correctement. Ces méthodes sont appelées par certains classes de layout, pour connaître lesdimensions correctes d'un composant.

public void layout ()

L'implémentation de cette méthode ne fait rien dans la classe Component. Elle est outrepassée notammentpar la classe Container, pour disposer les composants appartenant à un container.

public void validate ()

Si un composant est invalide (son image à l'écran ne correspond pas aux valeurs de ses variables), cetteméthode appelle layout (). Elle est outrepassée dans la classe Container pour mettre à jour tous lescomposants d'un container invalide.

public void invalidate ()

Marque un composant et ses parents comme étant invalide. Ainsi, un appel à validate () pourra mettreà jour ces composants invalides.

public Graphics getGraphics ()

Permet de d'obtenir un contexte graphique pour un composant, pour y effectuer des dessins. Cetteméthode renvoie null si le composant n'a pas encore été affiché.

public FontMetrics getFontMetrics (Font font)

Permet de récupérer les renseignements concernant une police de caractère (hauteur, largeur,...).

public void paint (Graphics gc)

Cette méthode est appelée quand le dessin d'un composant doit être mis à jour (à la premièrevisualisation d'un composant, quand il change de taille, quand une portion d'un composant cachée parune fenêtre, est réaffichée,...). L'implémentation de la méthode paint () de la classe Component ne faitrien. Quand vous créez de nouvelles classes de composants (dérivées d'une des classes Canvas, Applet,Frame,...), vous devez outrepasser cette méthode pour dessiner le composant avec les méthodes de laclasse Graphics, si vous ne voulez pas vous en servir comme container.

Page 206: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 5

Les composants Java n'utilisent pas le double-buffering (système utilisant une image cachée, copie del'image d'un composant à l'écran). C'est à dire que, par défaut, à chaque fois qu'un composant a besoind'être redessiné (même si ce dessin n'a pas changé), la méthode paint () de sa classe est appelée etdonc que toutes les instructions de cette méthode sont exécutées. Ceci implique deux inconvénientsmajeurs :

Si le dessin est inchangé (comme par exemple, quand un composant caché par une fenêtre estréaffichée), toutes les instructions de paint () sont réexécutées et ceci peut prendre un certaintemps. L'utilisateur voit le dessin se fabriquer à l'écran, ce qui peut être gênant si notamment, vousvoulez faire des animations.

Par contre, l'avantage est que moins de mémoire est utilisée pour l'affichage d'un composant (pas debesoin de mémoriser une image copie du composant à l'écran).Le chapitre sur les images, décrit comment simuler un effet de double-buffering , en créant une imagedans laquelle vous dessinez avant de la copier à l'écran.

public void update (Graphics gc)

Cette méthode est appelée indirectement par les méthodes repaint (). La méthode update () remplitd'abord le composant avec sa couleur de fond avant d'appeler paint (). Si le dessin réalisé par lesinstructions de la méthode paint () occupe la totalité de la surface du composant, outrepassez laméthode update () en appelant directement paint (), ceci évitera que le fond soit rempli inutilement.

public void paintAll (Graphics gc)

Redessine un composant et pour un container tous les composants lui appartenant.

public void repaint ()public void repaint (long millisec)public void repaint (int x, int y, int width, int height)public void repaint (long millisec, int x, int y, int width, int height)

Redessine un composant. Ces méthodes provoque indirectement un appel à update (), soit le plusrapidement possible, soit après au moins millisec millisecondes. x, y, width et height délimite la zone àredessiner.

public void print (Graphics gc)

Imprime le composant. L'implémentation de print () de la classe Component appelle paint ().

public void printAll (Graphics gc)

Imprime un composant et pour un container tous les composants lui appartenant.

public synchronized boolean inside (int x, int y)

Vérifie si le point de coordonnées (x,y) appartient à la boite englobante du composant.

public Component locate (int x, int y)

L'implémentation de cette méthode renvoie le composant lui-même si le point de coordonnées (x,y)appartient à sa boite englobante. Elle est outrepassée dans la classe Container pour rechercher lecomposant situé au point de coordonnées (x,y) d'un container.

public Image createImage (int width, int height)public Image createImage (ImageProducer producer)public boolean prepareImage (Image image, ImageObserver observer)public boolean prepareImage (Image image, int width, int height, ImageObserver observer)public int checkImage (Image image, ImageObserver observer)public int checkImage (Image image, int width, int height, ImageObserver observer)

Page 207: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 6

public boolean imageUpdate (Image img, int flags, int x, int y, int width, int height)

Ces méthodes permettent de manipuler les images. Voir le chapitre sur les images pour plus de détails.La méthode imageUpdate () est l'implémentation de la méthode de l'interface ImageObserver.

public void deliverEvent (Event evt)public boolean postEvent (Event evt)public boolean handleEvent (Event evt)public boolean mouseDown (Event evt, int x, int y)public boolean mouseDrag (Event evt, int x, int y)public boolean mouseUp (Event evt, int x, int y)public boolean mouseMove (Event evt, int x, int y)public boolean mouseEnter (Event evt, int x, int y)public boolean mouseExit (Event evt, int x, int y)public boolean keyDown (Event evt, int key)public boolean keyUp (Event evt, int key)public boolean action (Event evt, Object what)public boolean gotFocus (Event evt, Object what)public boolean lostFocus (Event evt, Object what)

Ces méthodes sont utilisées pour la gestion événementielle des composants (voir le chapitre sur lagestion de l'interface utilisateur).

public void requestFocus ()

Permet à un composant de lancer une requête pour obtenir le focus. Si le focus lui est accordé, laméthode gotFocus () sera appelée.

public void nextFocus ()

Donne le focus au composant suivant parmi ceux de la liste des composants d'un container.

public void addNotify ()

Cette méthode est outrepassée par les classes dérivées de Component pour créer le peer d'un composant,qui est sa représentation à l'écran. Elle est appelée indirectement par les méthodes qui gèrent l'affichagedes composants.

public synchronized void removeNotify ()

Cette méthode est appelée pour supprimer le peer d'un composant.

protected String paramString ()public String toString ()

Ces méthodes sont utilisées pour fabriquer une chaîne de caractères décrivant le composant (toString() outrepasse la méthode de la classe Object et appelle la méthode paramString () qui est outrepasséepar les classes dérivées de Component).

public void list ()public void list (PrintStream out)public void list (PrintStream out, int indent)

Imprime sur System.out ou sur out, la chaîne de caractères décrivant le composant.

Les composants prédéfinis

La classe java.awt.Button

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer etde manipuler des boutons. Une fois créé un objet de classe Button, vous devez l'ajouter à un containeravec la méthode add () de la classe Container, pour le visualiser.

Constructeurs

Page 208: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 7

public Button ()public Button (String label)

Ces constructeurs permettent de créer un bouton avec ou sans label (texte affiché dans le bouton).

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'unbouton.

public String getLabel ()public void setLabel (String label)

Ces méthodes permettent d'interroger ou de modifier le label d'un bouton.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant lebouton.

Exemples

Applets PlayApplet , AppletButton , TraitementTexte , MessageBoxApplet , BorderBuilder , ShowMenu etMiseAJourHorloge .

La classe java.awt.Checkbox

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer etde manipuler des boites à cocher et les boutons radios. Une fois créé un objet de classe Checkbox, vousdevez l'ajouter à un container avec la méthode add () de la classe Container, pour le visualiser. Uneboîte à cocher ou un bouton radio ont deux états (coché ou non) représentés par une valeur boolean(true ou false).Pour qu'un objet de classe Checkbox soit un bouton radio, il doit être associé à une instance deCheckboxGroup.

Constructeurs

public Checkbox ()public Checkbox (String label)

Ces constructeurs permettent de créer une boite à cocher avec ou sans label (texte affiché à côté de laboite à cocher). Par défaut, la boite à cocher n'est pas cochée.

public Checkbox (String label, CheckboxGroup group, boolean state)

Ce constructeur permet de construire une boite à cocher, ou un bouton radio si group est différent denull. Si state est égal à true la boite à cocher est cochée, ou le bouton radio est le bouton coché parmitous les boutons radios qui appartiennent au groupe group.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'uneboite à cocher ou d'un bouton radio.

public String getLabel ()public void setLabel (String label)

Ces méthodes permettent d'interroger ou de modifier le label d'une boite à cocher ou d'un bouton radio.

public boolean getState ()

Page 209: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 8

public void setState (boolean state)

Ces méthodes permettent d'interroger ou de modifier l'état (coché ou non) d'une boite à cocher ou d'unbouton radio.

public CheckboxGroup getCheckboxGroup ()public void setCheckboxGroup (CheckboxGroup group)

Ces méthodes permettent d'interroger ou de modifier le groupe auquel appartient un bouton radio.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant lecomposant.

Exemple

Applet DrawIt .

La classe java.awt.CheckboxGroup

Cette classe est la classe du package java.awt qui permet de gérer un ensemble de boutons radios. Parmitous les boutons radios (de classe Checkbox) associés à une instance de CheckboxGroup, au plus un seulpeut être coché.

Constructeur

public CheckboxGroup ()

Méthodes

public Checkbox getCurrent ()public synchronized void setCurrent (Checkbox box)

Ces méthodes permettent d'interroger ou de modifier le bouton radio qui est actuellement coché.

public String toString ()

Exemple

Applet DrawIt .

La classe java.awt.Choice

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer descomposants proposant un choix parmi une liste déroulante. Une fois créé un objet de classe Choice,vous devez l'ajouter à un container avec la méthode add () de la classe Container, pour le visualiser. Achaque choix de la liste est associé un indice, compris entre 0 et le nombre de choix - 1.

Constructeur

public Choice ()

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'uneinstance de la classe Choice.

public int countItems ()

Renvoie le nombre de choix possibles dans le composant.

public String getItem (int index)

Page 210: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 9

Renvoie la chaîne de caractères correspondante au choix d'indice index.

public synchronized void addItem (String item)

Permet d'ajouter en fin de liste un nouveau choix égal à la chaîne de caractères item.

public String getSelectedItem ()public int getSelectedIndex ()

Ces méthodes renvoient soit la chaîne de caractères soit l'indice du choix courant.

public synchronized void select (int index) throws IllegalArgumentExceptionpublic void select (String str)

Ces méthodes permettent de désigner le choix courant du composant, soit en donnant son indice index,soit en donnant sa valeur str.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant lecomposant.

Exemple

Applet CalculetteSimple .

La classe java.awt.List

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer deslistes permettant de sélectionner un ou plusieurs choix parmi plusieurs chaînes de caractères. Une foiscréé un objet de classe List, vous devez l'ajouter à un container avec la méthode add () de la classeContainer, pour le visualiser. A chaque choix de la liste est associé un indice, compris entre 0 et lenombre de choix - 1. Il est possible de définir le nombre de lignes qu'une liste peut afficher en mêmetemps, sans utiliser l'ascenseur associée à la liste, mais ce nombre de lignes et la taille du composantdépendent aussi du layout utilisé.

Constructeur

public List ()

Ce constructeur construit une liste dont le nombre de lignes affichées n'est pas déterminé, et quin'autorise pas la sélection multiple.

public List (int rows, boolean multipleSelections)

Ce constructeur construit une liste dont le nombre de lignes affichées est égal à rows, et qui autorise lasélection multiple si multipleSelections est égal à true.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'une liste.

public synchronized void removeNotify ()

Cette méthode outrepasse la méthode removeNotify () de la classe Component pour supprimer le peerd'une liste.

public int countItems ()

Renvoie le nombre de choix possibles dans la liste.

Page 211: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 10

public String getItem (int index)

Renvoie la chaîne de caractères correspondante au choix d'indice index.

public synchronized void addItem (String item)

Permet d'ajouter en fin de liste un nouveau choix égal à la chaîne de caractères item.

public synchronized void addItem (String item, int index)

Permet d'insérer à l'indice index un nouveau choix égal à la chaîne de caractères item (si index est égal à-1, item est ajouté en fin de liste).

public synchronized void replaceItem (String newValue, int index)

Remplace la chaîne de caractères à l'indice index par newValue.

public synchronized void clear ()

Supprime toutes les chaînes de caractères de la liste.

public synchronized void delItem (int index)public synchronized void delItems (int start, int end)

Supprime le choix à l'indice index, ou tous les choix compris entre les indices start et end.

public synchronized String getSelectedItem ()public synchronized int getSelectedIndex ()

Ces méthodes renvoient soit la chaîne de caractères sélectionnée soit son indice (en cas de sélectionmultiple seule la première est renvoyée).

public synchronized String [ ] getSelectedItems ()public synchronized int [ ] getSelectedIndexes ()

Ces méthodes renvoient soit un tableau des chaînes de caractères sélectionnées soit un tableau de leurindice.

public synchronized void select (int index)public synchronized void deselect (int index)

Ces méthodes permettent de sélectionner ou de désélectionner une chaîne de caractères en donnant sonindice index.

public synchronized boolean isSelected (int index)

Renvoie true si la chaîne de caractères d'indice index est sélectionnée.

public int getRows ()

Renvoie le nombre de lignes visibles dans la liste.

public boolean allowsMultipleSelections ()

Renvoie true si une liste autorise la sélection multiple.

public void setMultipleSelections (boolean v)

Permet d'autoriser ou non la sélection multiple dans une liste.

public int getVisibleIndex ()

Renvoie l'indice de la chaîne de caractères qui a été rendue visible lors d'un précédent appel à laméthode makeVisible ().

public void makeVisible (int index)

Page 212: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 11

Force la chaîne de caractères d'indice index à être visible à l'écran.

public Dimension preferredSize (int rows)public Dimension preferredSize ()public Dimension minimumSize (int rows)public Dimension minimumSize ()

Méthodes de la classe Component, outrepassées pour renvoyer la taille préférée ou la taille minimumd'une liste.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant la liste.

Voici un programme Java simple utilisant une liste : c'est celui de l'applet donnant la liste des caractèresUnicode compris entre '\u0080' et '\u00ff'(à copier dans un fichier dénommé Unicode.java et invoquéà partir d'un fichier HTML)

import java.awt.*;import java.applet.*; public class Unicode extends Applet{ public void init () { // Utilisation d'un layout grille 1 x 1 qui permet // à la liste d'occuper tout l'espace de l'applet setLayout (new GridLayout (1, 1)); // Changement de police de caractères setFont (new Font("Courier", Font.PLAIN, 12)); // Création d'une liste affichant les caractères // Unicode compris entre '\u0080' et '\u00ff' List listeCaracteres = new List (); for (short i = 0x0080; i <= 0x00ff; i++) listeCaracteres.addItem ( "\\u00" + Integer.toHexString (i) + " " + new Character ((char)i)); // Ajout de la liste au container add (listeCaracteres); }}

Autre exemple

Applet ListePolices .

La classe java.awt.Label

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer etde manipuler des labels. Une fois créé un objet de classe Label, vous devez l'ajouter à un container avecla méthode add () de la classe Container, pour le visualiser.

Variables

public final static int LEFTpublic final static int CENTERpublic final static int RIGHT

Constantes utilisées pour l'alignement du texte dans le composant.

Constructeurs

public Label ()public Label (String label)public Label (String label, int alignment)

Ces constructeurs permettent de créer un label avec ou sans texte, et en précisant éventuellement

Page 213: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 12

l'alignement du texte dans le composant (égal à LEFT, CENTER ou RIGHT).

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'un label.

public int getAlignment ()public void setAlignment (int alignment) throws IllegalArgumentException

Ces méthodes permettent d'interroger ou de modifier l'alignement du texte dans un label (égal à LEFT,CENTER ou RIGHT).

public String getText ()public void setText (String label)

Ces méthodes permettent d'interroger ou de modifier le texte d'un label.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant le label.

Exemples

Applets CalculetteSimple , TraitementTexte , MessageBoxApplet , MiseAJourHorloge , ListePolices et Nuancier .

La classe java.awt.TextComponent

Cette classe qui dérive de la classe Component, est la super classe des classes de composants TextFieldet TextArea qui permettent de créer des zones de saisies de texte. Cette classe regroupe l'ensemble desméthodes communes à ces deux classes. Comme elle n'a pas de constructeur public, vous ne pouvezcréer d'instance de cette classe.

Méthodes

public synchronized void removeNotify ()

Cette méthode outrepasse la méthode removeNotify () de la classe Component pour supprimer le peerd'une zone de saisie.

public void setText (String t)public String getText ()

Ces méthodes permettent d'interroger ou de modifier le texte d'une zone de saisie.

public boolean isEditable ()

Renvoie true si le texte d'une zone de saisie est éditable.

public void setEditable (boolean t)

Permet de spécifier si le texte d'une zone de saisie est éditable ou non.

public String getSelectedText ()public int getSelectionStart ()public int getSelectionEnd ()

Ces méthodes permettent d'interroger le texte en cours de sélection dans une zone de saisie ou l'indicedu début et de la fin du texte sélectionné.

public void select (int selStart, int selEnd)public void selectAll ()

Ces méthodes permettent de sélectionner une partie du texte de la zone de saisie (comprise entre lesindices selStart et selEnd) ou tout le texte de la zone de saisie.

Page 214: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 13

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant la zonede saisie.

La classe java.awt.TextField

Cette classe qui dérive des classes TextComponent et Component, est la classe du package java.awt quipermet de créer et de manipuler des zones de saisies de texte d'une seule ligne. Une fois créé un objetde classe TextField, vous devez l'ajouter à un container avec la méthode add () de la classe Container,pour le visualiser. Il est possible d'utiliser les zones de saisie de cette classe pour la saisie de mots depasse en précisant un caractère qui masque les caractères saisis. Toutes les méthodes permettant demanipuler le texte de la zone de saisie sont dans la classe TextComponent.

Constructeurs

public TextField ()public TextField (int cols)public TextField (String text)public TextField (String text, int cols)

Ces constructeurs permettent de créer une zone de saisie avec ou sans un texte de départ, et enprécisant éventuellement le nombre de colonnes que doit occuper la zone de saisie.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'unezone de saisie d'une seule ligne.

public boolean echoCharIsSet ()

Renvoie true si un caractère de masque est positionné.

public char getEchoChar ()public void setEchoCharacter (char c)

Ces méthodes permettent d'interroger ou de modifier le caractère de masque en cours d'utilisation.

public int getColumns ()

Renvoie le nombre de colonnes occupées par la zone de saisie.

public Dimension preferredSize (int cols)public Dimension preferredSize ()public Dimension minimumSize (int cols)public Dimension minimumSize ()

Méthodes de la classe Component, outrepassées pour renvoyer la taille préférée ou la taille minimumd'une zone de saisie.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant la zonede saisie.

L'applet CalculetteSimple qui suit est un exemple simple de l'utilisation des classes TextField, Label etChoice. Elle permet d'afficher le résultat d'une opération simple (+, -, * et /) entre deux opérandes. Cetexemple montre au passage comment convertir une chaîne de caractères en un nombre d'un type de basegrâce à la méthode valueOf () de la classe Float (les classes Integer, Long et Double fournissent aussides méthodes similaires de conversion).

Page 215: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 14

et le programme Java correspondant (à copier dans un fichier dénommé CalculetteSimple.java et invoqué àpartir d'un fichier HTML) :

import java.awt.*;import java.applet.*; public class CalculetteSimple extends Applet{ TextField operande1 = new TextField ("2000"); TextField operande2 = new TextField ("1000"); Choice choixOperateur = new Choice (); Label labelResultat = new Label ("3000 "); public void init () { // Ajout des opérateurs à la liste choixOperateur.addItem (" + "); choixOperateur.addItem (" - "); choixOperateur.addItem (" * "); choixOperateur.addItem (" / "); // Ajout des composants à l'applet add (operande1); add (choixOperateur); add (operande2); add (labelResultat); } // Méthode appelée par la machine virtuelle quand on effectue // une action sur un des composants public boolean action (Event event, Object eventArg) { try { // Récupération des valeurs saisies dans les deux champs de saisies // La méthode static valueOf () de la classe Float est utilisée pour // convertir le texte saisi en un nombre. Cette méthode déclenche une // exception de classe NumberFormatException si la chaîne de caractères // à convertir n'est pas un nombre float valeur1 = Float.valueOf (operande1.getText ()).floatValue (); float valeur2 = Float.valueOf (operande2.getText ()).floatValue (); float resultat = 0; // Calcul suivant l'opérateur choisi switch (choixOperateur.getSelectedItem ().charAt (1)) { case '+' : resultat = valeur1 + valeur2; break; case '-' : resultat = valeur1 - valeur2; break; case '*' : resultat = valeur1 * valeur2; break; case '/' : resultat = valeur1 / valeur2; break; } labelResultat.setText (" = " + resultat); } catch (NumberFormatException e) { // Exception si un des deux opérandes n'est pas un nombre labelResultat.setText (" (Calcul impossible)"); } return true; }}

Autre exemple

Applet ListePolices .

Page 216: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 15

La classe java.awt.TextArea

Cette classe qui dérive des classes TextComponent et Component, est la classe du package java.awt quipermet de créer et de manipuler des zones de saisies de texte de plusieurs lignes. Une fois créé un objetde classe TextArea, vous devez l'ajouter à un container avec la méthode add () de la classe Container,pour le visualiser. Il est possible d'utiliser les zones de saisie de cette classe pour la saisie de mots depasse en précisant un caractère qui masque les caractères saisis. Toutes les méthodes permettant demanipuler le texte de la zone de saisie sont dans la classe TextComponent. Un exemple plus completutilisant la classe TextArea est donné au chapitre suivant.

Constructeurs

public TextArea ()public TextArea (int rows, int cols)public TextArea (String text)public TextArea (String text, int rows, int cols)

Ces constructeurs permettent de créer une zone de saisie avec ou sans un texte de départ, et enprécisant éventuellement le nombre de colonnes et de lignes que doit occuper la zone de saisie.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'unezone de saisie de plusieurs lignes.

public void insertText (String str, int pos)

Permet d'insérer la chaîne de caractères str à la position pos dans le texte de la zone de saisie.

public void appendText (String str)

Permet d'ajouter la chaîne de caractères str à la fin du texte de la zone de saisie.

public void replaceText (String str, int start, int end)

Permet de remplacer par la chaîne de caractères str la partie du texte de la zone de saisie comprise entreles indices start et end.

public int getRows ()public int getColumns ()

Ces méthodes permettent d'interroger le nombre de colonnes ou le nombre de lignes occupées par lazone de saisie.

public Dimension preferredSize (int cols)public Dimension preferredSize ()public Dimension minimumSize (int cols)public Dimension minimumSize ()

Méthodes de la classe Component, outrepassées pour renvoyer la taille préférée ou la taille minimumd'une zone de saisie.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant la zonede saisie.

Exemple

Applet TraitementTexte .

La classe java.awt.Scrollbar

Page 217: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 16

Cette classe qui dérive de la classe Component, est la classe du package java.awt qui permet de créer etde manipuler des ascenseurs. Une fois créé un objet de classe Scrollbar, vous devez l'ajouter à uncontainer avec la méthode add () de la classe Container, pour le visualiser.

Variables

public final static int HORIZONTALpublic final static int VERTICAL

Constantes utilisées pour préciser l'orientation d'un ascenseur.

Constructeurs

public Scrollbar ()public Scrollbar (int orientation)public Scrollbar (int orientation, int value, int visible, int minimum, int maximum )

Ces constructeurs permettent de créer un ascenseur en précisant éventuellement son orientation égale àHORIZONTAL ou VERTICAL (valeur par défaut).minimum et maximum sont des entiers représentant les valeurs logiques minimale et maximale que peutprendre l'ascenseur (par exemple, 0 et 100 ou -500 et 500). On entend par logique que ces valeurs nesont pas des valeurs en pixels ou représentant une grandeur physique de l'ordinateur, ce sont des valeursarbitraires qui n'ont un sens que dans la logique de votre programme (nombre de lignes, valeurs sur unaxe de coordonnées,...).value représente la position logique initiale de l'ascenseur (comprise entre minimum et maximum).visible représente la taille logique de la portion visible ; par exemple, si un ascenseur verticale estassocié à un dessin dont vous ne pouvez afficher que le tiers en hauteur, visible sera égal à (maximum -minimum) / 3.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'unascenseur.

public int getOrientation ()

Renvoie l'orientation de l'ascenseur ( HORIZONTAL ou VERTICAL).

public int getValue ()public void setValue (int value)

Ces méthodes permettent d'interroger ou de modifier la position courante d'un ascenseur. Si value estplus petite que le minimum de l'ascenseur ou plus grande que le maximum de l'ascenseur, ces valeursprennent respectivement value pour nouvelle valeur (ceci permet de rajouter facilement des "pages").

public int getMinimum ()public int getMaximum ()public int getVisible ()

Ces méthodes permettent d'interroger le minimum, le maximum et la taille logique de la portion visibled'un ascenseur.

public int getLineIncrement ()public void setLineIncrement (int increment)

Ces méthodes permettent d'interroger ou de modifier la valeur increment à ajouter ou à retrancher à lavaleur de la position courante, quand l'utilisateur clique sur les flèches de l'ascenseur.

public int getPageIncrement ()public void setPageIncrement (int increment)

Ces méthodes permettent d'interroger ou de modifier la valeur increment à ajouter ou à retrancher à la

Page 218: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 17

valeur de la position courante, quand l'utilisateur clique dans l'ascenseur.

public void setValues (int value, int visible, int minimum, int maximum)

Modifie la valeur courante, la taille logique de la portion visible, le minimum et le maximum d'unascenseur.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivantl'ascenseur.

Comment ça marche ?

Afin de comprendre l'enchaînement des différentes méthodes appelées par le navigateur et une applet,l'applet suivante vous montre le comportement d'une applet simple utilisant un bouton, dont voici leprogramme (simplifié) :

import java.applet.Applet;import java.awt.*; public class AppletButton extends Applet { public void init () { Button bouton = new Button ("OK"); add (bouton); }}

Sous le bouton, une liste affichant l'ensemble des appels aux méthodes a été ajoutée.

Le peer d'un composant

Si vous pouvez visualiser cette page sous différents systèmes, vous verrez que les composants dupackage java.awt prennent à chaque fois l'aspect de ceux du système sur lequel le navigateurfonctionne. En regardant le programme Java des classes Component ou de ses dérivées, vous découvrirezque toutes ces classes ne comportent aucune instruction spécifique à chacun des systèmes : par exemple,la classe Button décrite dans le fichier Button.java, est la même pour toutes les Machines VirtuellesJava que vous soyez sous Windows, MacOS, UNIX,... Comment ceci est-il possible alors qu'un boutonn'a pas le même aspect et est géré différemment sous chacun de ces systèmes ?En fait, chaque composant du package java.awt a son pair (peer en anglais) auquel il est associé. Laclasse de ce deuxième objet implémente l'interface Peer associée à la classe du composant (par exemplel'interface ButtonPeer pour un composant de classe Button). Cet objet est mémorisé dans la variableprivate peer de la classe Component. L'ensemble des interfaces Peer sont déclarées dans le packagejava.awt.peer.La variable peer d'interface ComponentPeer permet de mémoriser un objet dont la classe implémentecette interface ou une de ses dérivées comme par exemple ButtonPeer. Pour créer un objet d'interfaceButtonPeer, il faut qu'il existe quelque part une classe implémentant cette interface. Si vous effectuezune recherche dans toutes les classes du package java.awt, vous verrez que Java ne fournit aucuneclasse implémentant ButtonPeer !?! Et c'est là qu'est l'astuce : chaque Machine Virtuelle fournit desclasses dont l'utilisateur n'a pas connaissance et qui implémentent chacune des interfaces Peer . Cesclasses déclarent des méthodes native, dont l'implémentation fait appel aux fonctions du système surlequel la Machine Virtuelle fonctionne (comme par exemple la fonction CreateWindow () utilisée pourcréer un composant sous Windows).Reste une chose : Comment sont liées les classes de composant du package java.awt et les classes de lamachine virtuelle implémentant les interfaces Peer ? Par exemple, comment la classe Button fait pourretrouver la classe qui implémente l'interface ButtonPeer, pour pouvoir créer un objet de cette classe ?Il existe une classe Toolkit qui est abstract. En observant cette classe vous verrez qu'il existe toutesles méthodes qui permettent de créer un objet d'interface Peer, et notamment la méthode createButton() qui renvoie un objet d'interface ButtonPeer. Toutes ces méthodes de création sont abstract. La

Page 219: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 18

Machine Virtuelle définit une classe dérivant de Toolkit qui implémente toutes ces méthodes abstract.Par exemple, la méthode createButton () va être implémentée de manière à créer une instance de laclasse implémentant ButtonPeer.Le nom de la classe dérivée de Toolkit est mémorisée dans la propriété "awt.toolkit". Grâce à cettepropriété, la méthode static getDefaultToolkit () de la classe Toolkit peut, en appelantSystem.getProperty ("awt.toolkit"), retrouver le nom de cette classe et l'instancier avecClass.forName (nomClasseDeriveeDeToolkit).newInstance (). Ainsi, après avoir obtenu une instancede Toolkit, un bouton crée son pair en appelant createButton (), et le tour est joué !L'appel aux fonctions de la classe Toolkit, s'effectue dans la méthode addNotify () d'un composant etnon dans le constructeur d'un composant. Cette méthode est invoquée soit quand on ajoute uncomposant à un container avec la méthode add (), soit pour les fenêtres dont la classe dérive de Windowquand on appelle la méthode show (). La méthode show () appelle addNotify () pour la fenêtre et pourtous les composants qui lui ont été ajoutés.En conclusion, les classes de composants du package java.awt sont en fait des représentations logiquesdes composants et leur objet peer est une représentation à l'écran du composant.

Pour mieux visualiser le raisonnement précédent, la figure suivante montre l'enchaînement des méthodesappelées pour créer un bouton :

figure 14. Etapes de la création d'un bouton

Si vous ne maîtrisez pas encore la notion d'interface ou le fonctionnement des composants d'uneinterface utilisateur, vous risquez sûrement de trouver fumeuse l'explication précédente. Après avoirécrit quelques programmes Java, votre curiosité vous amènera peut-être à y revenir.De toute façon, ce raisonnement a été construit en consultant le code source de Java alors n'hésitezpas à faire de même pour plus de renseignements.

Ce système comporte deux inconvénients importants :

Vous ne pouvez pas modifier l'aspect d'un composant prédéfini car c'est le peer de cescomposants qui gère leur dessin.Donc, si par exemple, vous voulez créer un bouton affichant un dessin à la place d'un texte, necréez pas une classe dérivée de Button en outrepassant la méthode paint (), mais plutôt uneclasse dérivée de Canvas. Ceci implique que dans cette classe, vous devrez non seulementredessiner entièrement le bouton en outrepassant la méthode paint (), mais en plusreprogrammer son comportement (enfoncement, relâchement, ...). La taille d'un composant prédéfini ne peut être connue ou modifiée tant que sa méthodeaddNotify () n'a pas encore été appelée. En effet, la taille d'un composant est établie qu'une foisque son peer a été créé. Ce n'est qu'à partir de ce moment que vous pouvez interroger sa taillepréférée ou modifier sa taille.

La classe java.awt.Toolkit

Page 220: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 19

Cette classe abstract déclare un ensemble de méthodes abstract appelées pour créer le peer descomposants, des menus du package java.awt, gérer les images et obtenir des informations sur l'interfacegraphique. Pour obtenir une instance de cette classe, vous pouvez appelez la méthode getToolkit () dela classe Component ou la méthode static getDefaultToolkit () de cette classe.

Méthodes

protected abstract ButtonPeer createButton (Button target)protected abstract ChoicePeer createChoice (Choice target)protected abstract ListPeer createList (List target)protected abstract CheckboxPeer createCheckbox (Checkbox target)protected abstract LabelPeer createLabel (Label target)protected abstract TextAreaPeer createTextArea (TextArea target)protected abstract TextFieldPeer createTextField (TextField target)protected abstract ScrollbarPeer createScrollbar (Scrollbar target)protected abstract CanvasPeer createCanvas (Canvas target)protected abstract PanelPeer createPanel (Panel target)protected abstract FramePeer createFrame (Frame target)protected abstract WindowPeer createWindow (Window target)protected abstract DialogPeer createDialog (Dialog target)protected abstract FileDialogPeer createFileDialog (FileDialog target)protected abstract MenuBarPeer createMenuBar (MenuBar target)protected abstract MenuItemPeer createMenuItem (MenuItem target)protected abstract MenuPeer createMenu (Menu target)protected abstract CheckboxMenuItemPeer createCheckboxMenuItem (CheckboxMenuItem target)

Ces méthodes sont appelées dans les méthodes addNotify () des classes de composants passés enparamètre, pour créer le peer de ce composant. Vous n'avez pas à appeler ces méthodes.

public abstract Dimension getScreenSize ()

Renvoie la taille de l'écran.

public abstract int getScreenResolution ()

Renvoie la résolution de l'écran en points par pouce (dpi).

public abstract ColorModel getColorModel ()

Renvoie le modèle de couleur utilisé.

public abstract String [ ] getFontList ()

Renvoie la liste des polices de caractères disponibles.

public abstract FontMetrics getFontMetrics (Font font)

Renvoie la taille de la police de caractères font.

public abstract void sync ()

Synchronise l'affichage graphique ; cette méthode peut être utile pour réaliser des animations.

public abstract Image getImage (String filename)public abstract Image getImage (URL url)

Ces méthodes permettent d'obtenir l'image du fichier filename ou à l'URL url. L'image n'esteffectivement chargée qu'à sa première utilisation (voir le chargement des images).

public abstract boolean prepareImage (Image image, int width, int height, ImageObserver observer)public abstract int checkImage (Image image, int width, int height, ImageObserver observer)

Ces méthodes permettent de gérer le chargement d'une image.

public abstract Image createImage (ImageProducer producer)

Page 221: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les composants de l'interface utilisateur Page: 20

Permet de créer une image.

public synchronized static Toolkit getDefaultToolkit ()

Renvoie le toolkit par défaut.

Exemples

Applets ListePolices et BoutonsNavigation .

Page 222: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 1

Les containerset la disposition des composants

Les containersLa disposition des composants : les layouts

Les menus

Les containers

L'architecture container/composant

Les containers sont des composants qui contiennent d'autres composants. Ce type d'architecture donneaux containers un ensemble de caractéristiques qui leur sont propres :

Chaque container mémorise la liste des composants qu'on lui ajoute avec les méthodes add () ouqu'on lui enlève avec les méthodes remove () et removeAll (). Un container dispose à l'écran les composants qu'il contient, grâce à un layout qui lui est associé. Il s'occupe d'envoyer les événements qui surviennent (clic de souris, touche du clavier,...) aucomposant concerné ou de les traiter lui-même.

Il existe ainsi une relation entre un container et ses composants. Comme un composant peut êtrelui-même un container contenant d'autres composants, l'ensemble de ces relations parent-enfant peut sedécrire sous forme d'un arbre, comme dans l'applet suivante, qui reproduit les commandes Couper /Copier / Coller / Effacer d'un traitement de texte :

Voici le programme Java correspondant (à copier dans un fichier dénommé TraitementTexte.java etinvoqué à partir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.util.Date; public class TraitementTexte extends Applet{ private TextArea texte = new TextArea (); private String texteCopie = ""; public void init () { // Choix d'un layout BorderLayout (FlowLayout par défaut) setLayout (new BorderLayout ()); // Création d'une barre de boutons avec les commandes // Couper/Copier/Coller/Effacer (layout FlowLayout par défaut) Panel panel = new Panel (); panel.add (new Button ("Couper")); panel.add (new Button ("Copier")); panel.add (new Button ("Coller")); panel.add (new Button ("Effacer")); // Ajout en haut de la barre de boutons

Page 223: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 2

add ("North", panel); // Ajout au centre de la zone de saisie add ("Center", texte); // Ajout en bas d'un label add ("South", new Label ( "Du C/C++ a Java " + new Date ().toLocaleString ())); } // Méthode appelée par la machine virtuelle quand on clique sur un bouton public boolean action (Event event, Object eventArg) { if ("Couper".equals (eventArg)) { // Simulation d'une action Copier/Effacer postEvent (new Event (this, Event.ACTION_EVENT, "Copier")); postEvent (new Event (this, Event.ACTION_EVENT, "Effacer")); } else if ("Copier".equals (eventArg)) // Récupération du texte sélectionné texteCopie = texte.getSelectedText (); else if ("Coller".equals (eventArg)) // Remplacement de la sélection par texteCopie texte.replaceText (texteCopie, texte.getSelectionStart (), texte.getSelectionEnd ()); else if ("Effacer".equals (eventArg)) // Remplacement de la sélection par rien texte.replaceText ("", texte.getSelectionStart (), texte.getSelectionEnd ()); return true; }}

Les relations entre les composants de l'applet précédente décrivent l'arbre suivant :

figure 15. Arbre des composants de l'applet TraitementTexte

Ne mélangez pas les concepts de graphe d'héritage entre classes et de graphe de parenté entrecomposants !... Ces liens de parenté ne sont le résultat que de la composition entre classes : chaquecomposant mémorise dans une variable private, une référence sur son parent que l'on peut obtenirgrâce à la méthode getParent () de la classe Component.

Chaque composant et par conséquent chaque container possède son propre système de coordonnées.L'origine de ce repère est situé en haut à gauche du composant, l'axe des x va vers la droite, et l'axe desy vers le bas. Ceci forme un repère indirect, ce qui n'est pas très pratique pour afficher des courbesmathématiques, mais comme presque tous les systèmes informatiques utilisent cette convention...Chaque composant (container ou pas) est positionné dans le repère du container qui le contient,c'est-à-dire que dans l'exemple précédent, le bouton Copier est positionné par rapport au repère ducontainer de classe Panel qui le contient, et ce container est positionné dans le repère de l'applet. Laméthode location () de la classe Component invoquée sur ce bouton vous renverra donc lescoordonnées du bouton dans son parent et non dans l'applet ; de même, si vous utilisez la méthode move(x, y) de la classe Component pour placer un composant comp, il faut fournir des coordonnées (x,y)relatives au container qui contient comp.

Page 224: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 3

Les containers sont généralement utilisés pour y ajouter des composants mais vous pouvez aussi yafficher des dessins fabriqués avec les méthodes de la classe Graphics en outrepassant par exemple laméthode paint () de la classe Component. Mais évitez de mélanger ces deux styles, car les composantssont disposés par un layout à des positions qui ne sont pas toujours les mêmes suivant les systèmes, etvos dessins pourraient être recouverts par des composants.Il vaut mieux dans ce cas créer une nouvelle classe de composant CanvasDessin dérivant de Canvas,où vous effectuez vos dessins, puis ajouter une instance de CanvasDessin au container.

La classe java.awt.Container

Cette classe abstract qui dérive de la classe Component, est la super classe de toutes les classes decontainer. Elle définit notamment un certains nombres de méthodes, qui permettent d'ajouter oud'enlever des composants aux containers, ou qui disposent les composants dans un container grâce à sonlayout associé.

Méthodes

public Component add (Component comp)public synchronized Component add (Component comp, int pos)public synchronized Component add (String name, Component comp)

Ces méthodes permettent d'ajouter le composant comp à un container et de créer le lien parent-enfant. Lecontainer garde une liste ordonnée des composants qui lui sont ajoutés, ce qui permet aux layouts de lesdisposer dans cet ordre si nécessaire. Par défaut, pos = -1, ce qui implique que le composant est ajouté àla fin de la liste des composants.La troisième méthode, en plus d'ajouter le composant en fin de liste, appelle la méthodeaddLayoutComponent (name, comp) de l'interface LayoutManager, si le container a un layout. Certainesclasses de layout comme BorderLayout, implémentent cette méthode pour utiliser les informationscontenues dans name et placer le composant autrement qu'en utilisant uniquement son numéro d'ordre.Si le peer du container existe déjà, ces méthodes appellent la méthode addNotify () du composant comp.

public synchronized void remove (Component comp)public synchronized void removeAll ()

Ces méthodes permettent d'enlever le composant comp ou tous les composants d'un container.

Si vous ajoutez ou enlevez un composant d'un container qui est déjà à l'écran, n'oubliez pas d'appelerla méthode validate () sur le container, sinon votre container restera inchangé à l'écran (voirl'exemple de la classe BorderLayout).

public int countComponents ()

Renvoie le nombre de composants que contient un container.

public synchronized Component getComponent (int n) throws ArrayIndexOutOfBoundsExceptionpublic synchronized Component [ ] getComponents ()

Ces méthodes renvoient le nième composant ou tous les composants d'un container.

public LayoutManager getLayout ()public void setLayout (LayoutManager manager)

Ces méthodes permettent d'interroger ou de modifier le layout utilisé par un container. Toutes lesclasses dérivées de container ont un layout par défaut.

public synchronized void layout ()

Méthode de la classe Component, outrepassée pour disposer les composants d'un container.

public synchronized void validate ()

Méthode de la classe Component, outrepassée pour mettre à jour tous les composants d'un container

Page 225: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 4

invalide.

public Insets insets ()

Renvoie la largeur des bordures du container en haut, en bas, à gauche et à droite. Comme cette méthodeinterroge le peer du container, les valeurs renvoyées ne sont valides que si son peer existe déjà.

public synchronized Dimension preferredSize ()public synchronized Dimension minimumSize ()

Ces méthodes renvoient la taille préférée et la taille minimum d'un container. Si le container a un layout,ces méthodes renvoient les dimensions respectivement données par les méthodes preferredLayoutSize() et minimumLayoutSize () de l'interface LayoutManager.

public void paintComponents (Graphics g)public void printComponents (Graphics g)

Ces méthodes redessine ou imprime tous les composants d'un container.

public void deliverEvent (Event e)

Cette méthode qui outrepasse celle de la classe Component est utilisée pour la gestion événementielle(voir le chapitre suivant).

public Component locate (int x, int y)

Méthode de la classe Component outrepassée pour rechercher le composant situé au point decoordonnées (x,y) d'un container.

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour appeler la méthodeaddNotify () sur chacun des composants du container.

public synchronized void removeNotify ()

Cette méthode outrepasse la méthode removeNotify () de la classe Component pour appeler la méthoderemoveNotify () sur chacun des composants du container.

protected String paramString ()

Méthode de la classe Component, outrepassée pour renvoyer une chaîne de caractères décrivant lecontainer.

public void list (PrintStream out, int indent)

Méthode de la classe Component, outrepassée pour imprimer sur out la chaîne de caractères décrivant lecontainer et tous composants.

La classe java.awt.Panel

Cette classe qui dérive des classes Container et Component, permet de créer un container utilisé commezone d'affichage pour y ajouter des composants ou pour y dessiner directement avec les méthodes declasse Graphics. Le layout utilisé par défaut par la classe Panel est la classe FlowLayout. Cette classe estla super classe Applet.

Constructeur

public Panel ()

Méthode

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Container pour créer le peer d'un panel

Page 226: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 5

puis appeler la méthode addNotify () de la classe Container.

Exemples

Applets TraitementTexte , DrawIt , ListePolices et Nuancier .

La classe java.awt.Window

Cette classe qui dérive des classes Container et Component, permet de créer une fenêtre sans bord, nititre, ni menu. Contrairement à ses classes dérivées Dialog et Frame, elle est peu utile mais peut servirpar exemple comme bannière au lancement d'un programme, pour afficher une image. Le layout utilisépar défaut par la classe Window est la classe BorderLayout.

N'oubliez pas d'appeler la méthode show () pour afficher une fenêtre et de la dimensionner à la taillecorrecte avec les méthodes pack () ou les méthodes resize () ou reshape () de la classe Component.

Constructeur

public Window (Frame parent)

Ce constructeur construit une fenêtre invisible dont le parent parent doit être de classe Frame ou sesdérivées.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Container pour créer le peer d'unefenêtre puis appeler la méthode addNotify () de la classe Container.

public synchronized void pack ()

Cette méthode permet de dimensionner la fenêtre à la taille donnée par la méthode preferredSize () dela classe Container. Si les peers de la fenêtre et des composants qu'elle contient n'existent pas encore,ceux-ci sont créés pour que la taille renvoyée soit correcte.

public void show ()

Méthode de la classe Component, outrepassée pour afficher la fenêtre et les composants qu'elle contient.Si la fenêtre est déjà visible, la fenêtre est ramenée devant toutes les autres.Cette méthode appelle la méthode addNotify (), ce qui a pour conséquence de créer à l'écran la fenêtreet tous les composants qui lui ont été ajoutés.Vous devez appeler au moins une fois cette méthode par fenêtre car elles sont créées invisibles.Le parent de la fenêtre n'a pas forcément besoin d'être visible pour que cette méthode fonctionne.

public synchronized void dispose ()

Détruit une fenêtre. Vous devez appeler cette méthode pour que la fenêtre à l'écran soit effectivementdétruite.

public void toFront ()public void toBack ()

Ces méthodes ramène une fenêtre devant ou derrière toutes les autres.

public Toolkit getToolkit ()

Méthode de la classe Component, outrepassée pour renvoyer le kit d'outils (Toolkit ) par défaut utilisépour la création du peer d'un composant.

public final String getWarningString ()

Renvoie le warning d'une fenêtre. Ce type de message est affiché dans les fenêtres créées dans un

Page 227: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 6

navigateur.

La classe java.awt.Frame

Cette classe qui dérive des classes Window, Container et Component et implémente l'interfaceMenuContainer permet de créer une fenêtre indépendante avec un cadre, un titre, et éventuellement unmenu et un pointeur de souris propre.

Variables

public final static int DEFAULT_CURSORpublic final static int CROSSHAIR_CURSORpublic final static int TEXT_CURSORpublic final static int WAIT_CURSORpublic final static int SW_RESIZE_CURSORpublic final static int SE_RESIZE_CURSORpublic final static int NW_RESIZE_CURSORpublic final static int NE_RESIZE_CURSORpublic final static int N_RESIZE_CURSORpublic final static int S_RESIZE_CURSORpublic final static int W_RESIZE_CURSORpublic final static int E_RESIZE_CURSORpublic final static int HAND_CURSORpublic final static int MOVE_CURSOR

Ces constantes représentent les pointeurs de souris prédéfinis que vous pouvez choisir dans une fenêtreavec la méthode setCursor ().

Constructeurs

public Frame ()public Frame (String title)

Ces constructeurs créent une fenêtre avec ou sans titre title.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Window pour créer le peer d'une fenêtreet son éventuel menu, puis appeler la méthode addNotify () de la classe Window.

public String getTitle ()public void setTitle (String title)

Ces méthodes permettent d'interroger ou de modifier le titre d'une fenêtre.

public Image getIconImage ()public void setIconImage (Image image)

Ces méthodes permettent d'interroger ou de modifier l'image utilisée quand une fenêtre est icônifiée,mais tous les systèmes n'utilisent pas cette caractéristique.

public MenuBar getMenuBar ()public synchronized void setMenuBar (MenuBar menubar)

Ces méthodes permettent d'interroger ou de modifier la barre de menu utilisée pour une fenêtre.

public synchronized void remove (MenuComponent menu)

Enlève le menu menu de la fenêtre.

public synchronized void dispose ()

Méthode de la classe Window, outrepassée pour détruire une fenêtre. Vous devez appeler cette méthodepour que la fenêtre à l'écran soit effectivement détruite.

public boolean isResizable ()

Page 228: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 7

Renvoie true si la fenêtre est redimensionnable interactivement.

public void setResizable (boolean resizable)

Permet de spécifier si une fenêtre est redimensionnable interactivement ou non.

public int getCursorType ()public void setCursor (int cursorType)

Ces méthodes permettent d'interroger ou de modifier le curseur de souris utilisé dans une fenêtre.cursorType doit être une des constantes dont la liste est donnée avec les variables.

protected String paramString ()

Méthode de la classe Container, outrepassée pour renvoyer une chaîne de caractères décrivant lafenêtre.

Exemples

Applets BorderBuilder et ShowMenu .Application TraitementTexte .

Transformer une applet en application isolée

La classe d'une applet héritant de la classe Panel, il est possible d'ajouter une applet à une fenêtre declasse Frame. Grâce à cette caractéristique, vous pouvez ajouter à la plupart de vos applets la facultéd'être utilisées comme applications isolées, en leur ajoutant une méthode main () qui crée une instancede Frame pour y ajouter une instance de votre applet (les limitations de ce système sont décrites auchapitre sur les applets).Voici par exemple comment transformer l'applet de classe TraitementTexte définie au début de cechapitre pour en faire une application isolée :

public class TraitementTexte extends Applet{ // Code précédemment défini... public static void main (String [ ] args) { // Création d'une fenêtre et d'une instance de l'applet Frame fenetreApplet = new Frame ("TraitementTexte"); Applet applet = new TraitementTexte (); // Ajout de l'applet à la fenêtre puis affichage de la fenêtre fenetreApplet.add ("Center", applet); fenetreApplet.show (); fenetreApplet.resize (300, 200); // Démarrage de l'applet applet.init (); fenetreApplet.validate (); }}

La classe java.awt.Dialog

Cette classe qui dérive des classes Window, Container et Component permet de créer une boite dedialogue avec un cadre et un titre. Les boites de dialogues ont un parent de classe Frame, et peuvent êtremodale ou non. Une boite de dialogue qui est modale bloque toute entrée dans les autres fenêtres tantqu'elle est ouverte.

Quand une boite de dialogue est modale, l'utilisateur ne peut plus manipuler que cette boite dedialogue et plus les autres fenêtres créées par la Machine Virtuelle Java. A l'appel de la méthode show() sur une boite de dialogue modale dialog1, la boite de dialogue est affichée et les instructions quisuivent show () ne sont exécutées qu'une fois que dialog1 est détruite. N'oubliez donc pas de détruirevos boites de dialogues une fois son traitement terminé avec la méthode dispose ().

Page 229: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 8

Constructeurs

public Dialog (Frame parent, boolean modal)public Dialog (Frame parent, String title, boolean modal)

Ce constructeur construit une boite de dialogue invisible avec ou sans titre title, dont le parent parentdoit être de classe Frame ou ses dérivées. Cette boite de dialogue peut être modale ou non.

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Window pour créer le peer d'une boite dedialogue, puis appeler la méthode addNotify () de la classe Window.

public boolean isModal ()

Renvoie true si la boite de dialogue est modale.

public String getTitle ()public void setTitle (String title)

Ces méthodes permettent d'interroger ou de modifier le titre d'une boite de dialogue.

public boolean isResizable ()

Renvoie true si la boite de dialogue est redimensionnable interactivement.

public void setResizable (boolean resizable)

Permet de spécifier si une boite de dialogue est redimensionnable interactivement ou non.

protected String paramString ()

Méthode de la classe Container, outrepassée pour renvoyer une chaîne de caractères décrivant la boitede dialogue.

La bibliothèque Java ne fournissant pas en standard une boite de dialogue affichant simplement unmessage, voilà l'applet MessageBoxApplet qui peut vous servir de base pour en réaliser une :

en cliquant sur le bouton, on obtient le résultat suivant :

Voici le programme Java correspondant (à copier dans un fichier dénommé MessageBoxApplet.java etinvoqué à partir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class MessageBoxApplet extends Applet{ public void init () { add (new Button ("Afficher message")); } // Méthode appelée par la machine virtuelle quand on clique sur le bouton public boolean action (Event event, Object eventArg) { MessageBox.showMessageBox(this, "Message", "Ceci est un message...");

Page 230: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 9

return true; }} class MessageBox extends Dialog{ private MessageBox (Frame frame, String titre) { // Appel du constructeur de la classe Dialog en mode modal super (frame, titre, true); } static public void showMessageBox (Component parent, String titre, String message) { // Recherche du parent qui est un Frame Component frame = parent; while ( frame != null && !(frame instanceof Frame)) frame = frame.getParent (); // Création d'une instance de MessageBox MessageBox boite = new MessageBox ((Frame)frame, titre); // Ajout du message et d'un bouton Ok boite.add ("Center", new Label (message)); boite.add ("East", new Button ("Ok")); // Affichage de la boite de message // show () ne rend la main que quand la boite est détruite boite.setResizable (false); boite.pack (); boite.show (); } // Méthode appelée quand on clique sur Ok public boolean action (Event event, Object eventArg) { // Destruction de la boite de message dispose (); return true; }}

La classe java.awt.FileDialog

Cette classe qui dérive des classes Dialog, Window, Container et Component permet de créer une boite dedialogue de saisie de fichier. Comme pour tous les composants du package java.awt, cette boite dedialogue est celle communément utilisée avec le système sur lequel fonctionne l'applet. Comme cetteclasse donne accès au système de fichiers, certains navigateurs interdisent tout simplement de s'en servir.

Variables

public final static int LOADpublic final static int SAVE

Ces constantes sont utilisées pour choisir le mode de saisie du fichier de la boite de dialogue (Ouvrir ouEnregistrer ).

Constructeurs

public FileDialog (Frame parent, String title)public FileDialog (Frame parent, String title, int mode)

Ce constructeur construit une boite de dialogue invisible de saisie de fichier avec ou sans titre title,dont le parent parent doit être de classe Frame ou ses dérivées. Par défaut, le mode saisie est LOAD.

Méthodes

public synchronized void addNotify ()

Page 231: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 10

Cette méthode outrepasse la méthode addNotify () de la classe Dialog pour créer le peer d'une boite dedialogue de saisie de fichier, puis appeler la méthode addNotify () de la classe Dialog.

public int getMode ()

Ces méthodes permettent d'interroger le mode saisie du fichier (LOAD ou SAVE).

public String getDirectory ()public void setDirectory (String dir)

Ces méthodes permettent d'interroger ou de modifier le répertoire courant de la boite de dialogue.

public String getFile ()public void setFile (String file)

Ces méthodes permettent d'interroger ou de modifier le fichier saisie dans la boite de dialogue.

public FilenameFilter getFilenameFilter ()public void setFilenameFilter (FilenameFilter filter)

Ces méthodes permettent d'interroger ou de modifier le filtre utilisé pour la saisie du fichier, par exemplepour n'accepter que les fichiers se terminant par .java (ce qui correspondrait à *.java ).

protected String paramString ()

Méthode de la classe Container, outrepassée pour renvoyer une chaîne de caractères décrivant la boitede dialogue de saisie de fichier.

La disposition des composants : les layouts

Associé à chaque container, existe un gestionnaire qui permet de disposer les éventuels composants quecontient le container : ce sont les layouts . Il est conseillé d'utiliser ce type de gestionnaire pour indiquerla position des composants plutôt que les coordonnées pixel qui ne garantissent pas le même rendu surchacune des plateformes où peuvent fonctionner une applet (par exemple, un bouton n'a pas le mêmeaspect ni la même taille sous tous les systèmes).Globalement, il existe trois solutions pour donner une position à un composant :

En utilisant une des cinq classes de layout fournies avec Java : FlowLayout, BorderLayout,GridLayout, GridBagLayout ou CardLayout. En créant et en utilisant une classe de layout qui implémente l'interface LayoutManager. Cetteinterface déclare un ensemble de méthodes qui permettent de gérer et de placer les composantsd'un container (Les cinq classes précédentes implémentent cette interface). En n'utilisant aucun layout (grâce à setLayout (null)) et en plaçant les composants "à la main"dans le container, au pixel près grâce aux méthodes move (), resize () ou reshape () de la classeComponent. Dans ce cas, n'oubliez pas de prendre en compte la largeur des bordures du containerrenvoyées par la méthode insets () de la classe Container.

Le choix d'un layout se fait grâce à la méthode setLayout () de la classe Container.Les composants d'un container container1 sont positionnés à l'appel de la méthode layout () de laclasse Container sur container1. Cette méthode appelle le gestionnaire qui dispose les composants dansle container. Elle est appelée par la méthode validate () de la classe Component si le container ou un deses composants ne sont pas valides (à leur première visualisation, quand ils changent de taille,...).Quand le container est déjà visualisé, l'ajout (ou la suppression) d'un composant à ce container n'appellepas validate () automatiquement : il vous faut donc appeler cette méthode dans ce cas de figure pourmettre à jour la disposition des composants dans le container (voir l'exemple de la classe BorderLayout).

Les classes de Java dérivant de la classe container utilisent un layout par défaut : Les classes Panel etApplet utilisent la classe FlowLayout, et les classes Window, Dialog et Frame la classe BorderLayout.

Page 232: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 11

Si dans certains cas, les classes de layout fournies avec Java ne semblent pas vous convenir, n'oubliezpas avant d'envisager de créer un layout de toute pièce que vous pouvez très bien combiner les layoutsexistants. En effet, chaque container étant lui-même un composant vous pouvez agencer une partie devos composants en les incluant dans un sous-container (de classe Panel par exemple) qui disposera cescomposants de manière différente que le layout du container principal. Donc, étudiez bien l'effet dechacun des layouts suivants et soyez imaginatifs ! Toutes les combinaisons sont possibles...L'exemple du paragraphe sur les containers combine deux layouts, l'un de classe BorderLayout etl'autre de classe FlowLayout.

Si vous voulez n'utiliser aucun layout pour un container, il est très fortement conseillé d'outrepasser laméthode layout () de la classe Container pour y disposer vos composants. En effet, pour pouvoirplacer sans problème vos composants leur peer doit exister. Le peer d'un container et de sescomposants est créé à l'appel de la méthode addNotify () de la classe Container. Cette méthode n'estpas appelée au même moment pour une applet et une fenêtre indépendante, mais elle est toujourssuivie d'un appel à validate () et donc d'un appel à la méthode layout () :

Pour une applet, addNotify () est appelée juste avant que le navigateur n'appelle les méthodesvalidate () et init () de la classe Applet (voir l'exemple décrivant l'ensemble des méthodesappelées à la création d'une applet). Pour une fenêtre indépendante (de classe Frame ou Dialog par exemple), addNotify () estinvoquée par la méthode show () de la classe Window, qui appelle ensuite la méthode validate().

L'interface java.awt.LayoutManager

L'interface LayoutManager déclare cinq méthodes que doit définir toute classe qui l'implémente (même sices méthodes ne font rien).

Méthodes

public void addLayoutComponent (String name, Component component)

Méthode appelée quand le composant component est ajouté à un container par la méthode add (name,component) de la classe Container. Utiliser cette méthode si vous voulez mémoriser les informationssupplémentaires décrites dans name et associées au composant component pour le placer. Cette méthodeest utilisée par exemple par la classe BorderLayout. Rappelez-vous qu'il n'est pas obligatoire demémoriser la liste de tous les composants d'un container, car la classe Container fournit la méthodegetComponents () qui renvoient la liste de tous les composants ajoutés à un container.

public void removeLayoutComponent (Component component)

Méthode appelée quand le composant component est enlevé d'un container par la méthode remove(component) de la classe Container.

public Dimension preferredLayoutSize (Container parent)

Doit renvoyer les dimensions préférées du container parent auquel ont été ajoutés des composants.

public Dimension minimumLayoutSize (Container parent)

Doit renvoyer les dimensions minimum du container parent auquel ont été ajoutés des composants.

public void layoutContainer (Container parent)

Doit positionner les composants du container parent. Cette méthode est appelée par la méthode layout() de la classe Container si le container parent utilise un layout. C'est donc cette méthode qui place lescomposants dans le container parent, en utilisant les méthodes move (), resize () ou reshape () de laclasse Component et en prenant en compte la largeur des bordures du container renvoyées par la méthodeinsets () de la classe Container.

La classe java.awt.FlowLayout

Page 233: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 12

Cette classe qui implémente l'interface LayoutManager, est le type de layout le plus simple. Lescomposants d'un container container1 géré par un FlowLayout sont positionnés les uns derrière lesautres, en partant du coin en haut à gauche de container1, puis en occupant horizontalement aumaximum la largeur de container1, avant de passer à une ligne suivante.Chaque composant prend les dimensions que renvoie sa méthode preferredSize ().

Variables

public final static int LEFTpublic final static int CENTERpublic final static int RIGHT

Constantes utilisées pour l'alignement des composants dans le container (sur le bord gauche, au centre,ou sur le bord droit). Par défaut, l'alignement est CENTER.

Constructeurs

public FlowLayout ()public FlowLayout (int align)public FlowLayout (int align, int horizontalgap, int verticalgap)

Ces constructeurs permettent de créer un layout FlowLayout avec un alignement align (LEFT, CENTER ouRIGHT) et un espacement horizontal et vertical entre les composants de horizontalgap et verticalgappixels (par défaut égal à 5).

Méthodes

public void addLayoutComponent (String name, Component comp)public void removeLayoutComponent (Component comp)public Dimension preferredLayoutSize (Container target)public Dimension minimumLayoutSize (Container target)public void layoutContainer (Container target)

Implémentation des méthodes de l'interface LayoutManager. addLayoutComponent () etremoveLayoutComponent () ne font rien.

public String toString ()

Exemples

Les applets BorderBuilder , MiseAJourHorloge et BoutonsNavigation affichent leurs composants avecleur layout par défaut de classe FlowLayout.L'applet TraitementTexte utilise une barre de boutons qui sont ajoutés à un sous-container de classePanel utilisant son layout par défaut de classe FlowLayout.

La classe java.awt.BorderLayout

Cette classe qui implémente l'interface LayoutManager, est un type de layout qui permet de gérer laposition d'au plus cinq composants : La position d'un composant component est déterminée grâce lachaîne de caractères name passée en argument à la méthode add (name, component) de la classeContainer. Cette chaîne de caractères peut être égal à "North", "South", "East", "West" ou "Center".Les cinq composants (ou moins) sont redimensionnés pour occuper l'espace du container en respectantdans l'ordre, les règles suivantes :

Les composants "North" et "South" gardent la hauteur renvoyée par leur méthode preferredSize() et sont agrandis en horizontal pour occuper toute la largeur du container. Les composants "West" et "East" gardent la largeur renvoyée par leur méthode preferredSize ()et sont agrandis en vertical pour occuper toute la hauteur restante du container. Le composant "Center" occupe le reste de l'espace du container.

Cette classe de layout peut servir dans de nombreux types d'interfaces utilisateurs : Le composant"Center" peut représenter par exemple une zone de dessin ou d'édition de texte, les composants "North"et "West" être utilisés pour afficher des barres d'outils et les composants "East" et "South" pour desascenseurs (composant Scrollbar).

Page 234: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 13

Constructeurs

public BorderLayout ()public BorderLayout (int horizontalgap, int verticalgap)

Ces constructeurs permettent de créer un layout BorderLayout avec un espacement horizontal et verticalentre les composants de horizontalgap et verticalgap pixels (par défaut égal à 0).

Méthodes

public void addLayoutComponent (String name, Component comp)public void removeLayoutComponent (Component comp)public Dimension preferredLayoutSize (Container target)public Dimension minimumLayoutSize (Container target)public void layoutContainer (Container target)

Implémentation des méthodes de l'interface LayoutManager. L'implémentation de la méthodeaddLayoutComponent () mémorise pour chacune des cinq directions le composant qui lui est associé.

public String toString ()

Pour illustrer l'utilisation de la classe BorderLayout, voici un exemple d'applet permettant d'ajouter à unefenêtre indépendante des boutons aux cinq positions possibles (La fenêtre s'affiche quand vous cliquezsur un des boutons et est indépendante pour que vous puissiez la redimensionner et observer les effetsde la classe BorderLayout) :

donne le résultat suivant :

et le programme Java correspondant (à copier dans un fichier dénommé BorderBuilder.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class BorderBuilder extends Applet{ // Création des boutons de l'applet et du Frame Button [] appletButtons = {new Button ("Add North"), new Button ("Add South"), new Button ("Add West"), new Button ("Add East"), new Button ("Add Center")}; Button [] frameButtons = {new Button ("North"), new Button ("South"), new Button ("West"), new Button ("East"), new Button ("Center")}; Frame buttonsFrame; public void init () { // Ajout des boutons à l'applet (par défaut utilise FlowLayout) for (int i = 0; i < appletButtons.length; i++) add (appletButtons [i]); // Création d'une fenêtre (par défaut utilise BorderLayout)

Page 235: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 14

buttonsFrame = new Frame ("BorderLayout window"); buttonsFrame.resize (200, 200); } public void stop () { // A la fin de l'applet, destruction de la fenêtre buttonsFrame.dispose (); } // Méthode appelée par la machine virtuelle quand on clique sur un bouton public boolean action (Event event, Object eventArg) { // Affichage de la fenêtre buttonsFrame.show (); for (int i = 0; i < appletButtons.length; i++) if (event.target == appletButtons [i]) { // Si le label du bouton commence par Add, if (appletButtons [i].getLabel ().startsWith ("Add")) { // Ajouter le bouton correspondant à buttonsFrame buttonsFrame.add (frameButtons [i].getLabel (), frameButtons [i]); // Changer le nom du bouton de l'applet appletButtons [i].setLabel ("Remove " + frameButtons [i].getLabel ()); } else { // Sinon enlever le bouton correspondant de buttonsFrame buttonsFrame.remove (frameButtons [i]); // Changer le nom du bouton de l'applet appletButtons [i].setLabel ("Add " + frameButtons [i].getLabel ()); } // Mettre à jour les composants de l'applet et de la fenêtre appletButtons [i].invalidate (); validate (); buttonsFrame.validate (); return true; } return super.action (event, eventArg); }}

La classe BorderLayout vous oblige à vous servir de la méthode add (String name, Componentcomponent) de la classe Container pour ajouter les composants à un container.

Autres exemples

Applets TraitementTexte , MessageBoxApplet , DrawIt , ListePolices et Nuancier .

La classe java.awt.GridLayout

Cette classe qui implémente l'interface LayoutManager, est un layout permettant d'afficher lescomposants que contient un container sur une grille régulière. Le nombre de lignes et de colonnes étantpassés en argument au constructeur d'un layout GridLayout, la hauteur et la largeur d'un containercontainer1 géré par un GridLayout sont divisées par le nombre de lignes et de colonnes pour connaîtrela dimension de chaque cellule. Les composants de container1 sont ensuite positionnés dans lescellules, en partant du coin en haut à gauche de container1, puis colonne après colonne et ligne parligne.Chaque composant prend les dimensions de la cellule qu'il occupe.

Constructeurs

public GridLayout (int rows, int cols)public GridLayout (int rows, int cols, int horizontalgap, int verticalgap)

Ces constructeurs permettent de créer un layout GridLayout avec une grille de rows lignes par cols

Page 236: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 15

colonnes, et un espacement horizontal et vertical entre les composants de horizontalgap et verticalgappixels (par défaut égal à 0). Il n'est pas obligatoire de remplir entièrement la grille d'un layoutGridLayout, mais attention les lignes inoccupées restent vides ; donc évitez de créer un layoutGridLayout avec de grandes dimensions en prévision de son remplissage, sinon les cellules seront toutespetites !

Méthodes

public void addLayoutComponent (String name, Component comp)public void removeLayoutComponent (Component comp)public Dimension preferredLayoutSize (Container target)public Dimension minimumLayoutSize (Container target)public void layoutContainer (Container target)

Implémentation des méthodes de l'interface LayoutManager. addLayoutComponent () etremoveLayoutComponent () ne font rien.

public String toString ()

Exemples

Applets Unicode , DrawIt , ListePolices .L'applet GridBagBuilder de la classe GridBagLayout contient aussi un sous-container de classe Panel quiaffiche les composants des 17 premières lignes et des 2 colonnes avec un layout de classe GridLayout.

La classe java.awt.GridBagLayout

Cette classe qui implémente l'interface LayoutManager, est le layout le plus complet et le plus complexeà utiliser des layouts fournis avec Java.A chaque composant ajouté à un container géré par un layout GridBagLayout, sont associées descontraintes (constraints en anglais) décrivant comment placer ce composant dans le container. Cescontraintes sont décrites par une instance de la classe GridBagConstraint et positionnées sur lecomposant grâce à la méthode setConstraints () de la classe GridBagLayout.

Vu le nombre de paramètres utilisés par les contraintes, le placement des composants gérés par unlayout GridBagLayout est complexe et c'est pourquoi cette classe définit de nombreuses variables etméthodes protected, vous permettant de modifier le comportement de cette classe dans une classedérivée.

Variables

public int columnWidths [ ]public int rowHeights [ ]public double columnWeights [ ]public double rowWeights [ ] protected final static int MAXGRIDSIZEprotected final static int MINSIZEprotected final static int PREFERREDSIZE protected Hashtable comptableprotected GridBagConstraints defaultConstraintsprotected GridBagLayoutInfo layoutInfo

Constructeur

public GridBagLayout ()

Méthodes

public void addLayoutComponent (String name, Component comp)public void removeLayoutComponent (Component comp)public Dimension preferredLayoutSize (Container target)public Dimension minimumLayoutSize (Container target)public void layoutContainer (Container target)

Implémentation des méthodes de l'interface LayoutManager. addLayoutComponent () et

Page 237: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 16

removeLayoutComponent () ne font rien.

public void setConstraints (Component comp, GridBagConstraints constraints)

Positionne les contraintes sur un composant comp géré par un layout GridBagLayout.

public GridBagConstraints getConstraints (Component component)

Renvoie une copie des contraintes positionnées sur un composant géré par un layout GridBagLayout.

public Point getLayoutOrigin ()public int [ ][ ] getLayoutDimensions ()public double [ ][ ] getLayoutWeights ()public Point location (int x, int y) public String toString () protected GridBagLayoutInfo GetLayoutInfo (Container parent, int sizeflag)protected void AdjustForGravity (GridBagConstraints constraints, Rectangle r)protected Dimension GetMinSize (Container parent, GridBagLayoutInfo info)protected void ArrangeGrid (Container parent)

Pour illustrer l'utilisation de la classe GridBagLayout, voici l'applet GridBagBuilder permettant d'ajouter àune fenêtre indépendante le composant de votre choix et de positionner sur chacun des composants lescontraintes proposées par la classe GridBagConstraints. La fenêtre s'affiche à la première utilisation d'undes composants de l'applet.

Mode d'emploi

Une fois la classe de votre composant choisie avec le champ Type de composant, vous pouvez saisirdans le champ Label, text ou item le label (pour les classes Button, Checkbox et Label), le texte (pourles classes TextArea et TextField) ou le premier item (pour les classe Choice et List) des nouveauxcomposants.Vous pouvez aussi positionner une ou plusieurs contraintes (gridx à weighty) sur uncomposant avant de l'ajouter à la fenêtre Composants avec le bouton Ajouter.Le champ Variable permet de saisir un nom de variable pour chacun des composants que vous ajoutez ;ce nom est celui utilisé pour intituler chacune des variables du programme généré dans le champProgramme à copier : Vous pouvez sélectionner le code Java écrit dans ce champ, le copier puis lecoller dans la déclaration d'une classe dérivant de la classe Container (par exemple, une applet), pourcréer les mêmes composants que ceux de la fenêtre Composants .Le champ Composant courant permet de choisir un des composants créés pour le supprimer avec lebouton Supprimer ou le modifier avec le bouton Modifier après avoir positionner une ou plusieurscontraintes (gridx à weighty) sur ce composant.

Page 238: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 17

N'hésitez pas à utiliser cet exemple pour bien comprendre (et utiliser dans vos programmes) lefonctionnement des classes GridBagLayout et GridBagConstraints.

La classe java.awt.GridBagConstraints

Cette classe qui implémente l'interface Cloneable, est utilisée pour décrire les contraintes sur lepositionnement d'un composant inclus dans à un container géré par un layout GridBagLayout Lesdifférentes contraintes étant plutôt complexes à gérer, il vous est conseillé d'essayer l'appletGridBagBuilder pour essayer les différentes combinaisons possibles et comprendre leur effet. Cetteapplet génère le code correspondant aux différentes contraintes choisies dans le champ Programme àcopier.

Variables

public final static int RELATIVEpublic final static int REMAINDER public final static int NONEpublic final static int BOTHpublic final static int HORIZONTALpublic final static int VERTICAL public final static int CENTERpublic final static int NORTHpublic final static int NORTHEASTpublic final static int EASTpublic final static int SOUTHEASTpublic final static int SOUTHpublic final static int SOUTHWESTpublic final static int WESTpublic final static int NORTHWEST public int gridxpublic int gridy

Permet de donner la position en x et y de la cellule que doit occuper un composant, relativement au coinsupérieur gauche du container (dont la position est (0, 0)). Si gridx (ou respectivement gridy) est égal àRELATIVE, le composant sera placé à droite (ou respectivement en dessous) du composant précédemmentajouté au container par la méthode add () de la classe Container.

Page 239: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 18

public int gridwidthpublic int gridheight

Permet de donner le nombre de cellules en largeur et en hauteur qu'un composant occupe. Si gridwith(ou respectivement gridheight) est égal à REMAINDER, le composant sera le dernier sur une ligne (ourespectivement sur une colonne). Si gridwith (ou respectivement gridheight) est égal à RELATIVE, lecomposant sera placé à gauche (ou respectivement au dessus) du composant suivant.

public int fill

Permet de spécifier si un composant est redimensionné ou non pour occuper la(ou les) cellules qu'iloccupe. Si fill est égal à NONE, le composant prend la taille qu'il donne par la méthode preferredSize(). Si fill est égal BOTH, le composant est redimensionné pour occuper tout l'espace de la (ou des)cellules. Si fill est égal HORIZONTAL (ou respectivement VERTICAL) le composant prend la largeur (ourespectivement la hauteur) de la (ou les) cellules qu'il occupe.

public int ipadxpublic int ipady

Permet de donner la largeur et la hauteur supplémentaire que doit prendre le composant par rapport à lataille qu'il donne par la méthode preferredSize ().

public Insets insets

Permet de donner l'espacement vide autour du composant.

public int anchor

Quand le composant est plus petit que la (ou les) cellules qu'il occupe, anchor permet de donner à quelcoin ou à quel bord le composant est ancré (ou attaché). anchor peut être égal à CENTER ou aux 8 pointscardinaux : NORTH, NORTHEAST, EAST, SOUTHEAST, SOUTH, SOUTHWEST, WEST ou NORTHWEST.

public double weightxpublic double weighty

Permet de donner un poids au composant par rapport aux autres pour répartir les composantshorizontalement ou verticalement. Si tous les composants ont leurs contraintes weightx et weightyégales à 0, l'ensemble des composants d'un container géré par un layout GridBagLayout occupe leminimum d'espace au milieu du container.

Constructeur

public GridBagConstraints ()

Le constructeur affecte aux variables de contraintes les valeurs par défaut suivantes :

gridx, gridy : RELATIVE gridwidth, gridheight : 1 fill : NONE ipadx, ipady : 0 insets : new Insets (0, 0, 0, 0) anchor : CENTER weightx, weighty : 0

Méthode

public Object clone ()

A l'usage, vous vous rendrez compte que certaines contraintes ne se complètent pas toujours demanière très heureuse... Evitez notamment d'utiliser, le mélange du positionnement absolu de gridx etgridy, avec l'utilisation de REMAINDER pour gridwidth et gridheight.Si l'utilisation des classes GridBagLayout et GridBagConstraints vous semble trop compliqué, n'hésitezpas à utiliser plutôt une combinaison de layouts.

Page 240: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 19

La classe java.awt.CardLayout

Cette classe qui implémente l'interface LayoutManager, est un layout permettant d'ajouter à un containerune liste de sous-containers ou de composants qui sont affichés un par un, de manière similaire auxboites de dialogues à onglets (mais sans les onglets).

Constructeurs

public CardLayout ()public CardLayout (int horizontalgap, int verticalgap)

Ces constructeurs permettent de créer un layout CardLayout avec un espacement horizontal et verticalentre les composants de horizontalgap et verticalgap pixels (par défaut égal à 0).

Méthodes

public void addLayoutComponent (String name, Component comp)public void removeLayoutComponent (Component comp)public Dimension preferredLayoutSize (Container target)public Dimension minimumLayoutSize (Container target)public void layoutContainer (Container target)

Implémentation des méthodes de l'interface LayoutManager. La méthode addLayoutComponent () utilisele paramètre name pour associer une chaîne de caractères au composant ou au container comp.

public void first (Container parent)public void next (Container parent)public void previous (Container parent)public void last (Container parent)

Ces méthodes permettent d'afficher le premier, le suivant, le précédent ou le dernier de la liste descomposants ou des sous-containers du layout. parent doit être égal au container auquel est associé celayout.

public void show (Container parent, String name)

Affiche le composant ou le sous-container associé à la chaîne de caractères name. parent doit être égalau container auquel est associé ce layout. Si vous voulez utiliser cette méthode, il faut que le composantait été ajouté au container avec la méthode add (String name, Component component) de la classeContainer.

public String toString ()

Les menus

La création de menus se fait très simplement en Java, à l'aide de 4 classes différentes qui héritent toutesde la classe MenuComponent. Une barre de menu se compose d'une instance de la classe MenuBar auquelvous pouvez ajouter grâce à la méthode add () un ou plusieurs menus instances de la classe Menu.Finalement, vous pouvez ajouter à chaque menu grâce à la méthode add () de la classe Menu unensemble d'éléments instances des classes MenuItem (pour créer des éléments simples),CheckboxMenuItem (pour créer des éléments à cocher) ou Menu (pour créer un sous-menu).

figure 16. Les différents composants d'un menu

La classe Frame est la seule classe de fenêtre pour laquelle vous pouvez spécifier une barre de menu,grâce à la méthode setMenuBar (). Par conséquent, vous ne pouvez pas donner de menu aux applets,

Page 241: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 20

puisque leur classe n'hérite pas de la classe Frame.

L'applet suivante permet de tester tous les différents types de menu décrit ci-dessus (cliquez sur lebouton Nouveau Menu pour afficher la fenêtre utilisant un menu) :

Voici le programme Java correspondant (à copier dans un fichier dénommé ShowMenu.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class ShowMenu extends Applet{ // Création d'une instance de MenuFrame Frame fenetreMenu = new MenuFrame (); public void init () { // Ajout d'un bouton pour ouvrir une fenêtre add (new Button ("Nouveau Menu")); } public void stop () { // A la fin de l'applet, destruction de la fenêtre fenetreMenu.dispose (); } // Méthode appelée par la machine virtuelle quand on clique sur un bouton public boolean action (Event event, Object eventArg) { // Affichage de la fenêtre if ("Nouveau Menu".equals (eventArg)) fenetreMenu.show (); return true; }} // Classe MenuFrame utilisant un menuclass MenuFrame extends Frame{ public MenuFrame () { // Création d'une barre de menu et de 3 menus MenuBar menuBar = new MenuBar (); Menu menu1 = new Menu ("Menu 1"); Menu menu2 = new Menu ("Menu 2"); Menu menu3 = new Menu ("Sous menu"); // Ajout au premier menu de 2 éléments et d'un séparateur menu1.add ("Choix 1"); menu1.addSeparator (); menu1.add ("Choix 2"); // Ajout au second menu d'un élément à cocher // et d'un sous-menu menu2.add (new CheckboxMenuItem ("Choix")); menu2.add (menu3); // Ajout au sous-menu de 2 éléments menu3.add (new MenuItem ("Sous choix 1")); menu3.add (new MenuItem ("Sous choix 2")); // Ajout à la barre de menu des 2 premiers menus menuBar.add (menu1); menuBar.add (menu2); // Choix de la barre de menu pour cette fenêtre setMenuBar (menuBar); resize (200, 50); }

Page 242: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 21

}

L'interface java.awt.MenuContainer

Cette interface doit être implémentée par les classes de containers permettant l'utilisation des menus,comme c'est le cas pour la classe Frame.

Méthodes

public Font getFont ()public boolean postEvent (Event evt)public void remove (MenuComponent comp)

La classe java.awt.MenuComponent

La classe MenuComponent qui est abstract est la super classe de toutes les classes de composantsutilisables dans un menu (MenuBar, MenuItem, Menu et CheckboxMenuItem). Elle ressemble dans le principeà la classe Component en plus simple.

Constructeur

public MenuComponent ()

Méthodes

public MenuContainer getParent ()public MenuComponentPeer getPeer ()

Ces méthodes permettent d'obtenir le container auquel est rattaché un composant de menu et le peerd'un composant de menu.

public Font getFont ()public void setFont (Font font)

Ces méthodes permettent d'interroger ou de modifier la police de caractère utilisée pour l'affichage d'uncomposant de menu.

public void removeNotify ()

Cette méthode est appelée pour supprimer le peer d'un composant de menu.

protected String paramString ()public String toString ()

Ces méthodes sont utilisées pour fabriquer une chaîne de caractères décrivant le composant de menu(toString () outrepasse la méthode de la classe Object et appelle la méthode paramString () qui estoutrepassée par les classes dérivées de MenuComponent).

public boolean postEvent (Event evt)

La classe java.awt.MenuBar

Cette classe qui dérive de la classe MenuComponent, est la classe du package java.awt qui permet de créeret de manipuler une barre de menu. Une fois que vous avez créez une barre de menu vous pouvez yajouter un ou plusieurs menus. La méthode setMenuBar () de classe Frame permet de spécifier la barrede menu que doit utiliser une fenêtre.

Constructeur

public MenuBar ()

Méthodes

public synchronized void addNotify ()public void removeNotify ()

Page 243: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 22

Ces méthodes permettent de créer et de détruire le peer d'une barre de menu (removeNotify ()outrepasse la méthode de la classe MenuComponent).

public synchronized Menu add (Menu menu)

Permet d'ajouter un menu à une barre de menu.

public synchronized void remove (int index)public synchronized void remove (MenuComponent menu)

Ces méthodes permettent de supprimer un menu d'une barre de menu, soit en donnant son numérod'ordre index, soit en donnant directement l'instance de menu à supprimer.

public int countMenus ()

Renvoie le nombre de menus courant d'une barre de menu.

public Menu getMenu (int index)

Renvoie le menu dont le numéro d'ordre est index.

public Menu getHelpMenu ()public synchronized void setHelpMenu (Menu m)

Ces méthodes permettent d'interroger ou de modifier le menu d'aide.

Exemple

Applet ShowMenu .

La classe java.awt.MenuItem

Cette classe qui dérive de la classe MenuComponent, est la classe du package java.awt qui permet de créeret de manipuler un élément simple de menu. Un élément de menu a un label qui est le texte affiché dansle menu et peut être éventuellement grisé pour indiquer qu'il n'est pas utilisable à un moment donné.

Constructeur

public MenuItem (String label)

Ce constructeur permet de donner un label au nouveau menu créé.

Méthodes

public synchronized void addNotify ()

Permet de créer le peer d'un élément de menu.

public String getLabel ()public void setLabel (String label)

Ces méthodes permettent d'interroger ou de modifier le label d'un menu.

public boolean isEnabled ()

Renvoie true si un élément de menu est utilisable.

public void enable ()public void disable ()public void enable (boolean cond)

Vous pouvez rendre utilisable ou inutilisable un composant grâce à ces méthodes. Un élément de menuinutilisable (disabled ) est généralement grisé.

public String paramString ()

Page 244: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 23

Méthode de la classe MenuComponent, outrepassée pour renvoyer une chaîne de caractères décrivantl'élément de menu.

Exemple

Applet ShowMenu .

La classe java.awt.Menu

Cette classe qui dérive des classes MenuItem et MenuComponent est la classe du package java.awt quipermet de créer et de manipuler un menu ou un sous-menu. Un menu a un label et peut contenir un ouplusieurs éléments ; les éléments qui sont eux-mêmes des instances de la classe Menu deviennent dessous-menus.

Constructeurs

public Menu (String label)public Menu (String label, boolean tearOff)

Méthodes

public synchronized void addNotify ()public synchronized void removeNotify ()

Ces méthodes permettent de créer et de détruire le peer d'un menu (removeNotify () outrepasse laméthode de la classe MenuComponent).

public boolean isTearOff () public int countItems ()

Renvoie le nombre d'éléments d'un menu.

public MenuItem getItem (int index)

Renvoie l'élément du menu de numéro d'ordre index.

public synchronized MenuItem add (MenuItem menuItem)public void add (String label)

Ces méthodes permettent d'ajouter un élément à un menu.

public void addSeparator ()

Permet d'ajouter un séparateur à un menu. Equivalent à l'appel de la méthode add ("-").

public synchronized void remove (int index)public synchronized void remove (MenuComponent item)

Ces méthodes permettent de retirer d'un menu l'élément de numéro d'ordre index ou l'élément item.

Exemple

Applet ShowMenu .

La classe java.awt.CheckboxMenuItem

Cette classe qui dérive des classes MenuItem et MenuComponent est la classe du package java.awt quipermet de créer et de manipuler un élément de menu à cocher. Comme un composant de classeCheckbox, ce type d'élément de menu a un état coché ou non.

Constructeur

public CheckboxMenuItem (String label)

Page 245: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les containers et la disposition des composants Page: 24

Méthodes

public synchronized void addNotify ()

Permet de créer le peer d'un élément de menu à cocher.

public boolean getState ()public void setState (boolean t)

Ces méthodes permettent d'interroger ou de modifier l'état coché ou non de l'élément de menu.

public String paramString ()

Méthode de la classe MenuComponent, outrepassée pour renvoyer une chaîne de caractères décrivantl'élément de menu à cocher.

Exemple

Applet ShowMenu .

Page 246: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 1

La gestion de l'interface utilisateur

La gestion événementielleLa classe Graphics : tout pour dessiner

Les polices de caractèresLa couleur

Les classes manipulant des dimensionsLa création de nouveaux composants

La gestion événementielle

Maintenant que vous avez vu comment créer et disposer un ensemble de composants à l'écran, il reste àaborder comment gérer l'interactivité de ces composants avec votre programme pour que vous puissiezréagir aux actions d'un utilisateur, quand il utilise tel ou tel composant.

Les événements

La classe Component déclare tout un ensemble de méthodes qui permettent de réagir aux différentsévénements que peut recevoir un composant. Dans les différents exemples déjà cités, l'une de cesméthodes, action () a été souvent outrepassée pour traiter les actions d'un utilisateur sur un composant,mais en fait il existe tout un ensemble de méthodes traitant chacune des événements qui peuvent survenirlors de l'utilisation de l'ordinateur. On regroupe sous le terme générique événement tout type d'entréequ'un programme peut s'attendre à recevoir.Les événements peuvent se regrouper en plusieurs catégories :

Les événements provoqués par un périphérique de l'ordinateur : Entrée clavier(Enfoncement-relâchement d'une touche du clavier) et entrée souris (Enfoncement-relâchementd'un bouton de la souris et déplacement du pointeur de la souris). Les événements déclenchés par le gestionnaire de fenêtre du système, suite à un enchaînementd'actions de l'utilisateur sur une fenêtre (changement de taille d'une fenêtre, obtention du focusdans une fenêtre,...) ou un composant (clic sur un bouton, choix dans une liste,...).

Avant l'avènement des systèmes utilisant une interface graphique, les programmes attendaient quel'utilisateur appuie sur une touche de clavier pour effectuer telle ou telle action suivant la toucheenfoncée. Similairement, un programme utilisant les fonctionnalités d'une interface graphique utilise uneboucle pour attendre un événement quelconque qui permettra de déclencher telle ou telle action d'unprogramme.Quand un programme Java reçoit un événement, il exécute toujours le même scénario que vous devezbien comprendre pour que vous puissiez programmer correctement. La Machine Virtuelle Java utilisel'arbre des composants que vous avez créé (comme celui de l'applet TraitementTexte du chapitreprécédent) pour déterminer les différents composants auxquels peut se destiner un nouvel événement.Quand un événement est reçu par un composant comp d'un programme Java, la méthode handleEvent ()de la classe Component est appelée par la Machine Virtuelle Java. handleEvent () renvoie false pardéfaut ce qui provoque l'appel de la méthode handleEvent () du composant parent du composant comp,ainsi de suite jusqu'à ce que le composant n'est pas de parent. Si la classe d'un des composants surlequel handleEvent () est invoqué outrepasse cette méthode, c'est cette méthode qui sera appelée, cequi vous permet de modifier le comportement par défaut d'un composant qui dérive de Component.Quand vous outrepassez cette méthode, vous pouvez terminer votre méthode de trois manières suivantce que vous voulez faire :

return true; généralement utilisé après le traitement d'un événement pour indiquer que vous avezpris en compte l'événement et que vous ne voulez pas que le système continue à envoyerl'événement au parent du composant (par exemple, si vous avez traité un événementWINDOW_DESTROY envoyé quand l'utilisateur veut fermer une fenêtre indépendante). Dans ce cas, laméthode handleEvent () du parent du composant n'est pas appelée. return false; dans ce cas, la méthode handleEvent () du parent du composant est appelée.

Page 247: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 2

return super.handleEvent (event); dans ce cas, la méthode handleEvent () de la classe donthérite le composant est appelée.

L'enchaînement des appels aux méthodes handleEvent () sur chacun des parents d'un composant esttrès pratique car il évite de traiter les événements au niveau de chacun des composants où ilssurviennent. Vous pouvez ainsi traiter le clic d'un bouton dans la classe de son container, ce qui évite decréer une nouvelle classe pour ce bouton.Pour vous le montrer, voici une applet simple qui affiche l'heure courante dans un label quand vouscliquez sur le bouton Mise à l'heure :

Cette applet peut être réalisée de deux manières différentes comme suit (à copier dans un fichierdénommé MiseAJourHorloge.java et invoqué à partir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.util.Date; public class MiseAJourHorloge extends Applet{ private Label heure = new Label ( new Date ().toLocaleString ()); private Button miseAHeure = new BoutonMiseAJour ("Mise \u00e0 l'heure", heure); public void init () { // Ajout des deux composants add (miseAHeure); add (heure); }} class BoutonMiseAJour extends Button{ private Label heure; // Constructeur public BoutonMiseAJour (String label, Label heure) { super (label); this.heure = heure; } // Méthode appelée par la Machine // Virtuelle quand un événement survient public boolean handleEvent (Event event) { // Si l'événement est un clic sur le // bouton, mise à jour de l'horloge if (event.id == Event.ACTION_EVENT) { heure.setText ( new Date ().toLocaleString ()); return true; } return super.handleEvent (event); }}

import java.applet.Applet;import java.awt.*;import java.util.Date; public class MiseAJourHorloge extends Applet{ private Label heure = new Label ( new Date ().toLocaleString ()); private Button miseAHeure = new Button ("Mise \u00e0 l'heure"); public void init () { // Ajout des deux composants add (miseAHeure); add (heure); } // Méthode appelée par la Machine // Virtuelle quand un événement survient public boolean handleEvent (Event event) { // Si l'événement est un clic sur le // bouton, mise à jour de l'horloge if ( event.target == miseAHeure && event.id == Event.ACTION_EVENT) { heure.setText ( new Date ().toLocaleString ()); return true; } return super.handleEvent (event); }}

La première méthode respecte plus le style de programmation orientée objet : en effet, on modifie lecomportement par défaut d'un bouton en créant une nouvelle classe dérivée de Button. La secondeméthode est plus pratique : on modifie le comportement du container qui a créé tous les composants enlui indiquant comment gérer ses composants.

Page 248: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 3

Un container contenant généralement plusieurs composants qui interagissent entre eux (comme l'appletTraitementTexte ), on utilise plus souvent le second style de programmation en décrivant dans une seuleméthode le traitement des événements que reçoivent les différents composants gérés par le container.

Pour faciliter la clarté du traitement de certains types d'événements, la méthode handleEvent () de laclasse Component appelle certaines méthodes suivant le type d'événement reçu. Ces méthodes, comme laméthode action (), peuvent être outrepassées dans vos classes à la place (ou en plus) de la méthodehandleEvent (). Elles doivent toutes renvoyer une valeur booléenne indiquant comme pourhandleEvent () si l'événement doit être renvoyé au parent du composant (return false;) ou non(return true;). En voici la liste :

EVENEMENT METHODE DESCRIPTION

Event.MOUSE_ENTER public boolean mouseEnter(Event evt, int x, int y)

Méthode appelée quand le pointeur de la sourisentre dans un composant (utilisé par exemplepour changer l'aspect du pointeur).

Event.MOUSE_EXIT public boolean mouseExit(Event evt, int x, int y)

Méthode appelée quand le pointeur de la sourissort d'un composant.

Event.MOUSE_DOWN public boolean mouseDown(Event evt, int x, int y)

Méthode appelée le bouton de la souris estenfoncé.

Event.MOUSE_UP public boolean mouseUp(Event evt, int x, int y)

Méthode appelée le bouton de la souris estrelâché.

Event.MOUSE_MOVE public boolean mouseMove(Event evt, int x, int y)

Méthode appelée quand le pointeur de la sourisest déplacé.

Event.MOUSE_DRAG public boolean mouseDrag(Event evt, int x, int y)

Méthode appelée quand le pointeur de la sourisest déplacé, avec le bouton de la sourisenfoncé.

Event.KEY_PRESSEvent.KEY_ACTION

public boolean keyDown(Event evt, int key)

Méthode appelée quand une touche du clavierest enfoncée.

Event.KEY_RELEASEEvent.KEY_ACTION_RELEASE

public boolean keyUp(Event evt, int key)

Méthode appelée quand une touche du clavierest relâchée.

Event.GOT_FOCUS public boolean gotFocus(Event evt, Object arg)

Méthode appelée quand un composant obtientle focus. Un composant qui a le focus est celuiqui reçoit les entrées du clavier.

Event.LOST_FOCUS public boolean lostFocus(Event evt, Object arg)

Méthode appelée quand un composant perd lefocus.

Event.ACTION_EVENT public boolean action(Event evt, Object arg)

Méthode appelée quand l'utilisateur effectueune action dans un composant : Suivant laclasse du composant, ceci peut prendre un sensdifférent.

Nota : La liste de tous les événements reconnus en Java est donnée dans la classe Event décriteci-après.

Pour les événements MOUSE_..., x et y représentent les coordonnées du pointeur de la souris relativesau repère du composant où vous recevez l'événement.Pour les événements KEY_..., key représente le code UNICODE de la touche enfoncée ou l'une desvaleurs Event.HOME à Event.F12 pour les touches spéciales du clavier.Pour l'événement ACTION_EVENT, arg peut prendre une valeur différente suivant la classe du composantoù est survenu l'événement :

Page 249: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 4

Pour les composants de classe Button, l'événement ACTION_EVENT est envoyé quand l'utilisateurclique sur un bouton. arg est alors égal au label du bouton (de classe String). Pour les composants de classe Checkbox (que ce soit une boite à cocher ou un bouton radio)l'événement ACTION_EVENT est envoyé quand l'utilisateur clique sur le composant. arg est alors égalà l'état (coché ou non) de ce composant (arg de classe Boolean). Pour les composants de classe Choice, l'événement ACTION_EVENT est envoyé quand l'utilisateurchoisit un élément de la liste. arg est alors égal à la valeur de ce choix (de classe String). Pour les composants de classe List, l'événement ACTION_EVENT est envoyé quand l'utilisateur adouble-cliqué sur un élément de la liste. arg est alors égal à la valeur de cet élément (de classeString). Pour les composants de classe TextField, l'événement ACTION_EVENT est envoyé quand l'utilisateura appuyé sur return dans le champ de saisie. arg est alors égal à la chaîne saisie (de classe String). Pour les composants de classe MenuItem, l'événement ACTION_EVENT est envoyé quand l'utilisateurchoisit un élément de menu. arg est alors égal au label de cet élément de menu (de classe String). Pour les composants de classe CheckboxMenuItem, deux événements ACTION_EVENT sont envoyésquand l'utilisateur coche ou décoche un élément de menu. arg du premier événement est égal aulabel de cet élément de menu (de classe String) et arg du second événement est égal à l'état(coché ou non) de de cet élément (arg de classe Boolean)

Finalement, l'applet MiseAJourHorloge peut être programmée comme ceci :

import java.applet.Applet;import java.awt.*;import java.util.Date; public class MiseAJourHorloge extends Applet{ private Label heure = new Label (new Date ().toLocaleString ()); private Button miseAHeure = new Button ("Mise \u00e0 l'heure"); public void init () { // Ajout des deux composants add (miseAHeure); add (heure); } // Méthode appelée par la machine virtuelle à la suite d'une action public boolean action (Event event, Object arg) { // Si l'événement est un clic sur le bouton, mise à jour de l'horloge if ("Mise \u00e0 l'heure".equals (arg)) heure.setText (new Date ().toLocaleString ()); return true; }}

Si vous outrepassez handleEvent () ET une des méthodes précédentes dans la même classe, n'oubliezpas l'appel super.handleEvent (event); pour les événements que vous ne traitez pas danshandleEvent (). Sinon ces méthodes ne seront pas appelées.

Les applets DrawIt et PaperBoardClient sont des exemples d'utilisation des méthodes mouseDown (),mouseDrag () et mouseUp ().L'applet PaperBoardClient est un exemple d'utilisation des méthodes mouseDown (), mouseUp (),mouseEnter () et mouseExit ().L'applet EchoClient est un exemple d'utilisation de la méthode keyDown ().

La classe java.awt.Event

La classe Event est la classe qui regroupe tous les événements qui peuvent survenir dans un programme.Les méthodes de gestion événementielle (handleEvent () ou autre) que vous outrepassez dans vos

Page 250: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 5

classes reçoivent un événement de cette classe créé par la Machine Virtuelle Java.Vous pouvez aussi créer vous-même des événements que vous envoyez à un composant par la méthodepostEvent () de la classe Component. Le principal avantage d'envoyer un événement à un composant declasse Comp1 à partir d'une autre classe CompEmetteur plutôt que d'appeler une méthode que vous créezdans la classe Comp1, est que vous rendez indépendantes ces deux classes l'une de l'autre.

Contrairement à la plupart des classes de la librairie Java, les variables (non constantes) de la classeEvent sont public, et vous pouvez consulter directement les caractéristiques d'un événement par cesvariables.

Variables

public Object target

Désigne l'objet cible de l'événement (généralement le composant où est survenu l'événement).

public long when

Représente le moment où est survenu l'événement.

public int id

Caractérise le type d'événement qui est survenu (égal aux valeurs WINDOW_DESTROY à LOST_FOCUS décritesci-après).

public int xpublic int y

Pour les événements souris, x et y sont les coordonnées du pointeur de la souris. Ces coordonnées sontrelatives au repère du composant où vous consultez l'événement.

public int key

Pour les événements clavier, key représente le code UNICODE de la touche enfoncée ou l'une desvaleurs HOME à F12 décrites ci-après pour les touches spéciales du clavier.

public int modifiers

Représente la combinaison des valeurs SHIFT_MASK à ALT_MASK, représentant l'état enfoncé ou non destouches Shift, Control, Meta et Alt. Si par exemple les touches Shift et Control sont enfoncéesmodifiers sera égal à SHIFT_MASK | CTRL_MASK.

public int clickCount

Pour les événements MOUSE_DOWN, représente le nombre de clics consécutifs (égal à 2 pour un doubleclic,...).

public Object arg

arg peut prendre n'importe quelle valeur. Il est utilisé comme argument utilisateur pour fourniréventuellement des renseignements supplémentaires au composant récepteur de l'événement courant.Par exemple, l'événement ACTION_EVENT émis par la plupart des composants Java l'utilise pourcommuniquer le label du composant.

public Event evt

Désigne l'événement suivant quand les événements sont mis dans une liste chaînée.

public final static int SHIFT_MASKpublic final static int CTRL_MASKpublic final static int ALT_MASK

Ces constantes représentent la combinaison de l'état enfoncé ou non des touches Shift (Majuscule),Control et Alt.

Page 251: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 6

public final static int META_MASK

Cette constante représente la combinaison de l'état enfoncé ou non de la touche Pomme sous MacOS oudu bouton droit de la souris sur les autres systèmes.

public final static int HOMEpublic final static int ENDpublic final static int PGUPpublic final static int PGDNpublic final static int UPpublic final static int DOWNpublic final static int LEFTpublic final static int RIGHTpublic final static int F1public final static int F2public final static int F3public final static int F4public final static int F5public final static int F6public final static int F7public final static int F8public final static int F9public final static int F10public final static int F11public final static int F12

Ces constantes représentent les touches spéciales du clavier.

public final static int WINDOW_DESTROYpublic final static int WINDOW_EXPOSEpublic final static int WINDOW_ICONIFYpublic final static int WINDOW_DEICONIFYpublic final static int WINDOW_MOVEDpublic final static int KEY_PRESSpublic final static int KEY_RELEASEpublic final static int KEY_ACTIONpublic final static int KEY_ACTION_RELEASEpublic final static int MOUSE_DOWNpublic final static int MOUSE_UPpublic final static int MOUSE_MOVEpublic final static int MOUSE_ENTERpublic final static int MOUSE_EXITpublic final static int MOUSE_DRAGpublic final static int SCROLL_LINE_UPpublic final static int SCROLL_LINE_DOWNpublic final static int SCROLL_PAGE_UPpublic final static int SCROLL_PAGE_DOWNpublic final static int SCROLL_ABSOLUTEpublic final static int LIST_SELECTpublic final static int LIST_DESELECTpublic final static int ACTION_EVENTpublic final static int LOAD_FILEpublic final static int SAVE_FILEpublic final static int GOT_FOCUSpublic final static int LOST_FOCUS

Ces constantes représentent tous les événements qui peuvent survenir dans un programme Java. Pourcertains de ces événements, la méthode handleEvent () de la classe Component appelle des méthodesque vous pouvez outrepasser.

Constructeurs

public Event (Object target, long when, int id, int x, int y, int key, int modifiers, Object arg)public Event (Object target, long when, int id, int x, int y, int key, int modifiers)public Event (Object target, int id, Object arg)

Ces constructeurs permettent de créer un événement. Les paramètres correspondent aux variables de laclasse Event.

Page 252: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 7

Méthodes

public void translate (int x, int y)

Effectue une translation de (x,y) sur les coordonnées de l'événement.

public boolean shiftDown ()public boolean controlDown ()public boolean metaDown ()

Ces méthodes permettent de savoir si lors d'un événement les touches Shift, Control et Meta sontenfoncées (true) ou non.

protected String paramString ()public String toString ()

Ces méthodes sont utilisées pour fabriquer une chaîne de caractères décrivant le composant (toString() outrepasse la méthode de la classe Object et appelle la méthode paramString ()).

Pour essayer le traitement des événements, vous pouvez par exemple améliorer l'applet du piano duchapitre sur les applets, en ajoutant des raccourcis clavier aux différentes notes (ceci vous permettra detester le mixage des sons en jouant des accords).

A partir de la version de Java 1.1 un traitement des événements différents de Java 1.0 a été mis enplace. Ce sujet sera traité dans une version ultérieure de ce manuel.

Exemples

Applets Piano , PaperBoardClient , TraitementTexte , BorderBuilder , MiseAJourHorloge , ListePolices ,Nuancier et BoutonsNavigation . Voir aussi ci-dessus.

La classe Graphics : tout pour dessiner

La classe java.awt.Graphics

La classe Graphics qui est abstract représente un contexte graphique et regroupe toutes les méthodespermettant de dessiner (ligne, rectangle, arc de cercle, polygone, texte et image), quelque soit le supportfinal (écran, imprimante, image en mémoire). Il n'est pas possible de créer directement d'objet de cetteclasse grâce à l'opérateur new, mais vous pouvez récupérer une instance de cette classe en paramètre desméthodes paint () et update () ou par la méthode getGraphics () de la classe Component.

Constructeur

protected Graphics ()

Méthodes

public abstract Graphics create ()

Crée une copie d'un contexte graphique.

public Graphics create (int x, int y, int width, int height)

Crée une copie d'un contexte graphique, en effectuant en plus une translation (x,y) sur le repèrecourant et en créant une zone de clipping de largeur width et hauteur height. Seuls les dessins effectuésà l'intérieur de cette zone de clipping seront affichés.

public abstract void translate (int x, int y)

Cette méthode effectue une translation (x,y) sur le repère courant. Tous les ordres graphiques serontensuite calculés par rapport à ce nouveau repère.

public abstract Rectangle getClipRect ()

Page 253: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 8

public abstract void clipRect (int x, int y, int width, int height)

Ces méthodes permettent d'interroger ou de modifier la zone de clipping courante. Seuls les dessinseffectués à l'intérieur de cette zone de clipping seront affichés. S'il existe déjà un rectangle de clipping,le rectangle de clipping résultant de l'appel à la méthode clipRect () est l'intersection entre le rectanglecourant et celui passé en paramètre.

public abstract Color getColor ()public abstract void setColor (Color c)

Ces méthodes permettent d'interroger ou de modifier la couleur courante utilisée pour dessiner.

public abstract void setPaintMode ()public abstract void setXORMode (Color c1)

Ces méthodes permettent de choisir le mode d'utilisation de la couleur au cours d'un dessin.setPaintMode () positionne le mode le plus usuel où tout dessin est effectué avec la couleur courante.setXORMode () positionne le mode XOR : Dans ce mode, tout ordre graphique effectué deux fois auxmêmes coordonnées s'annule ; si la couleur d'un pixel (ou d'un point) à dessiner est égale à la couleurcourante, il prend la couleur c1, les pixels d'une autre couleur prennent une couleur non prévisible. Cemode est surtout utilisé pour dessiner des rectangles élastiques quand l'utilisateur doit désigner unensemble d'objets ou dessiner un rectangle élastique. A chaque déplacement du pointeur de la souris,avant de dessiner un rectangle aux nouvelles coordonnées, vous annulez le rectangle précédent en leredessinant à la même position.

public abstract Font getFont ()public abstract void setFont (Font font)

Ces méthodes permettent d'interroger ou de modifier la police de caractère courante utilisée pourdessiner les textes.

public FontMetrics getFontMetrics ()public abstract FontMetrics getFontMetrics (Font font)

Ces méthodes permettent d'interroger les tailles de la police de caractère courante ou de la police decaractère font.

public abstract void drawLine (int x1, int y1, int x2, int y2)

Permet de dessiner une ligne reliant les points de coordonnées (x1,y1) et (x2,y2).

public void drawRect (int x, int y, int width, int height)

Permet de dessiner le contour du rectangle au point de coordonnées (x,y), de largeur (vers la droite)width et de hauteur (vers le bas) height.Ce rectangle s'étend en fait du pixel de coordonnées (x,y) à celui de coordonnées (x + width,y +height), ce qui donne une largeur de width + 1 pixels et une hauteur de height + 1 pixels.

public abstract void fillRect (int x, int y, int width, int height)public abstract void clearRect (int x, int y, int width, int height)

Ces méthodes permettent de remplir le rectangle au point de coordonnées (x,y), de largeur width et dehauteur height. fillRect () utilise la couleur courante comme couleur de remplissage et clearRect ()utilise la couleur de fond.Contrairement à la méthode drawRect (), ce rectangle s'étend du pixel de coordonnées (x,y) à celui decoordonnées (x + width - 1,y + height - 1), ce qui donne une largeur de width pixels et une hauteurde height pixels.

public abstract void drawRoundRect (int x, int y, int width int height, int arcWidth, int arcHeight)public abstract void fillRoundRect (int x, int y, int width, int height, int arcWidth, int arcHeight)

Ces méthodes permettent de dessiner ou de remplir un rectangle dont les bords sont arrondis.

Page 254: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 9

public void draw3DRect (int x, int y, int width, int height, boolean raised)public void fill3DRect (int x, int y, int width, int height, boolean raised)

Ces méthodes permettent de dessiner ou de remplir un rectangle avec effet 3D. Si raised est égal àtrue, le rectangle sera en relief, sinon il sera en creux.

public abstract void drawOval (int x, int y, int width, int height)public abstract void fillOval (int x, int y, int width, int height)

Ces méthodes permettent de dessiner le contour d'un oval ou de remplir un ovale (ou une ellipse)contenu dans le rectangle de coordonnées (x,y), de largeur width et de hauteur height.Pour les deux méhodes, ce rectangle s'étend en fait du pixel de coordonnées (x,y) à celui decoordonnées (x + width,y + height), ce qui donne une largeur de width + 1 pixels et une hauteur deheight + 1 pixels.

public abstract void drawArc (int x, int y, int width, int height, int startAngle, int arcAngle)public abstract void fillArc (int x, int y, int width, int height, int startAngle, int arcAngle)

Ces méthodes permettent de dessiner le contour d'un arc ou de remplir un arc d'ellipse contenu dans lerectangle de coordonnées (x,y), de largeur width et de hauteur height. L'arc est dessiné à partir del'angle startAngle degrés (correspondant à l'angle de 3 heures), et s'étend sur arcAngle degrés dans lesens trigonométrique, si arcAngle est positif.Le rectangle englobant s'étend du pixel de coordonnées (x,y) à celui de coordonnées (x + width,y +height), ce qui donne une largeur de width + 1 pixels et une hauteur de height + 1 pixels.

public abstract void drawPolygon (int xPoints [ ], int yPoints [ ], int nPoints)public void drawPolygon (Polygon p)public abstract void fillPolygon (int xPoints [ ], int yPoints [ ], int nPoints)public void fillPolygon (Polygon p)

Ces méthodes permettent de dessiner ou de remplir un polygone. Les points du polygone peuvent êtredonnés soit dans les tableaux xPoints et yPoints représentant les coordonnées (x,y) de chaque point,soit par uns instance de la classe Polygon.

public abstract void drawString (String str, int x, int y)public void drawChars (char data [ ], int offset, int length, int x, int y)public void drawBytes (byte data [ ], int offset, int length, int x, int y)

Ces méthodes permettent de dessiner une chaîne de caractères avec la police de caractère courante aupoint de coordonnées (x,y) : l'ordonnée y de ce point est la ligne de base sur laquelle sera dessinée lachaîne. La chaîne de caractères peut être donnée soit par une instance de String, soit par les lengthpremiers caractères à partir de l'indice offset du tableau data.

public abstract void copyArea (int x, int y, int width, int height, int dx, int dy)

Permet de copier au point de coordonnées (x + dx,y + dy) la partie du composant contenue dans lerectangle au point de coordonnées (x,y), de largeur width et de hauteur height.

public abstract boolean drawImage (Image img, int x, int y, ImageObserver observer)public abstract boolean drawImage (Image img, int x, int y, int width, int height, ImageObserver observer)public abstract boolean drawImage (Image img, int x, int y, Color bgcolor, ImageObserver observer)public abstract boolean drawImage (Image img, int x, int y, int width, int height, Color bgcolor, ImageObserver observer)

Page 255: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 10

Ces méthodes permettent de dessiner l'image img, au point de coordonnées (x,y). La largeur et lahauteur width et height permettent éventuellement de d'agrandir ou de diminuer la taille de l'image. Sivous voulez ne dessiner qu'une partie d'une image, utiliser éventuellement la méthode clipRect (). Voiraussi le chapitre sur les images.

public abstract void dispose ()

Permet de détruire le contexte graphique. Une fois détruit le contexte graphique n'est plus utilisable et latranslation et la zone de clipping éventuellement actives sur ce contexte graphique sont annulées.

public void finalize ()

Détruit le contexte graphique (appel de dispose ()). Cette méthode outrepasse celle de la classe Object.

public String toString ()

Renvoie une chaîne de caractère représentant le contexte graphique. Cette méthode outrepasse celle dela classe Object.

Les méthodes de dessin (comme drawRect (), drawOval ()) prenant en paramètre une largeur et unehauteur (width et height), n'acceptent que des valeurs positives pour ces paramètres.

Voici l'applet DrawIt , vous permettant de dessiner interactivement des formes en désignant un rectangleenglobant avec la souris. Les boutons radios à droite vous permettent de choisir le type de dessin quevous voulez réaliser. Cette applet permet de tester le mode XOR, la plupart des méthodes de dessins dela classe Graphics et l'utilisation des méthodes mouseDown (), mouseDrag () et mouseUp () de la classeComponent :

et le programme Java correspondant (à copier dans un fichier dénommé DrawIt.java et invoqué à partird'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.util.Random; public class DrawIt extends Applet{ private CheckboxGroup choixDessin = new CheckboxGroup (); private Panel zoneDessin = new DrawItComponent (choixDessin); public void init () { // Choix d'un layout BorderLayout (FlowLayout par défaut) setLayout (new BorderLayout ()); // Création de boutons radios permettant de choisir // la fonction de dessin à utiliser Panel panel = new Panel (); panel.setLayout (new GridLayout (7, 1)); panel.add (new Checkbox ("Ligne", choixDessin, true)); panel.add (new Checkbox ("Rectangle", choixDessin, false)); panel.add (new Checkbox ("Rectangle 3D", choixDessin, false)); panel.add (new Checkbox ("Polygone", choixDessin, false)); panel.add (new Checkbox ("Ovale", choixDessin, false)); panel.add (new Checkbox ("Arc de cercle", choixDessin, false)); panel.add (new Checkbox ("Texte", choixDessin, false)); // Ajout à droite des boutons radios

Page 256: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 11

add ("East", panel); // Ajout au centre de la zone de saisie add ("Center", zoneDessin); }} // Classe DrawItComponentclass DrawItComponent extends Panel{ private int xDebut, yDebut, xFin, yFin; private CheckboxGroup choixDessin; private Color couleurDessin; private int angleDebut, angle; private String typeDessin = ""; // Constructeur DrawItComponent (CheckboxGroup choixDessin) { this.choixDessin = choixDessin; } // Méthodes mouseDown (), mouseDrag (), mouseUp () // appelées à l'enfoncement du bouton de la souris, // au déplacement du pointeur, et au relâchement du bouton public boolean mouseDown (Event evt, int x, int y) { xDebut = x; yDebut = y; dessinerElastique (x , y); return true; } public boolean mouseDrag (Event evt, int x, int y) { // Effacement du rectangle aux anciennes coordonnées // puis dessin d'un nouveau rectangle aux coordonnées courantes dessinerElastique (xFin, yFin); dessinerElastique (x, y); return true; } public boolean mouseUp (Event evt, int x, int y) { // Effacement du dernier rectangle dessiné dessinerElastique (xFin, yFin); // Récupération du type de dessin demandé, d'une couleur et deux angles // et redessin du composant typeDessin = choixDessin.getCurrent ().getLabel (); Random generateur = new Random (); couleurDessin = new Color (generateur.nextFloat (), generateur.nextFloat (), generateur.nextFloat ()); angleDebut = generateur.nextInt () % 360; angle = generateur.nextInt () % 360; repaint (); return true; } // Méthode dessinerElastique () : mémorise les coordonnées // courantes, puis trace un rectangle en mode XOR private void dessinerElastique (int xFin, int yFin) { this.xFin = xFin; this.yFin = yFin; Graphics gc = getGraphics (); gc.setXORMode (getBackground ()); gc.drawRect (Math.min (xDebut, xFin), Math.min (yDebut, yFin), Math.abs (xFin - xDebut), Math.abs (yFin - yDebut)); } // Méthode appelée à la mise à jour du composant public void paint (Graphics gc) { // Sélection de la couleur gc.setColor (couleurDessin); // Appel de la méthode de dessin suivant le type de dessin choisi int x = Math.min (xDebut, xFin);

Page 257: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 12

int y = Math.min (yDebut, yFin); int largeur = Math.abs (xFin - xDebut); int hauteur = Math.abs (yFin - yDebut); if (typeDessin.equals ("Ligne")) gc.drawLine (x, y, x + largeur, y + hauteur); else if (typeDessin.equals ("Rectangle")) gc.fillRect (x, y, largeur, hauteur); else if (typeDessin.equals ("Rectangle 3D")) gc.fill3DRect (x, y, largeur, hauteur, true); else if (typeDessin.equals ("Polygone")) { int xPoints [ ] = {x, x , x + largeur, x + largeur}; int yPoints [ ] = {y, y + hauteur, y, y + hauteur}; gc.fillPolygon (xPoints, yPoints, xPoints.length); } else if (typeDessin.equals ("Ovale")) gc.fillOval (x, y, largeur, hauteur); else if (typeDessin.equals ("Arc de cercle")) { gc.drawOval (x, y, largeur, hauteur); gc.fillArc (x, y, largeur, hauteur, angleDebut, angle); } else if (typeDessin.equals ("Texte")) { gc.setFont (new Font ("Helvetica", Font.PLAIN, hauteur)); FontMetrics tailles = gc.getFontMetrics (); gc.drawString ("Texte", x, y + tailles.getAscent () + tailles.getLeading ()); } }}

Autres exemples

Les applets Chrono , EchoClient , PaperBoardClient , ListePolices et ScrollText sont des exemplesd'utilisation de la méthode drawString ().Les applets AfficheurDeCalcul , ObservateurCalcul, PaperBoardClient , Piano , ListePolices et Horlogesont des exemples de tracés de lignes et de polygones.Les applets BoutonsNavigation , MultiImages , ImageSimple , ChargementImage , ImageTableau ,ImageNoirEtBlanc , NegatifImage , AnimationFleche et Horloge sont des exemples d'utilisation de laméthode drawImage ().

Le package java.awt définit aussi un ensemble de classes utiles pour la classe Graphics décritesci-après, qui permettent de manipuler les polices de caractères, les couleurs et les objets représentantdes dimensions (point, rectangle, polygone,...) :

Les polices de caractères

La classe java.awt.Font

Cette classe permet de manipuler les polices de caractères. Une police de caractères se caractérise parun nom, un style (normal, gras, italique) et une taille exprimée en points (voir aussi la classeFontMetrics).

Toutes les polices de caractères du système ne sont pas disponibles en Java. Vous pouvez en obtenir laliste (généralement, Courier, TimesRoman et Helvetica) grâce à la méthode getFontList () de laclasse Toolkit, utilisé dans l'applet ListePolices .

Variables

public final static int PLAINpublic final static int BOLDpublic final static int ITALIC

Ces constantes permettent de spécifier le style de la police de caractères à sa création (normal, gras ou

Page 258: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 13

italique). Il est possible de combiner les styles avec l'opérateur | (par exemple, Font.BOLD |Font.ITALIC).

protected String nameprotected int styleprotected int size

Ces variables protected permettent d'accéder aux caractéristiques d'une police de caractères, dans lesclasses dérivées de Font.

Constructeur

public Font (String name, int style, int size)

Construit une police de caractères de nom name, de style style et de taille size.

Méthodes

public String getName ()public int getStyle ()public int getSize ()

Ces méthodes permettent d'interroger le nom, le style et la taille d'une police de caractères`.

public boolean isPlain ()public boolean isBold ()public boolean isItalic ()

Ces méthodes renvoient true si une police de caractères a un style normal, gras ou italique.

public String getFamily ()

Renvoie le nom de la famille à laquelle appartient une police de caractères. La famille d'une policedépend du système sur lequel fonctionne la Machine Virtuelle Java, tandis que le nom d'une police estun nom logique qui est toujours le même quelque soit le système pour rendre un programme Javaportable.

public static Font getFont (String prop)public static Font getFont (String prop, Font font)

Ces méthodes renvoient la police de caractère mémorisée par la propriété prop du système (voir la classeSystem). Si cette propriété n'existe pas, la seconde méthode renvoie la valeur par défaut font.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unepolice de caractères à un objet ou renvoyer une chaîne de caractères décrivant une police.

Exemples

Applets DrawIt , ListePolices . et ScrollText .

La classe java.awt.FontMetrics

Cette classe décrit les différentes tailles (hauteurs par rapport à la ligne de base, largeurs diverses) d'unepolice de caractères (de classe Font).

Variable

protected Font font

Mémorise la police de caractères décrite.

Constructeur

Page 259: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 14

protected FontMetrics (Font font)

Ce constructeur est protected ce qui empêche de créer directement une instance de la classeFontMetrics. Les méthodes getFontMetrics () des classes Graphics et Toolkit vous permettentd'interroger les tailles d'une police de caractères.

Méthodes

public Font getFont ()

Renvoie la police de caractères décrite par une instance de la classe FontMetrics.

public int getHeight ()public int getLeading ()public int getAscent ()public int getDescent ()

Ces méthodes revoient la hauteur, l'interligne, la hauteur au-dessus de la ligne de base et le jambaged'une police de caractères. La hauteur, différente de la taille de la police donnée à sa création, est égale àla somme des trois autres dimensions.

public int getMaxAscent ()public int getMaxDescent ()

Ces méthodes revoient la hauteur maximum au-dessus de la ligne de base et le jambage maximum detous les caractères d'une police.

public int getMaxAdvance ()

Renvoie la largeur du plus large des caractères d'une police.

public int charWidth (int ch)public int charWidth (char ch)

Ces méthodes renvoient la largeur du caractère ch d'une police.

public int stringWidth (String str)public int charsWidth (char data [ ], int offset, int length)public int bytesWidth (byte data [ ], int offset, int length)

Ces méthodes renvoient la largeur d'une chaîne de caractères. La chaîne de caractères peut être donnéesoit par une instance de String, soit par les length premiers caractères à partir de l'indice offset dutableau data.

public int [ ] getWidths ()

Renvoie un tableau décrivant la taille des 256 premiers caractères d'une police.

public String toString ()

Cette méthode outrepasse la méthode toString () de la classe Object, pour renvoyer une chaîne decaractères décrivant les principales tailles d'une police de caractères.

L'applet suivante décrit la liste de l'ensemble des polices de caractères disponibles avec Java. Cliquez surun élément de la liste ou saisissez une taille de police de caractères dans le champ Size, pour afficher unexemple de texte et les caractéristiques de la police choisie :

Voici le programme Java correspondant (à copier dans un fichier dénommé ListePolices.java et invoqué à

Page 260: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 15

partir d'un fichier HTML) :

import java.awt.*;import java.applet.*; public class ListePolices extends Applet{ AfficheurTexte exemple = new AfficheurTexte (); List listePolices = new List (); TextField taillePolice = new TextField ("24"); Label labelHeight = new Label (); Label labelLeading = new Label (); Label labelAscent = new Label (); Label labelDescent = new Label (); Label labelMaxAdvance = new Label (); public void init () { // Choix d'un layout BorderLayout (FlowLayout par défaut) setLayout (new BorderLayout (5, 0)); // Création d'un panel contenant la liste des polices // et la zone de saisie de la taille Panel panelSaisie = new Panel (); panelSaisie.setLayout (new BorderLayout ()); // Récupération de la liste des polices disponibles String [ ] ensemblePolices = getToolkit ().getFontList (); for (int i = 0; i < ensemblePolices.length; i++) listePolices.addItem (ensemblePolices [i]); panelSaisie.add ("Center", listePolices); Panel panelTaille = new Panel (); panelTaille.add (new Label ("Size :")); panelTaille.add (taillePolice); panelSaisie.add ("South", panelTaille); // Ajout du panel de saisie add ("West", panelSaisie); // Ajout du composant affichant une chaîne d'exemple add ("Center", exemple); // Création d'un panel utilisant un layout de grille // et affichant un ensemble de labels qui permettent // de décrire les caractéristiques de la police sélectionnée Panel panelResultat = new Panel (); panelResultat.setLayout (new GridLayout (5, 2)); panelResultat.add (new Label ("Height :")); panelResultat.add (labelHeight); panelResultat.add (new Label ("Leading :")); panelResultat.add (labelLeading); panelResultat.add (new Label ("Ascent :")); panelResultat.add (labelAscent); panelResultat.add (new Label ("Descent :")); panelResultat.add (labelDescent); panelResultat.add (new Label ("MaxAdvance :")); panelResultat.add (labelMaxAdvance); // Ajout du panel de résultat add ("East", panelResultat); } // Gestion des événements sur la liste et la zone de saisie public boolean handleEvent (Event event) { // Si un événement de sélection de la liste ou un // événement de changement de texte survient, // mise à jour des labels décrivant la police et de l'exemple if ( event.id == Event.LIST_SELECT || ( event.id == Event.ACTION_EVENT && event.target == taillePolice)) { Font police = new Font (listePolices.getSelectedItem (), Font.PLAIN, Integer.parseInt (taillePolice.getText ())); FontMetrics metrics = getToolkit ().getFontMetrics (police);

Page 261: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 16

labelHeight.setText (String.valueOf (metrics.getHeight ())); labelLeading.setText (String.valueOf (metrics.getLeading ())); labelAscent.setText (String.valueOf (metrics.getAscent ())); labelDescent.setText (String.valueOf (metrics.getDescent ())); labelMaxAdvance.setText (String.valueOf (metrics.getMaxAdvance ())); exemple.modifierTexte (police, "Bonjour"); return true; } return super.handleEvent (event); }} // Classe AfficheurTexte affiche un texte avec une police de caractèresclass AfficheurTexte extends Panel{ Font police; String texte; // La méthode modifierTexte () permet de modifier // la police de caractères et le texte du composant public void modifierTexte (Font police, String texte) { this.police = police; this.texte = texte; repaint (); } public void paint (Graphics gc) { if (texte != null) { // Dessin d'un cadre autour du composant gc.drawRect (0, 0, size ().width - 1, size ().height - 1); // Dessin des rectangles représentant les tailles FontMetrics metrics = gc.getFontMetrics (police); int y = (size ().height - metrics.getHeight ()) / 2; int largeurTexte = metrics.stringWidth (texte); gc.setColor (Color.blue.darker ()); gc.drawRect (5, y, largeurTexte, metrics.getHeight ()); gc.drawRect (5, y + metrics.getLeading (), largeurTexte, metrics.getAscent ()); // Dessin du texte dans les rectangles gc.setColor (Color.black); gc.setFont (police); gc.drawString (texte, 5, y + metrics.getAscent () + metrics.getLeading ()); } }}

Autres exemples

Applets DrawIt et ScrollText .

La couleur

La classe java.awt.Color

Cette classe permet de manipuler une couleur. Elle déclare un ensemble de constantes décrivant lescouleurs les plus communément utilisées. Ses constructeurs permettent de créer des couleurs à partir deleurs composantes RGB (Red Green Blue : Rouge Vert Bleu), mais les méthodes brighter () et darker() sont aussi très pratiques pour créer des couleurs plus claire ou plus foncée à partir d'une couleurexistante.

Variables

public final static Color whitepublic final static Color lightGraypublic final static Color graypublic final static Color darkGraypublic final static Color black

Page 262: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 17

public final static Color redpublic final static Color pinkpublic final static Color orangepublic final static Color yellowpublic final static Color greenpublic final static Color magentapublic final static Color cyanpublic final static Color blue

Ces constantes permettent de récupérer directement des couleurs prédéfinies (blanc, gris clair, gris, grisfoncé, noir, rouge, rose, orange, jaune, vert, magenta, cyan et bleu).

Constructeurs

public Color (int r, int g, int b)

Construit une couleur à partir de ses composantes entières rouge r, vert g et bleu b comprises entre 0 et255.

public Color (int rgb)

Construit une couleur à partir de l'entier rgb combinaison des composantes rouge (bits 16 à 23), vert (bits8 à 15) et bleu (bits 0 à 7).

public Color (float r, float g, float b)

Construit une couleur à partir de ses composantes décimales rouge r, vert g et bleu b comprises entre0.0 et 1.0.

Méthodes

public int getRed ()public int getGreen ()public int getBlue ()

Ces méthodes renvoient les composantes rouge, vert ou bleu d'une couleur comprises entre 0 et 255.

public int getRGB ()

Renvoie un entier combinaison des composantes rouge (bits 16 à 23), vert (bits 8 à 15) et bleu (bits 0 à 7)d'une couleur.

public Color brighter ()public Color darker ()

Ces méthodes renvoient une couleur plus claire ou plus foncée d'une couleur.

public static Color getColor (String name)public static Color getColor (String name, Color v)public static Color getColor (String name, int v) public static int HSBtoRGB (float hue, float saturation, float brightness)

Renvoie un entier combinaison des composantes rouge, vert et bleu d'une couleur exprimée par sa teintehue, sa saturation saturation et sa luminosité brightness comprises entre 0.0 et 1.0.

public static float [ ] RGBtoHSB (int r, int g, int b, float hsbvals [ ])

Renvoie un tableau décrivant la teinte, la saturation et la luminosité (aux indices 0, 1 et 2) d'une couleur àpartir de ses composantes rouge, vert et bleu comprises entre 0 et 255. Les valeurs sont stockées danshsbvals s'il est différent de null, sinon un nouveau tableau est créé.

public static Color getHSBColor (float hue, float saturation, float brightness)

Crée une couleur à partir de sa teinte hue, sa saturation saturation et sa luminosité brightness

Page 263: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 18

comprises entre 0.0 et 1.0.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer uneune couleur à un objet ou renvoyer une chaîne de caractères décrivant la couleur.

L'applet suivante dessine un nuancier. Les couleurs utilisent le mode HSB (Teinte, Saturation,Luminosité) pour avoir plus simplement les couleurs de toute la palette à partir d'une teinte. Quand vouscliquez sur une couleur, le label en dessous du nuancier indique la couleur choisie. Cette applet vouspermet de tester la palette des couleurs disponibles sur une Machine Virtuelle :

Voici le programme Java correspondant (à copier dans un fichier dénommé Nuancier.java et invoqué àpartir d'un fichier HTML) :

import java.awt.*;import java.applet.*; public class Nuancier extends Applet{ // Label bidon utilisé pour afficher en couleur de fond la couleur choisie Label labelColorise = new Label (" "); Label labelCouleur = new Label ("Cliquez sur une couleur..."); public void init () { // Choix d'un layout BorderLayout (FlowLayout par défaut) setLayout (new BorderLayout ()); // Ajout d'un composant affichant le nuancier add ("Center", new ComposantNuancier ()); // Création et ajout d'un panel de deux labels d'information Panel panelInfo = new Panel (); panelInfo.setLayout (new BorderLayout (5, 0)); panelInfo.add ("West", labelColorise); panelInfo.add ("Center", labelCouleur); add ("South", panelInfo); } public boolean action (Event event, Object arg) { // Si une action est reçue du composant nuancier // modifier la couleur de fond du label sans texte // et afficher les composantes RGB de la couleur choisie if (event.target instanceof ComposantNuancier) { Color couleur = (Color)arg; labelColorise.setBackground (couleur); labelColorise.repaint (); labelCouleur.setText ("Couleur : Rouge " + couleur.getRed () + ", Vert " + couleur.getGreen () + ", Bleu " + couleur.getBlue ()); } return true; }} // Classe ComposantNuancierclass ComposantNuancier extends Panel{ private static final int TAILLE = 40; private Rectangle [ ] carreaux = new Rectangle [TAILLE * TAILLE];

Page 264: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 19

private Color [ ] couleurCarreaux = new Color [TAILLE * TAILLE]; // Constructeur : crée l'ensemble des couleurs des carreaux ComposantNuancier () { for (int i = 0; i < TAILLE; i++) { // Première boucle réalisant un fondu du noir vers la teinte (moitié supérieure) int j; for (j = 0; j < TAILLE / 2; j++) couleurCarreaux [i * TAILLE + j] = Color.getHSBColor ((float)i / TAILLE, // Teinte 1, // Saturation (float)j / TAILLE * 2); // Luminosité // Seconde boucle diminuant la saturation de la couleur (moitié inférieure) for ( ; j < TAILLE; j++) couleurCarreaux [i * TAILLE + j] = Color.getHSBColor ((float)i / TAILLE, // Teinte (float)(TAILLE - 1 - j) / TAILLE * 2, // Saturation 1); // Luminosité } } // Méthode appelée quand le composant change de taille public void reshape (int x, int y, int width, int height) { super.reshape (x, y, width, height); // Calcul de la largeur et de la hauteur des carreaux int largeur = size ().width / TAILLE; int hauteur = size ().height / TAILLE; // Création des rectangles représentant les carreaux de couleur for (int i = 0; i < TAILLE; i++) for (int j = 0; j < TAILLE; j++) carreaux [i * TAILLE + j] = new Rectangle (largeur * i, hauteur * j, largeur, hauteur); } public void paint (Graphics gc) { for (int i = 0; i < carreaux.length; i++) { // Sélection d'une couleur et dessin du carreau gc.setColor (couleurCarreaux [i]); gc.fillRect (carreaux [i].x, carreaux [i].y, carreaux [i].width, carreaux [i].height); } } public boolean mouseDown (Event evt, int x, int y) { // Recherche du carreau dans lequel l'utilisateur à cliquer // et envoi d'un événement d'action for (int i = 0; i < carreaux.length; i++) if (carreaux [i].inside (x, y)) postEvent (new Event (this, Event.ACTION_EVENT, couleurCarreaux [i])); return true; }}

Autres exemples

Applets ObservateurCalcul , DrawIt , ListePolices , MultiImages et ScrollText .

Les classes manipulant des dimensions

La classe java.awt.Dimension

Cette classe permet de manipuler les dimensions d'un objet (largeur et hauteur) grâce à ses deuxvariables public width et height.

Variables

public int width

Page 265: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 20

public int height

Constructeurs

public Dimension ()public Dimension (Dimension d)public Dimension (int width, int height)

Méthode

public String toString ()

Cette méthode outrepasse la méthode toString () de la classe Object, pour renvoyer une chaîne decaractères décrivant les dimensions.

Exemples

Applets BoutonsNavigation , MultiImages , ImageTableau , ImageNoirEtBlanc , ScrollText et Horloge .

La classe java.awt.Insets

Cette classe qui implémente l'interface Cloneable, permet de manipuler les bordures d'un container, quidélimitent une zone dans laquelle il n'est pas possible de dessiner.

Variables

public int toppublic int leftpublic int bottompublic int right

Ces variables public désignent les bordures en haut, à gauche, en bas et à droite.

Constructeur

public Insets (int top, int left, int bottom, int right)

Méthodes

public String toString ()public Object clone ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer une chaîne de caractères décrivantles valeurs des bordures ou un clone d'une instance de la classe Insets.

La classe java.awt.Point

Cette classe permet de manipuler des points de coordonnées (x,y).

Variables

public int xpublic int y

Constructeur

public Point (int x, int y)

Méthodes

public void move (int x, int y)

Déplace le point en (x,y).

public void translate (int x, int y)

Effectue une translation (x,y) sur un point.

Page 266: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 21

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unpoint à un objet ou renvoyer une chaîne de caractères décrivant le point.

La classe java.awt.Polygon

Cette classe permet de manipuler des polygones, ensemble de npoints points dont les coordonnées sontenregistrées dans les tableaux xpoints et ypoints.

Variables

public int npointspublic int xpoints [ ]public int ypoints [ ]

Constructeurs

public Polygon ()public Polygon (int xpoints [ ], int ypoints [ ], int npoints)

Méthodes

public void addPoint (int x, int y)

Ajoute le point de coordonnées (x,y) à la fin de l'ensemble des points.

public Rectangle getBoundingBox ()

Renvoie le rectangle englobant tous les points du polygone.

public boolean inside (int x, int y)

Renvoie true si le point de coordonnées (x,y) est à l'intérieur du polygone.

Exemple

AppletPaperBoardClient .

La classe java.awt.Rectangle

Cette classe permet de manipuler des rectangles, mémorisés sous forme d'un point origine decoordonnées (x,y) représentant le coin supérieur gauche, de sa largeur width et de sa hauteur height.

Variables

public int xpublic int ypublic int widthpublic int height

Constructeurs

public Rectangle ()public Rectangle (int x, int y, int width, int height)public Rectangle (int width, int height)public Rectangle (Point p, Dimension d)public Rectangle (Point p)public Rectangle (Dimension d)

Méthodes

public void reshape (int x, int y, int width, int height)

Permet de changer l'origine, la largeur et la hauteur d'un rectangle.

Page 267: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 22

public void move (int x, int y)

Déplace l'origine du rectangle en (x,y).

public void translate (int x, int y)

Effectue une translation (x,y) sur l'origine du rectangle.

public void resize (int width, int height)

Modifie la largeur et la hauteur d'un rectangle.

public boolean inside (int x, int y)

Renvoie true si le point de coordonnées (x,y) est à l'intérieur d'un rectangle.

public boolean intersects (Rectangle r)

Renvoie true si le rectangle r et le rectangle sur lequel la méthode est invoquée ont une intersection.

public Rectangle intersection (Rectangle r)public Rectangle union Rectangle r)

Ces méthodes renvoie un rectangle résultat de l'intersection ou de l'union entre deux rectangles.

public void add (int newx, int newy)public void add (Point pt)

Ces méthodes ajoutent un point à un rectangle qui est agrandit si nécessaire pour contenir le point passéen paramètre.

public void add (Rectangle r)

Ajoute le rectangle r au rectangle sur lequel la méthode est invoquée. Le résultat est l'union des deuxrectangles.

public void grow (int horiz, int vert)

Agrandit un rectangle de horiz points à gauche et à droite, et de vert points en haut et en bas.

public boolean isEmpty ()

Renvoie true si la largeur ou la hauteur d'un rectangle est négative ou nulle.

public int hashCode ()public boolean equals (Object obj)public String toString ()

Ces méthodes outrepassent celles de la classe Object, pour renvoyer un code de hash, comparer unrectangle à un objet ou renvoyer une chaîne de caractères décrivant le rectangle.

La création de nouveaux composants

Dans les trois exemples précédents, les classes DrawItComponent, AfficheurTexte et ComposantNuancierdérivent de la classe Panel. Bien que ces applets fonctionnent correctement, Panel est une classe decontainer donc prévue pour contenir d'autres composants.Pour créer de nouveaux composants, il est plutôt recommandé de dériver de nouvelles classes à partirde la classe Canvas.

La classe java.awt.Canvas

Cette classe qui dérive de la classe Component, est la classe du package java.awt dont vous devezdériver pour créer vos propres classes de composants.

Page 268: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 23

Constructeur

public Canvas ()

Méthodes

public synchronized void addNotify ()

Cette méthode outrepasse la méthode addNotify () de la classe Component pour créer le peer d'uneinstance de Canvas.

public void paint (Graphics gc)

Cette méthode outrepasse la méthode paint () de la classe Component, pour remplir le composant de lacouleur de fond.

L'applet suivante utilise une nouvelle classe de composant BoutonImage. Ce composant est un boutonutilisant deux images de même taille, pour représenter l'état relâché et l'état enfoncé du bouton :

Le programme Java correspondant a été divisé en deux fichiers. Comme la classe BoutonImage (à copierdans un fichier dénommé BoutonImage.java ) peut être appelée à être réutilisée, elle est rangée dans unpackage tools :

// Les classes de ce fichier appartiennent au package toolspackage tools; import java.awt.*;import java.net.*; public class BoutonImage extends Canvas{ private boolean boutonEnfonce = false; private boolean boutonSourisEnfonce = false; private Object argAction; private Image imageRelache; private Image imageEnfonce; // Constructeur public BoutonImage (Object argAction, URL urlImageRelache, URL urlImageEnfonce) { try { this.argAction = argAction; // Création des images enfoncé/relâché du bouton imageRelache = getToolkit ().getImage (urlImageRelache); imageEnfonce = getToolkit ().getImage (urlImageEnfonce); // Création d'un MediaTracker pour charger les images // afin que leur taille soit disponible pour le layout MediaTracker imageTracker = new MediaTracker (this); imageTracker.addImage (imageRelache, 0); imageTracker.addImage (imageEnfonce, 0); imageTracker.waitForAll (); // En cas d'erreur, déclenchement d'une exception if (imageTracker.isErrorAny ()) throw new IllegalArgumentException ("Images introuvables"); } catch (InterruptedException e) { } } // Il est conseillé d'outrepasser les méthodes preferredSize () // et minimumSize () pour que les layouts utilisant ces méthodes // puissent dimensionner ce composant correctement public Dimension preferredSize () {

Page 269: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 24

return new Dimension (imageRelache.getWidth (this), imageRelache.getHeight (this)); } public Dimension minimumSize () { return preferredSize (); } // La méthode paint () dessine l'image suivant l'état du bouton public void paint (Graphics gc) { if (boutonEnfonce) gc.drawImage (imageEnfonce, 0, 0, this); else gc.drawImage (imageRelache, 0, 0, this); } // Les méthodes mouseDown () et mouseUp () modifient l'image du // bouton à l'enfoncement/relâchement du bouton de la souris public boolean mouseDown (Event event, int x, int y) { modifierEnfoncementBouton (true); boutonSourisEnfonce = true; return true; } public boolean mouseUp (Event event, int x, int y) { boolean boutonEnfonce = this.boutonEnfonce; modifierEnfoncementBouton (false); boutonSourisEnfonce = false; // Si le bouton est resté enfoncé, envoi d'un événement d'action if (boutonEnfonce) postEvent (new Event (this, Event.ACTION_EVENT, argAction)); return true; } // Les méthodes mouseEnter () et mouseExit () modifient // l'image du bouton si le bouton de la souris est enfoncé public boolean mouseEnter (Event event, int x, int y) { if (boutonSourisEnfonce) modifierEnfoncementBouton (true); return true; } public boolean mouseExit (Event event, int x, int y) { if (boutonSourisEnfonce) modifierEnfoncementBouton (false); return true; } private void modifierEnfoncementBouton (boolean nouvelEtat) { // Si l'état enfoncé/relâché du bouton a changé // mettre à jour le dessin du bouton if (boutonEnfonce != nouvelEtat) { boutonEnfonce = nouvelEtat; paint (getGraphics ()); } }}

L'autre fichier décrit l'applet (à copier dans un fichier dénommé BoutonsNavigation.java et invoqué à partird'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.net.*;// Importation de la classe BoutonImage du package toolsimport tools.BoutonImage; public class BoutonsNavigation extends Applet{

Page 270: CJava

vendredi 11 février 2000 Du C/C++ à Java : La gestion de l'interface utilisateur Page: 25

public void init () { try { // Création et ajout des deux boutons à l'applet add (new BoutonImage (new URL (getDocumentBase (), "awtlayouts10.html"), new URL (getCodeBase (), "prevup.gif"), new URL (getCodeBase (), "prevdown.gif"))); add (new BoutonImage (new URL (getDocumentBase (), "image10.html"), new URL (getCodeBase (), "nextup.gif"), new URL (getCodeBase (), "nextdown.gif"))); } catch (MalformedURLException e) { } } // Les boutons de classe BoutonImage émettent des événements ACTION_EVENT public boolean action (Event evt, Object arg) { // Chargement d'un document HTML suivant le bouton enfoncé if (arg instanceof URL) getAppletContext ().showDocument ((URL)arg); return true; }}

En récupérant les valeurs de paramètres utilisant la balise PARAM, cette applet pourrait être généraliséepour qu'elle configure les images et les actions des boutons, sans avoir à modifier son code source àchaque utilisation différente dans un fichier HTML.

Page 271: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 1

Les images

La génération d'imagesLe chargement des images

La création d'imagesTransformer des images avec un filtre

Comment ça marche ?Gestion d'animations

La génération d'images

Les images, instances de la classe Image, peuvent provenir de deux sources différentes :

Chargées à partir d'un fichier grâce aux méthodes getImage () des classes Applet ou Toolkit. Ce fichierpouvant être éventuellement téléchargé à partir d'une URL sur un réseau, son chargement peut prendre uncertain temps. C'est pourquoi la création de ce type d'image se fait en deux temps : getImage () permet decréer une instance de la classe Image tandis que d'autres méthodes se chargent d'initialiser et de surveiller sonchargement, et d'attendre la fin de son chargement. Créées de toute pièce grâce aux méthodes createImage () des classes Component et Toolkit. Ces images sontsouvent utilisées comme buffer ou comme bitmap affichés à l'écran qu'une fois leur dessin terminé.

Les méthodes drawImage () de la classe Graphics permettent d'afficher une image à un point donné en laredimensionnant éventuellement, comme le montre l'applet suivante, qui crée une image d'un nuancier, etl'affiche à 4 tailles différentes :

Voici le programme Java correspondant (à copier dans un fichier dénommé MultiImages.java et invoqué à partird'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class MultiImages extends Applet{ private Image image; public void reshape (int x, int y, int width, int height) { // Effectuer le comportement par défaut du changement de taille super.reshape (x, y, width, height); // Création de l'image que quand le peer de l'applet existe if (getPeer () != null) { Dimension taille = size (); taille.width /= 3; taille.height /= 3; // Création d'une image de dimensions 3 fois plus petites que l'applet image = createImage (taille.width, taille.height); Graphics gc = image.getGraphics (); // Remplissage d'une image avec un nuancier de rouge et vert for (int i = 0; i < taille.height; i++) for (int j = 0; j < taille.width; j++) {

Page 272: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 2

gc.setColor (new Color ((float)i / taille.height, // Rouge (float)j / taille.width, // Vert 0)); // Bleu gc.fillRect (i, j, 1, 1); } } } public void paint (Graphics gc) { if (image != null) { // Dessin de l'image à sa taille et agrandie gc.drawImage (image, 0, 0, this); gc.drawImage (image, image.getWidth (this), 0, image.getWidth (this) * 2, image.getHeight (this), this); gc.drawImage (image, 0, image.getHeight (this), image.getWidth (this), image.getHeight (this) * 2, this); gc.drawImage (image, image.getWidth (this), image.getHeight (this), image.getWidth (this) * 2, image.getHeight (this) * 2, this); } }}

Soit un composant comp sur lequel vous invoquez la méthode createImage (int width, int height)de la classe Component (comp peut être une applet ou un autre composant). comp.createImage () necrée une image que si le peer du composant comp existe. Le peer n'étant pas créé dans le constructeurd'un composant (de classe dérivée de Applet, Canvas, ou autre), cette caractéristique vous amène à créerune image pas forcément dans la méthode à laquelle vous pensiez au départ... Vous devez appelercreateImage () qu'au moment où ce peer existe, par exemple dans la méthode init () de la classeApplet, dans la méthode paint () d'une classe dérivée de Canvas, ou en outrepassant la méthodeaddNotify () de la manière suivante :

//...Image image;public void addNotify (){ super.addNotify (); // Le peer du composant existe, on peut créer une image image = createImage (largeur, hauteur);}//...

Souvenez-vous donc que si un appel à comp.createImage () vous renvoie null, demandez vousd'abord si le peer du composant comp existe à ce moment.

La classe java.awt.Image

Cette classe abstract permet de manipuler les images en Java.

Variable

public final static Object UndefinedProperty

Constructeur

public Image ()

Méthodes

public abstract int getWidth (ImageObserver observer)public abstract int getHeight (ImageObserver observer)

Ces méthodes renvoient la largeur ou la hauteur d'une image. La classe Component implémentant l'interfaceImageObserver, observer peut être égal à un composant. Si l'image n'est pas encore chargée, la valeur -1 estrenvoyée.

Page 273: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 3

public abstract Graphics getGraphics ()

Renvoie une instance de la classe Graphics, grâce à laquelle vous pouvez dessiner dans l'image.

public abstract ImageProducer getSource ()

Renvoie une instance de la classe implémentant l'interface ImageProducer. Cet objet est notamment utilisé parles classes réalisant un filtrage.

public abstract Object getProperty (String name, ImageObserver observer)public abstract void flush ()

Exemples

Applets BoutonsNavigation , MultiImages , ImageSimple , ChargementImage , ImageTableau , ImageNoirEtBlanc ,NegatifImage , AnimationFleche , ScrollText et Horloge .

Le chargement des images

Comme il est expliqué au début de ce chapitre, la méthode getImage () permet créer une instance d'uneimage. Pour initialiser et surveiller le chargement d'une image et l'utiliser quand elle est partiellement ouentièrement chargée, il existe plusieurs moyens :

Soit à l'appel de l'une des méthodes drawImage () de la classe Graphics avec en paramètre uneimage img. Si img n'est encore pas chargée, la méthode drawImage () débute le chargement del'image de manière asynchrone et rend la main. Le dernier paramètre de drawImage () doit être uneinstance d'une classe implémentant l'interface ImageObserver comme par exemple la classeComponent. Cette interface ne déclare qu'une seule méthode imageUpdate () et l'implémentation decette méthode dans la classe Component redessine le composant pour mettre à jour le dessin del'image au fur et à mesure de son chargement.Donc, si vous donnez en dernier paramètre le composant dans lequel l'image est affichée, l'imagesera affichée automatiquement aussitôt qu'elle est disponible.L'applet suivante utilise la méthode drawImage () pour charger et afficher une image :

Voici le programme Java correspondant (à copier dans un fichier dénommé ImageSimple.java etinvoqué à partir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class ImageSimple extends Applet{ private Image image; public void init () { // Création d'une image image = getImage (getCodeBase (), "monval.jpg"); } public void paint (Graphics gc) { if (image != null) // Affichage de l'image (image chargée automatiquement) gc.drawImage (image, 0, 0, this); }}

Soit à l'appel des méthodes prepareImage (Image img, ImageObserver observer) ou

Page 274: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 4

prepareImage (Image img, int width, int height, ImageObserver observer) des classeComponent et Toolkit. Ces méthodes permettent de débuter le chargement de l'image img par unautre thread de manière asynchrone et rend la main. Les paramètres width et height permettent deredimensionner l'image dès son chargement. Le dernier paramètre observer doit être une instanced'une classe implémentant l'interface ImageObserver et permet de surveiller l'état du chargement del'image. La classe Component implémentant cette interface, vous pouvez utiliser un composantcomme paramètre.L'applet ChargementImage est un exemple d'utilisation de la méthode prepareImage () et del'interface ImageObserver. Soit en utilisant la classe MediaTracker, qui permet de surveiller et d'attendre la fin du chargementd'une image. Cette classe qui utilise la méthode prepareImage () et l'interface ImageObserver,simplifie la programmation du chargement d'une image.

De plus, les méthodes checkImage () des classes Component et Toolkit permettent de vérifier l'état duchargement d'une image. Ces méthodes prennent en dernier paramètre une instance d'une classeimplémentant l'interface ImageObserver, dont la méthode imageUpdate () est appelée pour luicommuniquer l'état de l'image.

La classe java.awt.MediaTracker

Cette classe permet de gérer le chargement d'une ou plusieurs images. Elle est utilisée par les appletsBoutonsNavigation , AnimationFleche et Horloge pour charger les images dont elles ont besoin. Lesméthodes addImage () permettent de donner un ensemble d'image à charger et les méthodes waitForID() et waitForAll () de lancer le chargement des images.

Variables

public final static int ABORTED public final static int COMPLETE public final static int ERRORED public final static int LOADING

Les méthodes statusID () et statusAll () renvoie une combinaison de ces constantes pour indiquerl'état du chargement des images (annulé, terminé, erreur ou en cours de chargement).

Constructeur

public MediaTracker (Component comp)

Construit une instance de MediaTracker. comp désigne un composant dans lequel sera visualisé lesimages à charger.

Méthodes

public void addImage (Image image, int id)public synchronized void addImage (Image image, int id, int width, int height)

Ces méthodes permettent d'ajouter une image à charger. width et height permettent d'éventuellementredimensionner l'image dès son chargement. id est un identifiant numérique permettant de rassembler lesimages, pour les charger par groupe avec les méthodes ...ID () de cette classe.

public void waitForID (int id)public synchronized boolean waitForID (int id, long ms)public void waitForAll ()public synchronized boolean waitForAll (long ms)

Ces méthodes permettent de lancer le chargement des images d'identifiant id ou de toutes les images etmet en attente le thread courant jusqu'à la fin de leur chargement ou pendant le laps de temps msmillisecondes.

public int statusID (int id, boolean load)public int statusAll (boolean load)

Page 275: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 5

Ces méthodes renvoient l'état du chargement des images d'identifiant id ou de toutes les images. Lavaleur renvoyée est une combinaison des constantes ABORTED, COMPLETE, ERRORED et LOADING. Si load estégal à true, le chargement des images est démarré.

public boolean checkID (int id)public synchronized boolean checkID (int id, boolean load)public synchronized boolean checkAll ()public boolean checkAll (boolean load)

Ces méthodes renvoient true si les images d'identifiant id ou toutes les images sont chargéescorrectement (état égal à COMPLETE). Si load est égal à true (égal à false par défaut), le chargement desimages est démarré.

public synchronized boolean isErrorID (int id)public synchronized boolean isErrorAny ()

Ces méthodes renvoient true si une erreur est survenue pendant le chargement d'une des imagesd'identifiant id ou de n'importe quelle image (état égal à ERRORED).

public synchronized Object [ ] getErrorsID (int id)public synchronized Object [ ] getErrorsAny ()

Ces méthodes renvoient un tableau contenant toutes les images éventuellement d'identifiant id, dont lechargement a produit une erreur.

Exemples

Applets BoutonsNavigation , AnimationFleche et Horloge .

L'interface java.awt.image.ImageObserver

Cette interface est utilisée pour surveiller le chargement d'une image. Une classe implémentant cetteinterface est requise par la méthode drawImage () de la classe Graphics, les méthodes prepareImage ()et checkImage () des classes Component et Toolkit et les méthodes getWidth () et getHeight () de laclasse Image. Cette interface est notamment implémentée par la classe Component pour mettre à jour uncomposant contenant une image au fur et à mesure que celle-ci est chargée.

Variables

Le paramètre infoflags de la méthode imageUpdate () utilise une combinaison des constantes suivantespour indiquer quelles caractéristiques d'une image sont connues au moment du chargement d'une image :

public final static int WIDTHpublic final static int HEIGHT

La largeur ou la hauteur de l'image sont disponibles.

public final static int PROPERTIES

Les propriétés de l'image sont disponibles.

public final static int SOMEBITSpublic final static int FRAMEBITS

Une partie de l'image est chargée.

public final static int ALLBITS

Le chargement de l'image est terminé et toutes ses caractéristiques sont disponibles.

public final static int ERROR

Une erreur est survenue pendant le chargement de l'image. Combiné avec ABORT.

public final static int ABORT

Page 276: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 6

Le chargement de l'image a été annulé.

Méthodes

public boolean imageUpdate (Image image, int infoflags, int x, int y, int width, int height)

Cette méthode est appelée au cours du chargement d'une image pour indiquer quelles en sont lescaractéristiques connues. infoflags est une combinaison des constantes WIDTH, HEIGHT, PROPERTIES,SOMEBITS, FRAMEBITS, ALLBITS, ERROR et ABORT. x, y, width et height sont significatives suivant la valeurde infoflags.imageUpdate () doit renvoyer true si elle a besoin d'être encore appelée pour lui communiquer lesphases suivantes du chargement d'une image. Généralement, false est renvoyé en cas d'erreur.

L'applet suivante utilise l'interface ImageObserver pour attendre la fin du chargement d'une image etl'afficher :

Voici le programme Java correspondant (à copier dans un fichier dénommé ChargementImage.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*; public class ChargementImage extends Applet implements ImageObserver{ private Image image; private boolean chargementTermine = false; public void init () { // Création d'une image et lancement de son chargement image = getImage (getCodeBase (), "brookbr.jpg"); prepareImage (image, this); } public void paint (Graphics gc) { // Si le chargement de l'image est terminé, affichage de l'image // sinon affichage d'une chaîne de caractères d'attente if (chargementTermine) gc.drawImage (image, 0, 0, this); else gc.drawString ("Chargement en cours...", 10, size ().height - 10); } // Méthode appelée pour communiquer les étapes du chargement de l'image public boolean imageUpdate (Image image, int infoFlags, int x, int y, int width, int height) { // Si le chargement est terminé, redessin de l'applet if ((infoFlags & ALLBITS) != 0) { chargementTermine = true; repaint (); } return (infoFlags & (ALLBITS | ABORT)) == 0; }}

Page 277: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 7

A la différence de l'applet ImageSimple , l'image de cette applet n'est affichée qu'une fois que l'image estentièrement chargée.

La création d'images

Comme le montre l'applet MultiImages , une image peut être créée grâce à la méthode createImage (intwidth, int height) de la classe Component. Cette méthode crée une image vierge dans laquelle vouspouvez dessiner grâce aux méthodes de dessin de la classe Graphics.Il existe une deuxième version de la méthode createImage () disponible dans les classes Component etToolkit : createImage (ImageProducer producer). Le paramètre producer doit être d'une classe quiimplémente l'interface ImageProducer. Le package java.awt.image fournit deux classes qui implémententcette interface :

La classe MemoryImageSource permet de créer une image initialisée avec un tableau décrivant lacouleur de chacun des points d'une image. La classe FilteredImageSource permet de créer une image qui est le résultat de l'application d'unfiltre sur une image existante.

La classe java.awt.image.MemoryImageSource

Cette classe qui implémente l'interface ImageProducer permet de créer une image à partir d'un tableaudécrivant la couleur de chacun des points (ou pixels) d'une image.

Constructeurs

public MemoryImageSource (int width, int height, int pix [ ], int offset, int scan)public MemoryImageSource (int width, int height, int pix [ ], int offset, int scan, Hashtable props)public MemoryImageSource (int width, int height, ColorModel cm, int pix [ ], int offset, int scan)public MemoryImageSource (int width, int height, ColorModel cm, int pix [ ], int offset, int scan, Hashtable props)public MemoryImageSource (int width, int height, ColorModel cm, byte pix [ ], int offset, int scan)public MemoryImageSource (int width, int height, ColorModel cm, byte pix [ ], int offset, int scan, Hashtable props)

Ces constructeurs permettent de créer une image de largeur width et de hauteur height à partir dutableau pix [ ] de type byte ou int. pix [ ] décrit la couleur de chacun des points de l'image ligne parligne. offset permet de donner le premier point du tableau à utiliser et scan le nombre de pixels parligne dans le tableau pix [ ] au cas où cette valeur serait différente de width. cm permet de spécifier unmodèle de couleur (par défaut égal au modèle RGB par défaut), et props décrit éventuellement lespropriétés associées à l'image.

Méthodes

public synchronized void addConsumer (ImageConsumer ic)public synchronized boolean isConsumer (ImageConsumer ic)public synchronized void removeConsumer (ImageConsumer ic)public void startProduction (ImageConsumer ic)public void requestTopDownLeftRightResend (ImageConsumer ic)

Implémentation des méthodes de l'interface ImageProducer.

L'applet suivante, comme l'applet MultiImages , crée un nuancier en rouge et vert mais cette fois-ci enutilisant la classe MemoryImageSource :

Page 278: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 8

Voici le programme Java correspondant (à copier dans un fichier dénommé ImageTableau.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*; public class ImageTableau extends Applet{ private Image image; public void init () { Dimension taille = size (); int [ ] tableauPixels = new int [taille.width * taille.height]; // Remplissage du tableau avec un nuancier de rouge et vert // les pixels sont décrits ligne par ligne par leur code RGB for (int i = 0; i < taille.height; i++) for (int j = 0; j < taille.width; j++) tableauPixels [i * taille.width + j] = 255 << 24 // Transparence | ((j * 255 / taille.width) << 16) // Rouge | ((i * 255 / taille.height) << 8) // Vert | 0; // Bleu // Création d'une image à partir du tableau image = createImage (new MemoryImageSource (taille.width, taille.height, tableauPixels, 0, taille.width)); } public void paint (Graphics gc) { if (image != null) gc.drawImage (image, 0, 0, this); }}

Remplir le tableau oblige ici à positionner les bits des composantes Rouge, Vert, Bleu d'une couleur. Quelleest la principale différence entre cette applet et l'applet MultiImages ? A partir de mesures de temps réaliséessur ces deux applets, la création d'une image de même dimension prend au moins 100 fois plus de temps parl'applet MultiImages que sur l'applet ImageTableau ! Donc, si la création d'une image n'a pas besoin desméthodes de dessin de la classe Graphics, n'hésitez pas à utiliser la classe MemoryImageSource.

Le modèle de couleur RGB par défaut implique que chaque couleur d'un point est codée sur un entier32 bits dont les bits 16 à 23 représentent le Rouge, les bits 8 à 15 le Vert et les bits 0 à 7 le Bleu, ETdont les bits 24 à 31 représentent le canal alpha. Cette dernière valeur correspond à la transparence (0pour transparent à 255 pour opaque) : si vous oubliez de mettre une valeur pour ces bits dans le codecouleur, l'image sera du coup transparente et donc invisible !

Autre exemple

Applets ImageNoirEtBlanc .

La classe java.awt.image.ColorModel

Cette classe abstract est la super classe des modèles de couleurs. Un modèle de couleur décrit commentretrouver la couleur d'un point (ou pixel) d'une image à partir de sa valeur entière. Le modèle de couleur RGBpar défaut est obtenu par la méthode static getRGBDefault (). Les classes DirectColorModel etIndexColorModel qui dérivent de cette classe permettent d'utiliser des modèles de couleur différents, pour parexemple décrire une image créée avec la classe MemoryImageSource.

Variable

Page 279: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 9

protected int pixel_bits

Nombre de bits par pixel.

Constructeur

public ColorModel (int bits)

Méthodes

public static ColorModel getRGBdefault ()

Renvoie le modèle de couleur RGB par défaut utilisant 32 bits avec les bits 24 à 31 pour le canal alpha, lesbits 16 à 23 pour le Rouge, les bits 8 à 15 pour le Vert et les bits 0 à 7 pour le Bleu.

public int getPixelSize ()

Renvoie le nombre de bits utilisé par un modèle de couleur pour coder la couleur d'un pixel.

public abstract int getRed (int pixel)public abstract int getGreen (int pixel)public abstract int getBlue (int pixel)public abstract int getAlpha (int pixel)

Ces méthodes doivent renvoyer les composantes Rouge, Vert, Bleu et Alpha (comprises entre 0 et 255) pourune valeur pixel.

public int getRGB (int pixel)

La classe java.awt.image.DirectColorModel

Cette classe qui dérive de la classe ColorModel permet de définir un modèle de couleur différent du modèleRGB par défaut, qui n'utilise pas forcément 32 bits pour coder la couleur d'un pixel. Ce modèle permet parexemple de décrire comment coder une couleur sur 16 bits, utilisant les bits 11 à 15 pour le Rouge, les bits 6 à10 pour le Vert et les bits 0 à 5 pour le Bleu (correspondant à la création d'une instance de la classeDirectColorModel par l'instruction new DirectColorModel (16, 0xF800, 0x07C0, 0x003F)).

Constructeur

public DirectColorModel (int bits, int rmask, int gmask, int bmask)public DirectColorModel (int bits, int rmask, int gmask, int bmask, int amask)

Ces constructeurs permettent de créer un modèle de couleur sur nbits bits. rmask, gmask bmask et amaskdécrivent les masques de bits utilisés pour coder les composantes Rouge, Vert, Bleu et Alpha. Les masquesdoivent occupés les bits de poids le plus faible. Par défaut, les couleurs sont opaques.

Méthodes

public final int getRed (int pixel)public final int getGreen (int pixel)public final int getBlue (int pixel)public final int getAlpha (int pixel)

Ces méthodes renvoient les composantes Rouge, Vert, Bleu ou Alpha (comprises entre 0 et 255) pour unevaleur de couleur pixel, utilisée avec ce modèle de couleur.

public final int getRGB (int pixel)

Renvoie la couleur RGB utilisant le modèle de couleur RGB par défaut pour une valeur pixel.

public final int getRedMask ()public final int getGreenMask ()public final int getBlueMask ()public final int getAlphaMask ()

Page 280: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 10

Renvoie masques de bits utilisés pour coder les composantes Rouge, Vert, Bleu ou Alpha de ce modèle decouleur.

La classe java.awt.image.IndexColorModel

Cette classe qui dérive de la classe ColorModel permet de définir une palette de plusieurs couleurs. Chaquecouleur de cette palette est définie par ses composantes RGB (comprises entre 0 et 255) et Alpha(transparence de 0 transparent à 255 opaque). Une image utilisant une palette de couleurs définit la couleur dechacun de ses points par un entier égal à l'indice d'une couleur de cette palette (comme par exemple lesimages au format GIF).

Constructeur

public IndexColorModel (int bits, int size, byte r [ ], byte g [ ], byte b [ ])public IndexColorModel (int bits, int size, byte r [ ], byte g [ ], byte b [ ], byte a [ ])public IndexColorModel (int bits, int size, byte r [ ], byte g [ ], byte b [ ], int trans)

Ces constructeurs permettent de créer une palette de size couleurs. Les tableaux r [ ], g [ ], b [ ] et a [ ]décrivent les composantes Rouge, Vert, Bleu et Alpha de chacune des couleurs de la palette. Par défaut,chaque couleur est opaque. trans permet de spécifier l'indice de la couleur qui sera considérée commetransparente (comme pour les images au format GIF). bits donne le nombre de bits utilisé par chaque pixel(habituellement égal à log2 size arrondi à l'entier supérieur).

public IndexColorModel (int bits, int size, byte cmap [ ], int start, boolean hasalpha)public IndexColorModel (int bits, int size, byte cmap [ ], int start, boolean hasalpha, int trans)

Ces constructeurs permettent de créer une palette de size couleurs. Le tableau cmap [ ] décrit dans l'ordreles composantes Rouge, Vert, Bleu et Alpha (si hasalpha est égal à true) de chacune des couleurs de lapalette. start permet de spécifier l'indice du premier élément du tableau à utiliser. trans et bits sont utiliséesde la même manière que pour les constructeurs précédents.

Méthodes

public final int getMapSize ()

Renvoie la taille de la palette.

public final int getTransparentPixel ()

Renvoie l'indice de la couleur transparente ou -1 s'il n'est pas défini.

public final int getRed (int pixel)public final int getGreen (int pixel)public final int getBlue (int pixel)public final int getAlpha (int pixel)

Ces méthodes renvoient les composantes Rouge, Vert, Bleu ou Alpha (comprises entre 0 et 255) à l'indicepixel de la palette.

public final int getRGB (int pixel)

Renvoie la couleur RGB utilisant le modèle de couleur RGB par défaut à l'indice pixel de la palette.

public final void getReds (byte r [ ])public final void getGreens (byte g [ ])public final void getBlues (byte b [ ])public final void getAlphas (byte a [ ])

Page 281: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 11

Ces méthodes remplissent le tableau qui leur est passé en paramètre avec les composantes Rouge, Vert, Bleuou Alpha de chacune des couleurs de la palette.

L'applet suivante crée une image aléatoire en utilisant la classe MemoryImageSource, et une palette de couleursnoir et blanc :

Voici le programme Java correspondant (à copier dans un fichier dénommé ImageNoirEtBlanc.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*;import java.util.Random; public class ImageNoirEtBlanc extends Applet{ private Image image; public void init () { byte [ ] noirEtBlanc = {0x00, 0x00, 0x00, // Noir (byte)0xFF, (byte)0xFF, (byte)0xFF}; // Blanc ColorModel paletteNoirEtBlanc = new IndexColorModel (1, 2, noirEtBlanc, 0, false); Dimension taille = size (); byte [ ] tableauPixels = new byte [taille.width * taille.height]; Random generateur = new Random (); // Remplissage aléatoire avec les valeurs 0 ou 1 for (int i = 0; i < tableauPixels.length; i++) tableauPixels [i] = (byte)Math.abs (generateur.nextInt () % 2); // Création d'une image à partir du tableau image = createImage (new MemoryImageSource (taille.width, taille.height, paletteNoirEtBlanc, tableauPixels, 0, taille.width)); } public void paint (Graphics gc) { if (image != null) gc.drawImage (image, 0, 0, this); }}

Une image créée avec la classe MemoryImageSource et une palette de couleurs de classeIndexColorModel doit utiliser un tableau de type byte pour mémoriser la couleur des points de l'image(ceci limite la palette à 256 couleurs).

La classe java.awt.image.PixelGrabber

Cette classe qui implémente l'interface ImageConsumer permet de récupérer les points d'une partie d'une imagedans un tableau. Le tableau est rempli avec la couleur de chacun de ces points en utilisant le modèle decouleur RGB par défaut.

Constructeurs

public PixelGrabber (Image img, int x, int y, int width, int height, int pix [ ], int offset, int scansize)public PixelGrabber (ImageProducer ip, int x, int y, int width, int height,

Page 282: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 12

int pix [ ], int offset, int scansize)

Ces constructeurs créent une instance de la classe PixelGrabber pour récupérer dans le tableau pix [ ] uneportion rectangulaire d'une image aux coordonnées (x,y), de largeur width et de hauteur height. Le tableauest rempli à partir de l'indice offset, avec un nombre de scansize pixels par ligne.

Méthodes

public boolean grabPixels () throws InterruptedExceptionpublic synchronized boolean grabPixels (long ms) throws InterruptedException

Ces méthodes démarre la récupération des points de l'image (éventuellement pendant ms millisecondesmaximum).

public synchronized int status ()

Renvoie le statut des points à récupérer. La valeur renvoyée est une combinaison des constantes déclaréesdans l'interface ImageObserver.

public void setDimensions (int width, int height)public void setProperties (Hashtable props)public void setColorModel (ColorModel model)public void setHints (int hints)public void setPixels (int x, int y, int w, int h, ColorModel model, byte pixels [ ], int off, int scansize)public void setPixels (int x, int y, int w, int h, ColorModel model, int pixels [ ], int off, int scansize)public void imageComplete (int status)

Implémentation des méthodes de l'interface ImageConsumer.

Transformer des images avec un filtre

Java comporte le concept de filtres qui permettent de transformer une image en une autre. Ces filtresdérivent de la classe ImageFilter, et permettent toute sorte de transformation. Le packagejava.awt.image fournit deux classes de filtre dérivées de la classe ImageFilter, les classesCropImageFilter qui permet d'extraire une partie d'une image, et RGBImageFilter qui permet detransformer la couleur de chacun des points d'une image ; vous pouvez aussi imaginer toute sorte defiltre.Une image filtrée est créée grâce à la méthode createImage (ImageProducer producer) des classesComponent ou Toolkit, avec le paramètre producer égal à une une instance de la classeFilteredImageSource.Pour plus d'information sur le fonctionnement du filtrage d'images, voir Comment ça marche ?

La classe java.awt.image.FilteredImageSource

Cette classe qui implémente l'interface ImageProducer permet de créer une image filtrée. Le constructeurde cette classe prend en paramètre une instance d'une classe implémentant l'interface ImageProducer(obtenue par exemple grâce à la méthode getSource () de la classe Image) et une instance d'une classede filtre. Les applets NegatifImage , Compteur et AnimationFleche utilise cette classe pour créer desimages filtrées.

Constructeur

public FilteredImageSource (ImageProducer orig, ImageFilter imgf)

Méthodes

public synchronized void addConsumer (ImageConsumer ic)public synchronized boolean isConsumer (ImageConsumer ic)

Page 283: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 13

public synchronized void removeConsumer (ImageConsumer ic)public void startProduction (ImageConsumer ic)public void requestTopDownLeftRightResend (ImageConsumer ic)

Implémentation des méthodes de l'interface ImageProducer.

La classe java.awt.image.ImageFilter

Cette classe qui implémente les interfaces ImageConsumer et Cloneable, est la super classe de toutes lesclasses permettant de réaliser un filtrage. Cette classe n'a aucun effet sur l'image à filtrer (filtre nul). Lepackage java.awt.image fournit les deux classes de filtre CropImageFilter et RGBImageFilter.

Variable

protected ImageConsumer consumer

Consommateur final d'images de l'image filtrée. Une fois modifiées, les données doivent être renvoyée àce consommateur.

Constructeur

public ImageFilter ()

Méthodes

public void setDimensions (int width, int height)public void setProperties (Hashtable props)public void setColorModel (ColorModel model)public void setHints (int hints)public void setPixels (int x, int y, int w, int h, ColorModel model, byte pixels [ ], int off, int scansize)public void setPixels (int x, int y, int w, int h, ColorModel model, int pixels [ ], int off, int scansize)public void imageComplete (int status)

Implémentation des méthodes de l'interface ImageConsumer pour renvoyer l'image non modifiée àconsumer.

public ImageFilter getFilterInstance (ImageConsumer ic)public void resendTopDownLeftRight (ImageProducer ip)public Object clone ()

Exemple

Applet Compteur .

La classe java.awt.image.CropImageFilter

Cette classe qui dérive de la classe ImageFilter permet d'extraire une partie d'une image. Elle estintéressante pour récupérer différentes images d'une image téléchargée. En effet, il est plus rapide decharger un seul fichier et d'en extraire plusieurs images que de charger plusieurs images, car une seulerequête est nécessaire et la taille d'un fichier compressé comportant plusieurs images est plus petite quela somme des tailles des fichiers compressés de ces images.

Constructeur

public CropImageFilter (int x, int y, int width, int height)

Construit un filtre permettant d'extraire une image aux coordonnées (x,y), de largeur width et dehauteur height.

Méthodes

Page 284: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 14

public void setProperties (Hashtable props)public void setDimensions (int w, int h)public void setPixels (int x, int y, int w, int h, ColorModel model, byte pixels [ ], int off, int scansize)public void setPixels (int x, int y, int w, int h, ColorModel model, int pixels [ ], int off, int scansize)

Ces méthodes outrepassent celles de la classe ImageFilter pour réaliser les opérations du filtre.

Exemple

Applet AnimationFleche .

La classe java.awt.image.RGBImageFilter

Cette classe abstract qui dérive de la classe ImageFilter permet de créer des classes de filtresmodifiant la couleur des points d'une images. Il faut pour cela créer une classe dérivée de cette classe etimplémenter la méthode filterRGB (int x, int y, int rgb) pour qu'elle renvoie la nouvelle couleur(modifiée ou non) du point de coordonnées (x,y). A la création de l'image filtrée avec la classeFilteredImageSource, l'ensemble des points de l'image originale est énuméré à travers cette méthodepour récupérer la couleur de chacun des points de la nouvelle image.

Variables

protected ColorModel origmodelprotected ColorModel newmodel protected boolean canFilterIndexColorModel

Si le filtrage de la couleur ne dépend pas des coordonnées des points de l'image, il est conseillé demettre cette variable à true.

Constructeur

public RGBImageFilter ()

Méthodes

public abstract int filterRGB (int x, int y, int rgb)

Cette méthode doit être outrepassée par les classes dérivées pour renvoyer la couleur du point decoordonnées (x,y) de l'image filtrée, sachant que la couleur de l'image originale est égale à rgb à cepoint.

public void filterRGBPixels (int x, int y, int w, int h, int pixels [ ], int off, int scansize) public void substituteColorModel (ColorModel oldcm, ColorModel newcm)public IndexColorModel filterIndexColorModel (IndexColorModel icm) public void setColorModel (ColorModel model)public void setPixels (int x, int y, int w, int h, ColorModel model, byte pixels [ ], int off, int scansize)public void setPixels (int x, int y, int w, int h, ColorModel model, int pixels [ ], int off, int scansize)

Ces méthodes outrepassent celles de la classe ImageFilter pour réaliser les opérations du filtre.

Page 285: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 15

Voici un exemple d'applet utilisant cette classe pour créer le négatif d'une image :

et le programme Java correspondant (à copier dans un fichier dénommé NegatifImage.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*; public class NegatifImage extends Applet{ private Image image, negatifImage; public void init () { // Création d'une image et de son négatif image = getImage (getCodeBase (), "rockfel.jpg"); negatifImage = createImage (new FilteredImageSource (image.getSource (), new FiltreNegatif ())); } public void paint (Graphics gc) { if (image != null) { // Affichage des images gc.drawImage (image, 0, 0, this); gc.drawImage (negatifImage, image.getWidth (this) + 10, 0, this); } }} // Classe FiltreNegatif transformant une couleur en son inverseclass FiltreNegatif extends RGBImageFilter{ public FiltreNegatif () { // La transformation des couleurs ne dépend pas // des coordonnées des points de l'image canFilterIndexColorModel = true; } public int filterRGB (int x, int y, int rgb) { int alpha = rgb & 0xFF000000; // Transformation des composantes RGB en leur inverse int rougeInverse = (rgb & 0xFF0000) ^ 0xFF0000; int vertInverse = (rgb & 0x00FF00) ^ 0x00FF00; int bleuInverse = (rgb & 0x0000FF) ^ 0x0000FF; return alpha | rougeInverse | vertInverse | bleuInverse; }}

Comment ça marche ?

Les classes décrites précédemment implémentent soit l'interface ImageProducer (classesMemoryImageSource et FilteredImageSource), soit l'interface ImageConsumer (classes PixelGrabber,ImageFilter et les classes qui en dérivent).

Page 286: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 16

Bien qu'il soit entièrement possible d'utiliser ces classes sans connaître ces interfaces, vous vousdemandez peut-être à quoi servent les interfaces ImageProducer et ImageConsumer et quel modèle ellesrespectent.Tout d'abord, ces deux interfaces ne vont pas l'une sans l'autre. C'est un peu comme pour vous,consommateur d'images (ImageConsumer ), et votre magnétoscope, producteur d'images (ImageProducer ) :vous mettez en marche le magnétoscope pour voir un film. Vous pouvez être plusieurs à voir un mêmefilm et le magnétoscope n'a d'intérêt que si les images qu'ils diffusent sont vues. Souvenez-vous de cetteanalogie, elle vous aidera à mieux comprendre comment fonctionne le modèle de gestion des images dupackage java.awt.image.

Généralement en Java, un consommateur d'images est le système graphique de votre ordinateur quiattend qu'on lui transmette les pixels à afficher à l'écran. Un producteur d'images est capable de créerune image à partir d'un fichier GIF ou JPEG (la méthode getImage () de la classe Toolkit renvoie uneinstance de la classe Image dont le producteur peut être obtenu grâce à la méthode getSource ()) ou àpartir d'une zone mémoire (via la classe MemoryImageSource).Quand le consommateur d'images a besoin d'afficher une image, le producteur d'images est démarré enappelant la méthode startProduction () qu'implémente le producteur. Ce dernier renvoie alors auconsommateur tous les renseignements (taille, modèle de couleur, couleur de chacun des pixels) qui luipermettront de construire l'image, en appelant successivement les méthodes setDimensions (),setColorModel (), setPixels () qu'implémente le consommateur.

figure 17. Génération d'une image

Quand toutes les données d'une image ont été transmises au consommateur ou en cas d'erreur, leproducteur appelle la méthode imageComplete () qu'implémente le consommateur.Le producteur peut éventuellement délivrer l'image par morceaux en appelant plusieurs fois la méthodesetPixels (), ce qui permet au consommateur d'afficher l'image au fur et à mesure qu'elle estdisponible. Par exemple, c'est ce qui se produit à l'affichage d'une image provenant d'un fichiertéléchargé sur Internet : comme les données de l'image sont délivrées relativement lentement, on voitl'image qui se dessine petit à petit comme dans l'exemple d'applet ImageSimple .Le producteur peut être aussi capable de générer plusieurs images pour créer un animation. Dans ce cas,il appelle imageComplete () à chaque fois qu'une image de l'animation (frame en anglais) a étéentièrement décrite.Comme il est possible que plusieurs personnes regardent un même film, un producteur d'images peutavoir plusieurs consommateurs qui lui demandent de leur envoyer les données d'une image.

En appliquant ce modèle de manière plus générale, il est possible d'imaginer toute sorte de classes deproducteur ou de consommateur d'images, du moment qu'ils implémentent les interfaces ImageProducerou ImageConsumer. Il est possible de créer par exemple une classe de consommateur d'images dont le butest d'écrire une image dans un fichier respectant tel ou tel format : c'est ce schéma qu'utilise labibliothèque fournit par Acme, pour générer des sorties GIF ou JPEG.La classe PixelGrabber est aussi une classe implémentant l'interface ImageConsumer : elle permetd'interroger la valeur des pixels d'une image. En fait, elle stocke dans un tableau les valeurs transmisespar le producteur à l'appel de la méthode setPixels ().

Le filtrage d'images utilise aussi ce système, en intercalant des classes de producteur(FilteredImageSource) et de consommateur (dérivant de la classe ImageFilter qui implémentel'interface ImageConsumer) entre le producteur original et le consommateur final.

Page 287: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 17

figure 18. Filtrage d'une image

Pour créer une image filtrée imageFiltree de classe FilteredImageSource, vous devez passer enparamètre au constructeur de cette classe un producteur d'image et un filtre dont la classe FiltreImagedérive de ImageFilter.Quand le consommateur d'images va appeler la méthode startProduction () sur imageFiltree, l'objetimageFiltree va créer une instance spéciale de filtre filtreImageIC qui mémorise le consommateurfinal puis imageFiltree va à son tour appeler la méthode startProduction () sur le producteur originalen lui passant en paramètre le nouveau consommateur d'images filtreImageIC.Quand le producteur original va produire l'image en appelant successivement les méthodessetDimensions (), setPixels (),... ce sera donc sur le consommateur filtreImageIC. filtreImageIC varappeler ces méthodes sur le consommateur final avec des valeurs modifiées en fonction du filtre voulu.Comme c'est filtreImageIC qui transmet toutes les données de l'image au consommateur final, il peutcréer tous les effets possibles, comme changer la taille ou les couleurs de l'image, voir même créer uneanimation sur une image qui était statique à l'origine !

Voici un exemple d'applet qui affiche l'image d'un nombre aléatoire et utilise la classe de filtreImageFilterCounter dérivant de la classe ImageFilter. Cette classe permet de fabriquer l'image d'unnombre donné à partir d'une image décrivant les 10 chiffres de 0 à 9, dans 10 zones rectangulaires detaille égale. Globalement, quand le producteur appelle une des deux méthodes setPixels (), cetteclasse mémorise les pixels qu'on lui transmet, puis une fois qu'elle a une image complète, elle retransmetau consommateur final les images de chacun des chiffres du nombre à afficher.Cette applet prend en paramètre le nom du fichier d'image contenant tous les chiffres. Ceci permet derendre le compteur sous différents aspects, comme le montrent les deux exemples suivants, l'un utilisantune image JPEG, l'autre un GIF animé (l'animation d'un GIF n'est gérée qu'à partir de Java 1.1) :

Voici le programme Java correspondant (à copier dans un fichier dénommé Compteur.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*; public class Compteur extends Applet{ private Image image; public void start () { // Récupération de l'image originale dont le fichier // est indiqué dans le paramètre de l'applet "image" Image imageOriginale = getImage (getCodeBase (), getParameter ("image")); // Création d'une image filtrée avec un nombre aléatoire image = createImage (new FilteredImageSource (imageOriginale.getSource (), new ImageFilterCounter ((int)(Math.random () * 100000), } public void paint (Graphics gc)

Page 288: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 18

{ if (image != null) // Affichage de l'image gc.drawImage (image, 0, 0, this); }} // Classe de filtre créant l'image d'un nombre à partir d'une// image comportant tous les chiffres de 0 à 9class ImageFilterCounter extends ImageFilter{ private int valeur; private int nbChiffres; private int largeurImageOriginale; private int hauteurImageOriginale; private byte [] bytePixels; private int [] intPixels; private ColorModel model; public ImageFilterCounter (int valeur, int nbChiffres) { this.valeur = valeur; this.nbChiffres = nbChiffres; } // Implémentation des méthodes de ImageConsumer public void setDimensions (int width, int height) { largeurImageOriginale = width; hauteurImageOriginale = height; // Renvoie la dimension de l'image au consommateur final consumer.setDimensions (nbChiffres * largeurImageOriginale / 10, height); } public void setHints (int hints) { // Positionnemennt de RANDOMPIXELORDER uniquement pour dire que // les pixels dont renvoyés dans un ordre aléatoire consumer.setHints ( ( hints | RANDOMPIXELORDER) & ~(TOPDOWNLEFTRIGHT | COMPLETESCANLINES)); } public void setColorModel (ColorModel model) { this.model = model; consumer.setColorModel (model); } public void setPixels (int x, int y, int width, int height, ColorModel model, byte pixels [], int offset, int scansize) { if (bytePixels == null) bytePixels = new byte [largeurImageOriginale * hauteurImageOriginale]; copyPixels (x, y, width, height, pixels, offset, scansize, bytePixels); } public void setPixels (int x, int y, int width, int height, ColorModel model, int pixels[], int offset, int scansize) { if (intPixels == null) intPixels = new int [largeurImageOriginale * hauteurImageOriginale]; copyPixels (x, y, width, height, pixels, offset, scansize, intPixels); } // Recopie la portion d'image chargee dans le tableau destPixels private void copyPixels (int x, int y, int width, int height, Object pixels, int offset, int scansize, Object destPixels) { for (int i = 0; i < height; i++) System.arraycopy (pixels, offset + (scansize * i), destPixels, x + (y + i) * largeurImageOriginale, width);

Page 289: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 19

} public void imageComplete (int status) { if ( status == IMAGEERROR || status == IMAGEABORTED) consumer.imageComplete(status); else { int largeurChiffre = largeurImageOriginale / 10; // Renvoie vers le consommateur final les chiffres du compteur un à un for (int puissanceDix = nbChiffres - 1; puissanceDix >= 0; puissanceDix--) { // Recherche du chiffre à afficher int chiffre = (valeur / (int)Math.pow (10, puissanceDix)) % 10; if (bytePixels != null) consumer.setPixels ((nbChiffres - puissanceDix - 1) * largeurChiffre, 0, largeurChiffre, hauteurImageOriginale, model, bytePixels, chiffre * largeurChiffre, largeurImageOriginale); else consumer.setPixels ((nbChiffres - puissanceDix - 1) * largeurChiffre, 0, largeurChiffre, hauteurImageOriginale, model, intPixels, chiffre * largeurChiffre, largeurImageOriginale); } consumer.imageComplete (status); } }}

L'interface java.awt.image.ImageProducer

Cette interface est implémentée par les classes qui sont capables de produire des images. A l'appel de laméthode startProduction (), la classe qui implémente cette interface doit commencer à produire uneimage vers un consommateur, qui lui doit implémenter l'interface ImageConsumer. Ceci doit se traduirepar l'appel des méthodes de l'interface ImageConsumer pour transmettre au consommateur lesinformations décrivant l'image.Un producteur est capable de produire des images pour un ou plusieurs consommateurs. Les méthodesaddConsumer (), isConsumer () et removeConsumer () doivent être implémentées pour gérer cetensemble de consommateurs.

Méthodes

public synchronized void addConsumer (ImageConsumer ic)public synchronized void removeConsumer (ImageConsumer ic)

Ces méthodes doivent ajouter ou retirer le consommateur d'images ic, de l'ensemble des consommateursenregistrés par ce producteur.

public synchronized boolean isConsumer (ImageConsumer ic)

Doit renvoyer true si ic appartient à l'ensemble des consommateurs d'images enregistrés par ceproducteur.

public void startProduction (ImageConsumer ic)

Cette méthode méthode doit enregistrer ic comme consommateur d'images, et commencer la productionde(s) image(s) en appelant les différentes méthodes de l'interface ImageConsumer sur chacun desconsommateurs d'images enregistrés.

public void requestTopDownLeftRightResend (ImageConsumer ic)

Cette méthode doit essayer de renvoyer les données de l'image vers le consommateur d'images ic avecles pixels transmis de haut en bas et de gauche à droite, pour que le traitement des pixels par ceconsommateur soit de meilleure qualité. Par conséquent, le producteur doit appeler la méthode setHints() de l'interface ImageConsumer avec comme paramètre TOPDOWNLEFTRIGHT.

L'interface java.awt.image.ImageConsumer

Page 290: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 20

Cette interface est implémentée par les classes qui ont besoin des données d'une image. Un producteurd'image, dont la classe doit implémenter l'interface ImageProducer, invoque chacune des différentesméthodes de cette interface pour transmettre au consommateur d'images tous les renseignementsdécrivant une image.

Variables

public final static int RANDOMPIXELORDERpublic final static int TOPDOWNLEFTRIGHTpublic final static int COMPLETESCANLINES

La méthode setHints () est appelée avec comme paramètre l'une de ces trois constantes combinéeéventuellement avec l'une des deux suivantes, pour transmettre au consommateur dans quel ordre seronttransmis les pixels de l'image pendant les appels successifs à la méthode setPixels (). Le producteurpeut envoyer ces pixels dans un ordre aléatoire, de haut en bas et de gauche à droite, ou par ligne entièremais dans un ordre indéterminé.

public final static int SINGLEPASS

La méthode setHints () peut recevoir en paramètre cette constante, pour signifier au consommateurque l'image sera générée par le producteur en une seule passe.

public final static int SINGLEFRAME

La méthode setHints () peut recevoir en paramètre cette constante, pour signifier au consommateurqu'une seule image sera générée par le producteur. Dans le cas contraire, un ensemble d'images peuventêtre transmises au consommateur pour fabriquer une animation et chaque fois qu'une image est complèteimageComplete () est appelée avec SINGLEFRAMEDONE en paramètre ou SINGLEFRAMEDONE quandl'animation est terminée.

public final static int IMAGEERRORpublic final static int IMAGEABORTEDpublic final static int STATICIMAGEDONEpublic final static int SINGLEFRAMEDONE

La méthode imageComplete () est appelée avec comme paramètre l'une de ces quatre constantes, pourindiquer au consommateur si la génération de l'image a rencontré une erreur, si elle a été interrompue, sil'image final est terminée ou si la génération d'une image d'un ensemble en comportant plusieurs estcomplète.

Méthodes

public void setDimensions (int width, int height)

Cette méthode est appelée par le producteur d'images pour transmettre au consommateur la largeurwidth et la hauteur height de l'image produite.

public void setProperties (Hashtable props)

Cette méthode est appelée par le producteur d'images pour transmettre au consommateur les propriétésprops de l'image.

public void setColorModel (ColorModel model)

Cette méthode est appelée par le producteur d'images pour transmettre au consommateur le modèle decouleurs le plus courant utilisé pour décrire l'image.

public void setHints (int hints)

Cette méthode est appelée par le producteur d'images pour transmettre au consommateur les propriétéshints de l'image. hints est une combinaison des constantes RANDOMPIXELORDER, TOPDOWNLEFTRIGHT ouCOMPLETESCANLINES, SINGLEPASS et SINGLEFRAME et permet au consommateur de préparer et d'optimiserson environnement en fonction de la manière dont sera générée l'image.

Page 291: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 21

public void setPixels (int x, int y, int width, int height, ColorModel model, byte pixels [ ], int off, int scansize)public void setPixels (int x, int y, int width, int height, ColorModel model, int pixels [ ], int off, int scansize)

L'une de ces deux méthodes est appelée par le producteur d'images pour transmettre au consommateurles valeurs des pixels de la portion d'image de taille width et height au point (x,y). La première méthodereçoit les pixels dans un tableau de type byte, l'autre dans un tableau de type int. Ces pixels utilisent lemodèle de couleur model. Les données du tableau pixels sont à prendre en compte à partir de l'indiceoffset, et comprennent un nombre de scansize pixels par ligne.

public void imageComplete (int status)

Cette méthode appelée par le producteur d'images doit être implémentée pour prendre en compte lestatut status de la génération d'images (égal à IMAGEERROR, IMAGEABORTED, STATICIMAGEDONE ouSINGLEFRAMEDONE).

Exemple

Applet Compteur .

Gestion d'animations

L'utilisation des threads et des images permet de réaliser rapidement des animations en Java. Comme lemontrent les trois exemples suivant, le principe de programmation d'une animation est presque toujoursle même : Vous créez un thread dont la méthode run () utilise une boucle qui à chaque tour affiche unenouvelle image puis arrête le thread courant pendant un laps de temps avec la méthode sleep () de laclasse Thread.Bien que comme au cinéma, une animation sera en apparence bien fluide à 25 images par seconde(équivalent à un laps de temps entre chaque image de 40 millesecondes), évitez un laps de temps derafraîchissement aussi court, car les machines ont souvent du mal à suivre.

Si comme dans certains des exemples qui suivent, vous utilisez la méthode repaint () pour mettre àjour l'image d'une animation, le redessin du fond du composant effectué par la méthode update () dela classe Component est inutile si vous devez transférer une image à l'écran occupant toute la surface ducomposant.N'oubliez pas alors d'outrepasser la méthode update () pour qu'elle appelle directement la méthodepaint () sans redessiner le fond de l'image. Ceci évitera un clignotement désagréable.

Enchaînement d'images téléchargées

Cette première applet utilise des images contenues dans un fichier téléchargé. Elles sont extraites de l'imagechargée grâce à l'utilisation de la classe de filtre CropImageFilter, puis un thread provoque leur affichage l'uneaprès l'autre à intervalle régulier pour donner l'effet animé :

Voici le programme Java correspondant (à copier dans un fichier dénommé AnimationFleche.java etinvoqué à partir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*; public class AnimationFleche extends Applet implements Runnable{

Page 292: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 22

private Thread threadAnimation = null; private Image imagesAnimation [ ] = new Image [8]; private int imageCourante = 0; public void init () { try { // Création de l'image globale mémorisant 8 dessins de flèches Image multiImages = getImage (getCodeBase (), "fleches.gif"); // Création d'un MediaTracker pour récupérer les 8 images MediaTracker imageTracker = new MediaTracker (this); for (int i = 0; i < imagesAnimation.length; i++) { // Chacune des 8 images est extraite de l'image principale imagesAnimation [i] = createImage (new FilteredImageSource (multiImages.getSource (), new CropImageFilter (i * 50, 0, 50, 50))); imageTracker.addImage (imagesAnimation [i], 0); } imageTracker.waitForID (0); // En cas d'erreur, déclenchement d'une exception if (imageTracker.isErrorAny ()) throw new IllegalArgumentException ("Images non chargees"); } catch (Exception e) { } } public void start () { // Création et démarrage d'un thread d'animation threadAnimation = new Thread (this); threadAnimation.start (); } public void stop () { threadAnimation.stop (); } public void run () { while (threadAnimation.isAlive ()) try { // Redessin de l'applet et passage à l'image suivante repaint (); imageCourante = ++imageCourante % 8; // Attente de 70 ms avant de passer à l'image suivante Thread.sleep (70); } catch (InterruptedException exception) { } } // Méthode outrepassée pour qu'elle dessine directement l'image public void update (Graphics gc) { paint (gc); } public void paint (Graphics gc) { // Dessin de l'image courante gc.drawImage (imagesAnimation [imageCourante], 0, 0, this); }}

Utilisation du double buffering

Cette applet montre l'intérêt d'utiliser le système du double buffering pour gérer l'animation d'une image

Page 293: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 23

générée par un programme.Le principe en est simple : au lieu de dessiner directement à l'écran un dessin qui évolue à chaque lapsde temps, vous utilisez une image dans laquelle vous dessinez puis que vous transférez à l'écran. Ceciévite l'effet de clignotement d'une animation démontré par l'applet suivante, qui affiche un texte défilanthorizontalement :

Voici le programme Java correspondant (à copier dans un fichier dénommé ScrollText.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*; public class ScrollText extends Applet implements Runnable{ private String texte; private Thread threadAnimation; private Dimension tailleApplet; private int positionTexte; private FontMetrics metrics; private int largeurTexte; public void start () { // Mise en blanc du fond de l'applet setBackground (Color.white); tailleApplet = size (); // Récupération du texte à afficher texte = getParameter ("Texte"); positionTexte = tailleApplet.width; // Création et démarrage du thread d'animation threadAnimation = new Thread (this); threadAnimation.start(); } public void stop () { threadAnimation.stop (); } public void run () { try { while (threadAnimation.isAlive ()) { // Redessin de l'applet et calcul d'une nouvelle position repaint (); if (positionTexte > -largeurTexte) positionTexte -= tailleApplet.height / 2; else positionTexte = tailleApplet.width; // Arrête le compteur pendant 2/10 de secondes (200 ms) Thread.sleep (200); } } catch (InterruptedException e) { } } public void paint (Graphics gc) { gc.setColor (Color.black); // Création d'une police de caractères et récupération de sa taille gc.setFont (new Font ("Helvetica", Font.BOLD, tailleApplet.height - 4)); if (metrics == null) { metrics = gc.getFontMetrics (); largeurTexte = metrics.stringWidth (texte); } // Utilisation d'un rectangle de clipping

Page 294: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 24

// pour créer une bordure au bord de l'applet gc.clipRect (2, 0, tailleApplet.width - 4, tailleApplet.height); // Dessin du texte gc.drawString (texte, positionTexte + 2, tailleApplet.height - metrics.getDescent () - 2); }}

Si vous consultez le source de ce fichier HTML , vous pourrez voir que le paramètre Texte de cetteapplet permet de modifier le texte affichée :

<APPLET CODE="ScrollText" CODEBASE="../classes" ALT="ScrollText" WIDTH=250 HEIGHT=40 ALIGN=middle> <PARAM NAME="Texte" VALUE="Texte d&eacute;filant horizontalement..."></APPLET>

Maintenant, voici la même applet modifiée pour éviter l'effet de clignotement :

La modification apportée porte sur la manière de programmer la méthode paint () de l'applet ScrollText:

// ... public class ScrollText extends Applet implements Runnable{ // start (), stop () et run () : même code que précédemment private Image imageTexte; public void paint (Graphics gc) { // Création d'une image de la taille de l'applet if (imageTexte == null) imageTexte = createImage (tailleApplet.width, tailleApplet.height); Graphics gcImage = imageTexte.getGraphics (); // Même dessin mais cette fois-ci dans l'image gcImage.setColor (Color.white); gcImage.fillRect (0, 0, tailleApplet.width, tailleApplet.height); gcImage.setColor (Color.black); gcImage.setFont (new Font ("Helvetica", Font.BOLD, tailleApplet.height - 4)); if (metrics == null) { metrics = gcImage.getFontMetrics (); largeurTexte = metrics.stringWidth (texte); } gcImage.clipRect (2, 0, tailleApplet.width - 4, tailleApplet.height); gcImage.drawString (texte, positionTexte + 2, tailleApplet.height - metrics.getDescent () - 2); // Dessin de l'image à l'écran gc.drawImage (imageTexte, 0, 0, this); } // Méthode outrepassée pour éviter de dessiner le fond public void update (Graphics gc) { paint (gc); }}

Horloge avec image de fond

Cette applet est aussi un exemple d'utilisation du système du double buffering et montre la possibilité dedessiner par dessus une image chargée à partir d'un fichier. Au début du programme, le fond de l'horlogeest téléchargé, puis toutes les secondes une nouvelle image est mise à jour en copiant ce fond dans le

Page 295: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 25

double buffer puis en dessinant les aiguilles par dessus à leur nouvelle position :

Voici le programme Java correspondant (à copier dans un fichier dénommé Horloge.java et invoqué àpartir d'un fichier HTML) :

import java.applet.Applet;import java.awt.*;import java.awt.image.*;import java.util.Date; public class Horloge extends Applet implements Runnable{ private Thread threadHorloge; private Image fondHorloge; public void init () { try { // Chargement du fond de l'horloge avec un MediaTracker fondHorloge = getImage (getCodeBase (), "starclock.gif"); MediaTracker imageTracker = new MediaTracker (this); imageTracker.addImage (fondHorloge, 0); imageTracker.waitForID (0); if (imageTracker.isErrorAny ()) fondHorloge = null; } catch (Exception e) { } } public void start () { // Lancement d'un thread pour mettre à jour l'horloge threadHorloge = new Thread (this); threadHorloge.start (); } public void stop () { threadHorloge.stop (); } public void run () { try { while (threadHorloge.isAlive ()) { // Récupération du temps courant pour calculer // le durée d'arrêt du thread en fonction du temps // d'exécution de la méthode afficher () long tempsCourant = System.currentTimeMillis (); afficher (new Date (tempsCourant)); long dureeArret = 1000 - ( System.currentTimeMillis () - tempsCourant); if (dureeArret > 0) Thread.sleep (dureeArret); } } catch (InterruptedException exception) { } } private Image horloge; private void afficher (Date tempsCourant)

Page 296: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 26

{ // Création d'une image aux dimensions de l'applet Dimension taille = size (); if (horloge == null) horloge = createImage (taille.width, taille.height); // Récupération des heures, minutes et secondes int heures = tempsCourant.getHours (); int minutes = tempsCourant.getMinutes (); int secondes = tempsCourant.getSeconds (); // Pour chaque aiguille, conversion du temps en radian // et récupération du polygone utilisant cet angle double angleHeure = (180 - heures * 60 - minutes) * Math.PI / 360; Polygon pointsHeure = calculerAiguille (angleHeure, taille.width / 4., taille.height / 4.); double angleMinute = (900 - minutes * 60 - secondes) * Math.PI / 1800; Polygon pointsMinute = calculerAiguille (angleMinute, 3. * taille.width / 8., 3. * taille.height / 8.); double angleSeconde = (15 - secondes) * Math.PI / 30; Polygon pointsSeconde = calculerAiguille (angleSeconde, 2. * taille.width / 5., 2. * taille.height / 5.); Graphics gcImage = horloge.getGraphics (); if (fondHorloge != null) // Dessin de l'image de fond d'horloge avec redimensionnement gcImage.drawImage (fondHorloge, 0, 0, taille.width, taille.height, this); else { // Si l'image de fond d'horloge est absente // remplissage avec une couleur et dessin d'un cercle gcImage.setColor (new Color (0x638494)); gcImage.fillRect (0, 0, taille.width, taille.height); gcImage.setColor (Color.white); gcImage.drawOval (0, 0, taille.width - 1, taille.height - 1); } // Translation au centre de l'horloge gcImage.translate (taille.width / 2, taille.height / 2); // Dessin des aiguilles (les secondes utilisent une ligne) gcImage.setColor (Color.white); gcImage.drawPolygon (pointsHeure); gcImage.drawPolygon (pointsMinute); gcImage.drawLine (pointsSeconde.xpoints [0], pointsSeconde.ypoints [0], pointsSeconde.xpoints [2], pointsSeconde.ypoints [2]); // Mise à jour à l'écran repaint (); } // Dessin d'une aiguille à 3 heures (0 rad) private int [] xAiguille = {-15, 33, 100, 33, -15}; private int [] yAiguille = { 0, 10, 0, -10, 0}; private Polygon pointsAiguille = new Polygon (xAiguille, yAiguille, xAiguille.length); private Polygon calculerAiguille (double angle, double width, double height) { Polygon points = new Polygon (); // Calcul de la rotation de chaque point de l'aiguille for (int i = 0; i < pointsAiguille.npoints; i++) points.addPoint ((int)( ( pointsAiguille.xpoints [i] * Math.cos (angle) + pointsAiguille.ypoints [i] * Math.sin (angle)) * width / 100), (int)( ( pointsAiguille.xpoints [i] * -Math.sin (angle)

Page 297: CJava

vendredi 11 février 2000 Du C/C++ à Java : Les images Page: 27

+ pointsAiguille.ypoints [i] * Math.cos (angle)) * height / 100)); return points; } public void update (Graphics gc) { paint (gc); } public void paint (Graphics gc) { // Dessin de l'image à l'écran if (horloge != null) gc.drawImage (horloge, 0, 0, this); }}

Cette applet pourrait être améliorée en lui permettant de récupérer en paramètre l'image de fond, le choixd'afficher les secondes ou non, l'ajout d'effets sonores toutes les secondes ou toutes les heures enutilisant l'interface AudioClip,...

Page 298: CJava

vendredi 11 février 2000 Du C/C++ à Java : Plus loin avec Java... Page: 1

Plus loin avec Java...

Les évolutions du langageConclusion

Les évolutions du langage

Le langage Java évolue rapidement : après les premières versions 1.0 de test sorties fin 1995, la version1.1 est apparue au printemps 1997 et la version 2 (anciennement 1.2) en décembre 1998 (disponible pourWindows, Solaris et Linux chez Javasoft).Ce paragraphe vous présente les principales évolutions apportées à Java au cours de ses versions : cesdéveloppements ont surtout enrichis la bibliothèque de classes Java mais certains portent aussi sur lenoyau du langage lui-même.

Classes internes (inner classes ) : ce type de classes a accès à toutes les variables de la classedans laquelle elles sont définies. Les fichiers de classes, d'images, de sons,... dont peut avoir besoin un programme Java,peuvent être rassemblés dans un seul fichier au format JAR (Java ARchvive). Ceci permetde charger une applet en seule requête HTTP et de réduire la taille des fichiers car ceformat reprend le format de compression ZIP. Le chargement des applets est ainsiaccéléré. Un nouveau système de gestion des événements utilisant un modèle de délégation desévénements. JavaBeansTM : ce nouveau package permet de créer des classes de composants réutilisableset que l'on peut facilement assembler ensemble dans les environnements dedéveloppement rapide (RAD), comme le permettent d'autres produits comme ActiveX deMicrosoft. Internationalisation : gestion de ressources pour permettre de gérer les différentes versionsd'un programme suivant la langue de l'utilisateur. La possibilité d'enregistrer les objets (sérialisation) et de les recréer à partir d'unesauvegarde. Remote Method Invocation : ces nouveaux packages permettent d'invoquer des méthodes àdistance sur des objets fonctionnant sur d'autres Machines Virtuelles Java etéventuellement même sur un autre ordinateur d'un réseau. Ceci permet de mettre enpratique la programmation objet distribué. JDBCTM (Java DataBase Connectivity) : ce package permet d'accéder à des bases dedonnées via des requêtes SQL. ...

JFC (Java Foundation Classes) : cette ensemble de classes vient enrichir de manièresignificative la gestion de l'interface graphique actuelle AWT. Il se décompose endifférents types de fonctionnalités :

Swing : ces nouvelles classes définissent un nouvel ensemble de composantsreprenant les composants classiques (bouton, liste,...) enrichi de composants pluscomplexes (arbre, tableau,...). Java 2D : ces nouvelles classes du package java.awt permettent d'effectuer desopérations plus riches de dessins : définitions et compositions de formes,transformations, antialiasing, gestion plus riche des polices de caractères... Drag and drop (glisser-déposer pour les puristes) : gestion du transfert de donnéesentre applications Java et applications natives du système.

Collections de données : de nouvelles classes sont ajoutées au package java.util,permettant de gérer des listes chaînées, des ensembles,... et d'effectuer des opérations detris, de recherche,... Intégration de CORBA (Common Object Request Broker Architecture) dans Java. Améliorations diverses des classes existantes et des performances. ...

Page 299: CJava

vendredi 11 février 2000 Du C/C++ à Java : Plus loin avec Java... Page: 2

A ces versions de base, s'ajoutent des bibliothèques d'extensions développées par Javasoft, quifonctionnent soit avec Java 1.1, soit avec Java 2 :

Swing (compatible Java 1.1) : cette bibliothèque intégrée dans Java 2, est aussi utilisable avec Java1.1. Servlets (compatible Java 1.1) : les servlets permettent de réaliser des programmes CGI (CommonGateway Interface ) en Java sur un serveur Internet. Ce type de programme permet par exemple deprogrammer un compteur de page ou un moteur de recherche. JavaMail (compatible Java 1.1) : cette bibliothèque permet de gérer une boite email (envoi/lecturede message sur un serveur de mail). Java 3D (compatible Java 2) : cette bibliothèque permet de programmer de réaliser des scènesvirtuelles en 3D, et permet de gérer les éclairages, les textures, les animations d'objets 3D. ...

Ce manuel présente la version 2 du noyau du langage Java et la version 1.0 de la bibliothèque Java (quipermet de faire déjà beaucoup de choses), et sera appelé à présenter plus dans le détail les évolutionsdécrites précédemment.

Conclusion

Un des principaux atouts de Java est sa portabilité résumée dans la phrase Write once, run anywhere TM

(Ecrivez une fois, faites tourner n'importe où). A l'usage, vous verrez que certaines des premièresversions des navigateurs ne permettent pas toujours de faire tourner vos applets de la manière attendue.Les principaux problèmes surviennent surtout pour les méthodes des interfaces du package java.appletqui sont justement implémentées par chaque navigateur... Si vous voulez utiliser ces fonctionnalités,testez si possible vos applets sur différents navigateurs pour vérifier leur bon fonctionnement.

Certaines personnes reprocheront aussi au système d'interface graphique AWT de Java de n'être que leplus petit dénominateur commun entre toutes les fonctionnalités fournies par les différents systèmesexistants (MacOS, Windows, X11/Motif,...). Bien que ceci soit plutôt vrai, le package java.awt a lemérite d'exister et de satisfaire les besoins de la plupart des applets et applications.Mais la nouvelle bibliothèque Swing qui est utilisable avec Java 1.1 et/ou Java 2 a considérablementenrichi les possibilités de gestion de l'interface graphique tout en offrant un modèle de conception trèsouvert.

Personnellement, je trouve que Java est un langage très agréable et se maîtrisant très rapidement. Pourvous donner un ordre d'idée, j'ai appris le langage en une cinquantaine d'heures (en lisant deuxouvrages), et j'ai réalisé ensuite en une quarantaine d'heures une première version du démineur Java Mine(très proche de la version finale fournie sur le site http://www.eteks.com).

A ce jour, je n'ai trouvé que peu de personnes critiques sur ce langage (et encore que sur des points dedétails à mon avis négligeables tels que les assertions, l'absence de template, l'utilisation de paramètresconstants,...). C'est peut-être bien là que réside la véritable explication de son succès présent et futur :après tout un langage n'est qu'un outil du développeur, et si celui-ci est satisfait par son utilisation, l'outilen question a de bonnes chances de succès...

J'espère que ces pages auront pu rassasier vos esprits curieux, et vous auront convaincu.

Pour terminer, je ne ferai pas de citation (je suis plutôt mauvais dans ce domaine) mais je tiens àremercier toutes les personnes de mon entourage qui m'ont soutenu dans ce travail de longue haleine, neserait-ce que par leur curiosité... et particulièrement Diem My, mon petit Thomas et Sophie la petitedernière.

Si vous avez encore un peu de temps à consacrer à ce manuel, MERCI de donner votre avis grâce auformulaire accompagnant le site http://www.eteks.com.

Page 300: CJava

vendredi 11 février 2000 Historique du site Page: 1

Historique

11 Février 2000 Version 1.1.1 :Corrections diverses de fautes de frappe et d'erreurs de texte.

07 Juillet 1999 Version 1.1 :Description complète des ajouts au noyau du langage Java dans Java 1.1 (classes internes,...). Ces descriptionssont faites essentiellement dans un nouveau chapitre, mais aussi dans les autres chapitres et notamment ceuxsur la création des classes et les tableaux.Description du fonctionnement des classes ImageProducer et ImageConsumer.Ajout de l'applet Compteur , utilisant un filtre d'image.Revue de la plupart du texte.Corrections de fautes de frappe et d'erreurs de texte.

10 Février 1999 Version 1.0.1 :Pour permettre d'ajouter des fonctionnalités de Java 1.1 et Java 2, l'architecture du cours a changé.Après avoir pris en compte l'avis des internautes qui ont répondu au sondage du mois de janvier 99, la solutionretenue est celle-ci (75% des personnes qui ont répondu) :Le manuel Java 1.0 reste tel quel, et une nouvelle branche Java 2 commencera "en parallèle" à partir de ladescription de la bibliothèque (chapitre sur la bibliothèque Java 1.0 et suivants). La seule partie communerestera la description du noyau du langage. Quand cela s'avérera intéressant, des liens entre les parties Java 1.0et Java 2 seront ajoutés.Pour faciliter l'évolution vers cette architecture, tous les chapitrexx.html ont été renommés pour ne plus êtrelié à un numéro de chapitre (désolé pour ceux qui avaient créé un lien vers ces chapitres), le packagejava.lang a son propre chapitre, les conventions d'écriture et le portage de programmes C/C++ ont étérassemblés dans le chapitre qui conclut la description du noyau du langage.Au passage, toutes les ancres utilisées par les liens du site http://www.eteks.com (ce qui suit le symbole #dans un tag <A HREF="file#anchor">), ont été vérifiées et éventuellement corrigées.Corrections de fautes de frappe.

17 Décembre 1998 Version 1.0 :Début décembre, JavaTeks est devenu eTeks et est hébergé sur son propre serveur http://www.eteks.com.Tout Java 1.0 (langage et classes) est décrit. Description complète du package java.net.Ajout des programmes client serveur d'Echo et du Paper board Internet .Ajout d'une description détaillée de la procédure de compilation de l'applet HelloWorld , pour les débutants enprogrammation.Corrections de fautes de frappe et d'erreurs de texte.

31 Octobre 1998 Version 0.9.4 :Ajout des applets CalculetteSimple et MessageBoxApplet .Description partielle du package java.net (Accès via une URL).Corrections de fautes de frappe et d'erreurs de texte (merci à Arcmap).

24 Septembre 1998 Version 0.9.3 :Nouveau look "bleu métal" du site : Nouveaux boutons de navigation, mise en place de frames avec un menupour améliorer la navigation sur le site et alléger la page d'accueil.Ajout d'une FAQ, d'un livre d'or et d'une liste de liens utiles plus complète.Description complète du package java.io.Description plus détaillée des classes du package java.lang.Ajout d'un paragraphe "exemples" à chacune des classes quand c'est possible. Chacun de ces paragraphescontient des liens vers les applets ou les applications du manuel où la classe est utilisée.Découpage en deux du fichier HTML sur l'accès aux fichiers et au réseau (io10.html ), décalage des pages quisuivent.

Page 301: CJava

vendredi 11 février 2000 Historique du site Page: 2

Corrections de fautes de frappe et d'erreurs de texte. 31 Mai 1998

Version 0.9.2 :Ajout d'une table des matières complète.Explication plus détaillée des constructeurs, des méthodes outrepassées, des classes abstract, avec un nouvelexemple d'application.Description partielle du package java.io (Principes généraux et manipulation des fichiers).Ajout d'un paragraphe sur le remplacement de l'héritage multiple du C++ en Java.Modification de l'applet AfficheurDeCalcul .Ajout de l'applet d'animation Horloge .Corrections de fautes de frappe et d'erreurs de texte.

15 Mai 1998 Version 0.9.1 :Ajout de l'applet ImageNoirEtBlanc .Ajout des captures d'écrans des applets pour permettre de visualiser une image à la place de chaque applet sile navigateur n'utilise pas Java.Corrections de fautes de frappe et d'erreurs de texte.

08 Mai 1998 Ajout de balises <META ...> pour les moteurs de recherche et d'un formulaire de réponse sur le site.

06 Mai 1998 Version 0.9 : Première version disponible sur Internet.Après un an de travail et de longues nuits souvent blanches, voilà la version 0.9 de ce manuel : 0.9 comme90% du boulot réalisé. Reste à décrire plus en détail les packages java.io et java.net.