Introduction Java Partie1 - BFH-TI Staff: Homepagesfup1/Contents/Scripts/Introduction_Java_P... ·...

70
Haute école spécialisée bernoise Haute école Technique et Informatique, HTI Section Microtechnique Introduction à la programmation Java Introduction Aspect procédural de la programmation Java Introduction à la programmation OO 2004, HTI Burgdorf E. Firouzi Nom de fichier: Introduction_Java_Partie1 Erstellt am: 5. March 2007 Autor: Elham FIrouzi Version: 1.0

Transcript of Introduction Java Partie1 - BFH-TI Staff: Homepagesfup1/Contents/Scripts/Introduction_Java_P... ·...

Haute école spécialisée bernoise Haute école Technique et Informatique, HTI Section Microtechnique

Introduction à la programmation Java

Introduction

Aspect procédural de la programmation Java Introduction à la programmation OO

� 2004, HTI Burgdorf

E. Firouzi

Nom de fichier: Introduction_Java_Partie1 Erstellt am: 5. March 2007 Autor: Elham FIrouzi Version: 1.0

Introduction à la programmation Java Tables des matières

Version 1.0, 05.03.07 Page II

Tables des matières

1 Introdution........................................................................................................................................................1 1.1 Fondement............................................................................................................................................... 1

1.1.1 Propriété du Java ............................................................................................................................. 1 1.1.2 Champ d’application du Java .......................................................................................................... 1 1.1.3 Lecture ............................................................................................................................................ 1 1.1.4 Information disponibles sur le web ................................................................................................. 2

1.2 Un premier exemple ................................................................................................................................ 2 1.3 Développement de programme en Java................................................................................................... 3

1.3.1 Editeur de text ................................................................................................................................. 3 1.3.2 Compilateur..................................................................................................................................... 3 1.3.3 Interpréteur...................................................................................................................................... 3 1.3.4 Vue d’ensemble............................................................................................................................... 4

1.4 Les applications....................................................................................................................................... 4 1.5 Les applets............................................................................................................................................... 4 1.6 Avantages et désavantage du Java........................................................................................................... 7

2 Aspect procédural de la programmation Java ..................................................................................................8 2.1 Introduction............................................................................................................................................. 8 2.2 Les éléments lexicographiques................................................................................................................ 8

2.2.1 Jeu de caractères.............................................................................................................................. 8 2.2.2 Indicateur ........................................................................................................................................ 8 2.2.3 Les commentaires............................................................................................................................ 8 2.2.4 Les séquences d’échappement......................................................................................................... 9

2.3 Les mots clés ......................................................................................................................................... 10 2.4 Les variables et le type de données élémentaires .................................................................................. 10

2.4.1 Declaration et initialisation de variable......................................................................................... 10 2.4.2 Type de donnée élémentaire.......................................................................................................... 11 2.4.3 Les changements de type de données............................................................................................ 13 2.4.4 La visibilité.................................................................................................................................... 14 2.4.5 Les variables globales ................................................................................................................... 14

2.5 Les chaînes de caractères ...................................................................................................................... 14 2.5.1 String............................................................................................................................................. 14 2.5.2 StringBuffer................................................................................................................................... 15

2.6 Les tableaux .......................................................................................................................................... 16 2.6.1 Les tableaux unidimensionels ....................................................................................................... 16 2.6.2 Les tableaux multidimentionnels................................................................................................... 18

2.7 Les constantes ....................................................................................................................................... 18 2.8 Les opérateurs ....................................................................................................................................... 19

2.8.1 Les opérateurs arithmétiques......................................................................................................... 19 2.8.2 Les opérateurs de comparaison ..................................................................................................... 20 2.8.3 Les opérateurs logiques ................................................................................................................. 20 2.8.4 Les opérateurs de traitement des bits ............................................................................................ 20 2.8.5 Les opérateurs d’affectation .......................................................................................................... 21 2.8.6 L’opérateur point d’intérogation ................................................................................................... 22 2.8.7 L’opérateur cast............................................................................................................................. 22 2.8.8 Les opérateurs supplémentaires pour la programmation OO ........................................................ 22

2.9 Les structures de contrôle...................................................................................................................... 23 2.9.1 Introduction ................................................................................................................................... 23 2.9.2 L’instruction if ............................................................................................................................ 23 2.9.3 L’instruction switch................................................................................................................... 24 2.9.4 La boucle while .......................................................................................................................... 25

Introduction à la programmation Java Tables des matières

Version 1.0, 05.03.07 Page III

2.9.5 La boucle do while ................................................................................................................... 26 2.9.6 La boucle for............................................................................................................................... 27 2.9.7 Contrôle des boucles avec les instructions break et continue ............................................... 28

2.10 Les Méthodes ........................................................................................................................................ 29 2.10.1 Nom, Liste de paramètres et valeur de restitution ......................................................................... 29 2.10.2 Signature, prototype et sur chargement (overloading) .................................................................. 31 2.10.3 La récursion................................................................................................................................... 32

2.11 La méthode principale main()............................................................................................................ 32 3 Introduction à la POO avec Java ....................................................................................................................34

3.1 Introduction........................................................................................................................................... 34 3.1.1 Les problèmes des langage de programmation procédural............................................................ 34 3.1.2 Les types de donnée abstraits ........................................................................................................ 34 3.1.3 Exigences pour les langage de programmation OO ...................................................................... 35

3.2 Caractéristiques des langages OO ......................................................................................................... 35 3.2.1 Abstraction à l’aide d’objet ........................................................................................................... 35 3.2.2 Encapsulage............................................................................. Fehler! Textmarke nicht definiert. 3.2.3 Héritage et polymorphisme ........................................................................................................... 36 3.2.4 Caractéristiques de Java ................................................................................................................ 37

3.3 Les classes et les objets ......................................................................................................................... 37 3.3.1 Définition ...................................................................................................................................... 37 3.3.2 La syntaxe ..................................................................................................................................... 38 3.3.3 Les attributs................................................................................................................................... 38 3.3.4 Les méthodes................................................................................................................................. 38 3.3.5 Modificateur d’accès ..................................................................................................................... 39 3.3.6 Les diagrammes de classe ............................................................................................................. 40 3.3.7 Les méthodes et les attributs de classe .......................................................................................... 41 3.3.8 Instancier un objet, constructeur ................................................................................................... 42 3.3.9 Destructeur et collecteur d’ordure (Garbage Collection) .............................................................. 44 3.3.10 Transmission et retour des objets .................................................................................................. 46 3.3.11 Les classes internes ....................................................................................................................... 47

3.4 Héritage................................................................................................................................................. 48 3.4.1 Fondement..................................................................................................................................... 48 3.4.2 Ordre des constructeurs et des destructeurs................................................................................... 51 3.4.3 Les classes et méthodes abstraites................................................................................................. 53 3.4.4 Polymorphisme ............................................................................................................................. 56 3.4.5 Les casting des classes .................................................................................................................. 57

3.5 Relation entre les classes....................................................................................................................... 58 3.6 Les interface .......................................................................................................................................... 60 3.7 Les paquets............................................................................................................................................ 62

3.7.1 Utilisation et importation .............................................................................................................. 63 3.7.2 Les paquets mis à dispostion par Java........................................................................................... 64 3.7.3 Definition des paquets propres ...................................................................................................... 64 3.7.4 Visibilité........................................................................................................................................ 66

3.8 OO Design............................................................................................................................................. 66 3.8.1 UML.............................................................................................................................................. 66

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 1

1 Introduction

1.1 Fondement Java est un langage de programmation moderne, qui a développé par SUN Microsystems. Java a été introduit officiellement en 1995 et est disponible avec sous licence Open Source depuis 1999.

1.1.1 Propriété du Java Le langage de programmation Java possède les propriétés suivantes :

• Orienté objet : Tous les composants, mis à part les types de donnée simple comme les integer, character ou boolean sont des objets.

• Indépendant de la plateforme : Les programmes Java peuvent être utilisés presque sur toutes les plateformes (PC, Mac, Workstation ...) et systèmes d’opération (Windows, MAC-OS, Linux etc.).

• Interprété : Le code Byte du langage de programmation Java est interprété par la machine virtuelle, en anglais Virtual Machine (VM). Le code byte peut être interprété soit sous forme d’applet (dans un explorateur Internet) ou en tant qu’application indépendante.

• Robuste: Plusieurs dispositifs ont été mis à disposition pour éliminer les erreurs typiques de programmation (pas de pointer, Garbage Collection ...).

• Sur : Des modèles de sécurité sont mis à disposition.

• Dynamique : Java charge uniquement les classes nécessaires à l’application, à travers le réseau.

• Ouvert : Les modules, qui ont été programmés dans un autre langage, peuvent être intégrés au programme Java.

• Applicable en réseau : Une implémentation simple des systèmes en réseau est possible.

• Graphique: La programmation d’interface graphique (GUI) simple et indépendant de la plateforme est possible.

• Multithreading : Java permet d’exécuter des tâches en parallèle et met à disposition des mécanicismes pour les synchroniser.

• Bibliothèque de classes : Java met à disposition des multiples bibliothèques.

1.1.2 Champ d’application du Java Java fut d’abord utilisé dans les secteurs classiques, comme celui des ordinateurs et des applications Internet. Aujourd’hui Java est de plus en plus utilisé dans les consoles portables (en anglais handheld) comme les téléphones portables, les agendas électroniques, Set-Top-Boxen etc. Toutefois, Java n’a toujours pas pu s’affirmer dans le domaine des applications temps réel (voir chapitre 1.6).

1.1.3 Lecture Programmation en Java, Fritz Jobst, HANSER-Verlag, ISBN 3-446-22061-5 Go To Java 2, Guido Krüger, Addison-Wesley, ISBN 3-8273-1370-8

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 2

1.1.4 Information disponibles sur le web Documentation originale de SUN: http://java.sun.com/docs http://java.sun.com/docs/books/tutorial Différents lien pour Java: http://www.javabuch.de (HTML-Version des Buches „Go To Java 2“) http://java.seite.net/ (die deutsche Java-Seite) http://www.java.de (Java User Group Deutschland) http://www.javamagazin.com (Web-Seite der Zeitschrift Java-Magazin) http://www.javaworld.com (Web-Seite der Zeitschrift Java World) http://javareport.com (Web-Seite der Zeitschrift Java Report)

1.2 Un premier exemple Un premier exemple pour démontrer la simplicité du code Java : /**

* First example of java code

*

* @author (FUE1)

* @version (1.0 17.11.03)

*/

public class Ex01

{

/**

* Principal program main()

* @The parameter args[0] contains the number of students

*/

public static void main(String args[])

{

int nbrStudents;

System.out.println("Hello"); // Displays "Hello"

if(args.length > 0) // Contains the program arguments

{ // yes --> define the number of students

nbrStudents = Integer.parseInt(args[0]);

System.out.println("The class contains " + nbrStudents + " students(s)");

}

System.exit(0); // end the program

}

}

Le code source Java ne se distingue guère d’un programme C/C++. Les remarques suivantes ont un caractère introductif. Ils seront traités plus en détail dans les chapitres suivants : • Un programme Java est composé de plusieurs classes. • Chaque classe devrait être définie dans un fichier séparé. • Les commentaire sont définis à l’aide de « /* */ » ou « / / ». • Les instructions sont définies à l’aide de point-virgule. • Chaque programme (à l’exception des applets) doit contenir la méthode principale

« public static void main (args[]) ». • System.out.println() permet d’afficher un texte sur la sortie standard. Les chaînes de caractères peuvent

enchaînées à l’aide de « + ».

• System.exit() termine le programme.

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 3

1.3 Développement de programme en Java SUN met à disposition gratuitement sur son site (www.java.sun.com) le JDK (Java Development Kit), qui contient les outils suivants : javac : Java-Compiler, traduit le code source en code byte java : exécute une application indépendante (stand alone) applet viewer : exécute un applet javadoc : génère une documentation à partir du code source Tous ces outils doivent être démarrés à l’aide de lignes de commande. Par conséquent, on utilise souvent des environnement de développement intégré (en anglais Integrated Development Environment et abrégé IDE), qui sont basés sur le JDK et qui rassemblent tous les outils JDK dans un éditeur de texte et un débuggeur. Exemple : JCreator, JBuilder, BlueJ etc.

1.3.1 Editeur de texte Tous les éditeurs de texte sans instructions formatées peuvent être utilisé pour éditer le code source. Toutefois, on utilise souvent des éditeurs qui mettent en évidence à l’aide de couleurs les structures du langage, les commentaires etc.

1.3.2 Compilateur Le compilateur Java traduit le code source dans le code byte, qui peut être exécuté sur toutes les plateformes. Le code source est contrôlé pendant la compilation. Le code byte ne peut être généré, que s’il n’y a pas d’erreurs dans le code source. Les fichiers contenant le code source ont une terminaison « .java » et les fichiers contenant le code byte ont une terminaison « .class ». Instruction pour démarrer le compilateur avec la ligne de commande : javac <filename>.java

Le compilateur génère ainsi le fichier suivant : <filename>.class

1.3.3 Interpréteur La machine virtuelle (en anglais Virtual Machine et abrégé par VM) interprète et exécute le code byte intermédiaire. L’instruction « java » permet de démarrer la VM. Instruction pour démarrer la machine virtuelle avec la ligne de commande : java <filename>

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 4

1.3.4 Vue d’ensemble Le développement et l’exécution d’un programme Java s’effectuent schématiquement de la manière suivante :

Code source Java

Compilateur Java

Editeur <nomfichier>.java

< nomfichier >.class

Browser avec VM intégré

Code byte Java

Système d’opération avec VM

Chip VLSI avec VM

Hardware (Ordinateur en réseau, console de jeux, téléphone mobile,

ustensile de ménage etc.)

Figure 1: Développement et exécution d’un programme Java

1.4 Les applications Les applications Java sont des applications indépendantes et correspondent aux programmes standard, définis avec des autres langages de programmation. Les applications Java nécessitent toutefois un interpréteur. Certaines applications Java sont traduites avec un compilateur « juste à temps » (en anglais Just in Time). Le code généré ainsi est plus rapide qu’un code interprété, mais n’est plus indépendant par rapport aux plateformes. Le chapitre 1.2 contient un exemple d’application.

1.5 Les applets Les applets peuvent être insérés dans les pages HTML et exécutés avec un explorateur Internet compatible Java. Les applet sont des éléments actifs et tournent sur l’ordinateur de l’utilisateur en utilisant ses ressources. Ils contiennent des éléments graphiques et se voient attribuer une surface par l’explorateur. Les applets peuvent également être exécutés à l’aide d’un « visualiseur d’applet » (en anglais Applet-Viewer). Le code suivant montre un applet, qui affiche le texte « I like Java » dans un cercle rouge : import java.applet.Applet;

import java.awt.Graphics;

import java.awt.*;

/**

* Class ExApplet - A simple applet

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 5

*

* @author FUE1

* @version 17.11.2003

*/

public class ExApplet extends Applet

{

// instance variables

private final String msg = "I like Java";

private Font font;

/**

* Called by the browser or applet viewer to inform this Applet that it

* has been loaded into the system. It is always called before the start

* method is called for the first time.

*/

public void init()

{

font = new Font("Helvetica", Font.BOLD, 32);

}

/**

* Returns information about this applet.

* @return a String representation of information about this Applet

*/

public String getAppletInfo()

{

// provide information about the applet

return "Title: First Applet \nAuthor: WBR1 \nA simple hello-applet ";

}

/**

* Draw the applet whenever necessary

* @param g Reference to graphics system

*/

public void paint(Graphics g)

{

// draw red Circle

g.setColor(Color.red);

g.fillOval(10,10,300,300);

// set text

g.setColor(Color.black);

g.setFont(font);

g.drawString(msg,90,170);

}

}

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 6

L’applet peut être inséré dans une page HTML de la manière suivante : <html>

<head>

<title>BspApplet Applet</title>

</head>

<body>

<h1>BspApplet Applet</h1>

<hr>

<applet code="BspApplet.class" width=320 height=320

</applet>

<hr>

</body>

</html>

Le démarrage de la page HTML dans l’explorateur Internet se traduit par l’affichage suivant :

Figure 2 : Notre applet

Introduction à la programmation Java Introduction

Version 1.0, 05.03.07 Page 7

1.6 Avantages et désavantage du Java Comme beaucoup de chose de la vie, Java ne possède pas que des avantages. Par conséquent, ce chapitre énumère les avantages et les désavantages du langage de programmation. Avantages • Java est indépendant par rapport à la plateforme. Le même code peut fonctionner sur des plateformes

différentes sans qu’il ne doive être compilé à nouveau. • Java contient beaucoup de fonctionnalité, qui sont définies dans le cadre du langage de programmation

(GUI, connexion Internet etc.). Dans les autres langages de programmation, ces fonctionnalités sont définies dans des bibliothèques, qui ne sont pas toujours standardisées.

• Il existe beaucoup d’environnements de développement bon marchés pour Java. • Java est un langage qui s’apprend facilement (en tous cas beaucoup plus simplement que C++) • Certain prétendent que la productivité du développement en Java et meilleur que celle en C/C++ (Pas de

problématiques liées aux pointeurs, gestion de mémoire facilitée, et test d’exécution etc.). Désavantages • Le collecteur d’ordure (Garbage Collection) a pour tâche de libérer l’espace mémoire qui n’est plus utilisé.

Le code devient ainsi non déterministique, car le collecteur d’ordure, qui possède une grande priorité, peut être appelé à tout moment. Cela ne constitue pas un problème dans le domaine de la programmation des ordinateurs personnels. Par contre cela peut être catastrophique pour les applications temps réels. En d’autres thermes, Java n’est pas recommandé pour les applications temps réels.

• Java est un langage interprété. Un interpréteur exécute le code toujours plus lentement qu’un programme en code machine. Les programme Java sont donc toujours plus lent que les programmes C/C++. Les compilateurs « juste à temps » permettent de résoudre ce problème, en générant un code objet.

• Java ne permet pas l’accès direct au hardware. Remarque finale Java est un langage de programmation moderne et puissant, qui possède des atouts dans le domaine de l’Internet. Toutefois, java est relativement peu utilisé dans le domaine du temps réel. La VM fonctionne souvent comme une tâche (anglais Task) sur un système d’opération temps réel. Les connexions Internet et les interfaces graphiques sont souvent programmées en Java. Toutes les autres fonctionnalités, qui sont critiques en temps, sont programmé en C/C++ et fonctionnent sous forme d’autres tâches, dont les priorités sont supérieures.

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 8

2 Aspect procédural de la programmation Java

2.1 Introduction Java est un langage de programmation orienté objet. Toutefois, avant de commence avec la programmation orienté objet, nous allons nous occuper des éléments procéduraux du langage de programmation Java (type de données, structure de contrôle et les méthodes). Ces éléments sont très semblables à ceux du langage de programmation C/C++. Le but de ce chapitre est de dresser la liste de ces éléments et de montrer les éventuelles différences avec le langage de programmation C/C++. Il est admis ici que le lecteur possède déjà une certaine connaissance du langage de programmation C.

2.2 Les éléments lexicographiques

2.2.1 Jeu de caractères Java est un langage de programmation, qui est utilisé dans le monde entier. Pour cette raison, il utilise le jeu de caractères Unicode. Ce jeu de caractère contient des nombreux caractères internationaux. Un caractère Unicode est codé sur deux bytes. Les 128 premiers caractères sont identiques à ceux du code ASCII. De plus, les 256 premiers caractères sont compatibles avec le jeu de caractères ISO-8859-1. Un programme Java est composé essentiellement de caractères Unicode. Il est ainsi possible d’utiliser des caractères spéciaux (comme par exemples é à è û etc.) pour constituer les noms symboliques.

2.2.2 Indicateur Les indicateurs (identifier) sont des noms de variables, de méthodes, de classes et d’objets etc. Les caractères suivants sont autorisés pour constituer un indicateur : • Les majuscules et les minuscules (c. à d. qu’il existe une distinction entre les majuscules et les minuscules!) • Les chiffres (0, 1, 2, 3, 4, 5, 6, 7, 8, 9). L’identificateur ne peut toutefois pas commencer avec un chiffre • Le caractère de soulignement „_“ • Le caractère dollars „$“ • Tous les caractères Unicodes en dessus de 00C0 Exemples d’identificateurs autorisés : JavaTools

Java_Tools

Java_3

Exemples d’identificateurs non autorisés : Java-Tools

Java/Tools

3_Java

2.2.3 Les commentaires Un bon code Java se distingue entre autre par la qualité des ces commentaires. Les commentaires simplifient la recherche des erreurs et l’entretient du programme. Les nouveaux collaborateurs s’initient plus rapidement au code. Java met à disposition 3 sortes de commentaires • Les commentaires en ligne • Les commentaires en bloque • Les commentaires de documentation

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 9

2.2.3.1 Les commentaires en ligne Les commentaires en ligne permettent d’ajouter des remarques courtes au code. Ils permettent la définition d’un commentaire jusqu’à la fin de la ligne. Les commentaire en ligne sont introduit avec « // » et terminent à la fin de la ligne. Ce commentaire correspond à celui du C++. Exemple : // This is a ligne comment int loop = 0; // This is also a ligne comment

2.2.3.2 Les commentaire en bloque Avec les commentaires en bloque, il est possible de commenter plusieurs lignes. Le commentaire de bloque est enfermé entre les suites de caractères « /* » et « */ ». Mis à part *, tous les caractères sont admis après /* (voir commentaire de documentation). Exemple : /* This is a bloc comment */

2.2.3.3 Les commentaires de documentation Les commentaires de documentation sont utilisés pour la génération de documentation automatique avec java doc. Le commentaire de documentation est enfermé entre les suites de caractères « /** » et « */ ». javadoc recherche la suite de caractère /** dans le code source afin de genèrer une documentation en foramt HTML. Exemple: /** * Comment for the method * @param p1 description of the first parameter */ public static void myFunc(int p1)

{

}

2.2.4 Les séquences d’échappement Pour les caractères, qui ne peuvent pas être représentés, il existe les séquences d’échappement. C à d. que des combinaisons spéciales de caractères sont mises à disposition pour représenter ces caractères. Ces dernières commencent toujours avec « \ ».

Séquence d’échappement

Description Séquence d’échappement

Description

\b Backspace \‘ ‘ \n Linefeed \“ “ \r Carriage Return \u Caractère Unicode \t Tabulateur horizontal \x Caractère hexadécimal \f Formfeed \oo Caractère octal \\ \

Tableau 1 : Séquence d’échappement

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 10

2.3 Les mots clés Java contient des mots clés, qui ne devraient pas être utilisés comme identificateur. Ces mots clés sont les suivants : Abstract double interface switch Assert else long synchronized Boolean extends native this Break final new throw Byte finally package throws Case float private transient Catch for protected try Char goto public void class if return volatile Const implements short while Continue import static Default instanceof strictfp Do int Super

Tableau 2 : Les mots clés de Java

En plus il existe les constantes littérales true et false pour les valeurs du type booléen ainsi que la constante littérale null pour les références sur nulle part.

2.4 Les variables et le type de données élémentaires Les variables servent pour stocker des données. Elles sont toujours typées, c. à d. que le type de la donnée à stocker doit être défini à l’avance. Le type défini la taille de l’espace mémoire nécessaire au stockage de la variable. Les variables sont adressées à l’aide de leur identificateur. Java connaît 3 sortes de variables: • Variable locale : Ces variables sont définies dans une méthode ou dans un bloque et existent uniquement

jusqu’à la fin du bloque, qui contient leur définition. • Variable de classe : Ces variables sont définies dans une classe et existent indépendamment de l’objet, c. à

d. durant tout le déroulement du programme (voir chapitre Introduction à la POO avec Java). • Variable d’objet : Ces variables sont également définies dans une classe. Elles sont créées lorsque qu’une

instance de la classe est créée et existent durant l’existence de cet objet (voir chapitre Introduction à la POO avec Java).

2.4.1 Déclaration et initialisation de variable Les variables sont déclarées de la manière suivante : <type> <ident>;

Dans la syntaxe de ci dessus <type> correspond au type de la variable. Cela peut être un type élémentaire ou une classe (voir chapitre 2.4.2). <ident> représente l’identificateur de la variable. Une variable peut être initialisé pendant la déclaration ou plus tard : // Initialisation durung the declaration

int a = 1234;

// Initialisation after the declaration

int a;

a = 1234;

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 11

Contrairement à ANSI C, les variables peuvent être définie à n’importe quel endroit dans une méthode ou dans un bloque (c. à d. qu’elles ne doivent pas obligatoirement être déclarée au début de la méthode ou du bloque).

2.4.2 Type de donnée élémentaire Java distingue entre les types de données élémentaires et composés. Les types de données élémentaires (appelé également simples ou primitifs) sont les nombres, les caractères ou les valeurs de vérité. Les types de données composés sont les chaînes de caractères, les tableaux et les tableaux. Des types de données différents nécessitent des bloques de mémoire différents. Ces types ressemblent à ceux du C/C++, mais il existe des différences importantes : • La mémoire nécessaire au stockage des types de données élémentaires est définie indépendamment de la

plateforme par Java. Les problèmes concernant la grandeur du type, qui dépend de la plateforme, comme en C, n’existent pas en Java.

• Toutes les valeurs numériques sont signées. Les types de données non signés (unsigned) n’existent pas. • Tous les changements de type ne sont pas possibles, comme en C.

2.4.2.1 Les nombres entiers Les nombres entiers sont précis et stockés de façon binaire en interne. Java contient les types de donnée entiers et signés suivant : Type Taille in bit Domaine Exemple Byte 8 -128 bis 127 byte b = 63; Short 16 -32768 bis 32767 short s = -4253; Int 32 -2'147'483'648 bis +2'147’483’647 int i = 523413241; Long 64 -9'223’372'036'854'775'808 bis

+9'223’372'036'854'775'807 long l = -1234242L;

Tableau 3 : Nombre entier

Remarque concernant le type long: L’adjonction L ou l précise, qu’il s’agit d’un format long. Les valeurs des nombres entiers peuvent être attribuées en décimal, hexadécimal ou en octal : décimal: les valeurs sont attribuées normalement, Ex. : int i = 123; hexadécimal: les valeurs commencent avec "0x", Ex. : int i = 0x234; octal: les valeurs commencent avec "0", Ex. : int i = 0123; Ils existent des classes de wrapper pour tous les types de données élémentaires (voir chapitre POO). Ces classes mettent à disposition les constantes MIN_VALUE et MAX_VALUE, qui spécifient les domaines de validité des différents types. Ces classes possèdent le même nom que les types de données, mais leurs noms commencent cependant avec une majuscule. Pour les entier ils existent les classes : Byte, Short, Integer et Long. Exemple: byte minByte = Byte.MIN_VALUE;

long maxLong = Long.MAX_VALUE;

Les classes de wrapper fournissent également des méthodes pour l’affichage des valeurs (transformation de la valeur entière en chaîne de caractères). Ces méthodes sont les suivants : toString(n) Transformation avec un système numérique décimal toBinaryString(n) Transformation avec un système numérique binaire toHexString(n) Transformation avec un système numérique hexadécimal toOctalString(n) Transformation avec un système numérique octal

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 12

Exemple : int i = 127;

System.out.println("Hexadecimal value: " + Integer.toHexString(i));

Affichage : Hexadécimal value: 7F

2.4.2.2 Les nombres à virgule flottante Les nombres à virgule flottante (ou les nombres réelle) sont stockés selon le format standard IEEE 754. Les nombres à virgule flottante sont sujets aux erreurs de représentation. Plus spécifiquement, des erreurs d’arrondi peuvent apparaître. Les types de données suivants sont à disposition pour les nombres à virgule flottante. Type Grandeur en bit Domaine Exemple float 32 +/- 1,4*E-45 bis 3,4*E38

Précision: 6 chiffres décimaux float fl = 123.0f; float f2 = 1.23E2f;

double 64 +/- 4,9*E-324 bis 1,7*E308

Précision: 15 chiffres décimaux double d1 = 1.4E2; double d2 = 1.0d;

Tableau 4 : Les nombres à virgule flottante

Remarque : les nombres à virgule flottant doivent toujours être représentés avec un point devant la partie fractionnaire. L’adjonction de f ou F avec le type float est obligatoire, alors que l’adjonction de d ou D avec le type double est facultative. Les nombres sans adjonction seront interprétés comme double. Ils existent également des classes de wrapper pour les nombres à virgule flottante (Float et Double), qui spécifient également le domaine de validité de ces types (MIN_VALUE et MAX_VALUE).

2.4.2.3 Les caractères En Java les caractères sont représentés à l’aide du Unicode (voir chapitre 2.2.1). Type Taille en bit Domaine Exemple char 16 Tous les caractères char c = 'a';

Tableau 5 : Les caractères

Important : Le type char correspond à 8 bit dans le langage de programmation C, alors qu’en Java il correspond à 16 bits !

2.4.2.4 Les nombres booléens Le type booléen est nécessaire pour les comparaisons. Les nombres booléen possèdent les valeurs true ou false. Par conséquent, ce ne sont pas des nombres. Par ailleurs, le type booléen ne peut pas être changé dans un autre type de données. Type Taille en bit Domaine Exemple boolean 8 true ou false boolean isReady = true;

Tableau 6 : Type booléen

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 13

Important: Dans le langage de programmation C, false est équivalent à une valeur zéro et true à une valeur différente de zéro. Cela n’est pas le cas en Java ! Les conditions comme « if » (voire chapitre 2.9.2) nécessitent une valeur booléenne. « if (1) » est correct en C mais faux en Java.

2.4.3 Les changements de type de données Les changements de type de données (appelé également casting) permettent de changer un type de données dans un autre type de données. Syntaxe: <Variable-Destination> = (Type de la Variable-Destination) <Variable-Source> Exemple : int i1, i2;

float f1

f1 = (float)i1 / (float)i2;

Ils existent deux sortes de changements de type de données : - Casting explicite : Le changement de type est défini explicitement par le programmeur. - Casting implicite : Le changement du type est exécuté implicitement par le compilateur. Les changements de type de données peuvent mener à des effets de bord, qui ne sont pas souhaités, comme dans l’exemple suivant : byte b1;

short s1;

b1 = (byte) s1; // Datenverlust des High-Byte, auf Risiko des Programmierers

Le tableau suivant contient une vue d’ensemble de tous les changements de type de données possibles. Le tableau peut être interprété de la manière suivante : Type de la partie de gauche = (cast nécessaire?) Type de la partie de droite Type de la partie de gauche

Type de la partie de droite

byte short int Long float double boolean char Byte � cast cast Cast cast cast � cast Short � � cast Cast cast cast � cast

int � � � Cast cast cast � � long � � � � cast cast � � float � � � � � cast � �

double � � � � � � � � boolean � � � � � � � �

char cast cast cast Cast cast cast � �

Tableau 7 : Changement de type de données

� : opérateur de casting n’est pas nécessaire, attribution possible sans perte de donnée cast : opérateur de cast est nécessaire, possibilité de perdre des données � : opération de casting n’est pas possible en Java

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 14

2.4.4 La visibilité Les variables sont visibles dans un bloque (domaine entre « {} »), plus précisément depuis leur définition jusqu’à la fin du bloque. Elles sont également visibles dans les sous bloque, de ce bloque. Exemple: public static void main(String args[])

{

int a = 1; // a is only visible

{

int b = 2; // a and b are visible

{

int c = 3; // a, b and c are visible

}

// c in no more visible

}

// b in no more visible

}

2.4.5 Les variables globales Les variables ne peuvent être définies qu’aux niveaux des méthodes et des classes (voir POO). Java ne connaît pas de variables globales dans les sens de C. En échange, Java met à disposition les variables statiques de classe. L’accès à ces derniers se fait indépendamment de toute instanciation d'objet. Exemple : public class Global

{

static int myGlobal; // global class variable

public static void main(String args[])

{

myGlobal = 7;

}

}

2.5 Les chaînes de caractères Un string est un tableau de caractères (Unicode) et est utilisé pour stocker du texte. Les chaînes de caractères en Java ne sont plus des types de données élémentaires mais des objets de classe String. Du fait que les strings sont également nécessaires pour la programmation procédurale, le chapitre POO est un peu devancé à cet endroit. Java soutient deux classes pour le stockage des chaînes de caractères : String pour les chaînes de caractères constantes et StringBuffer pour la création de chaîne de caractères.

2.5.1 String Un objet String peut être défini de la manière suivante : String student1 = "Hans";

String student2 = new String("Thomas");

Les méthodes, les plus importantes, qui peuvent être appliquées sur un objet String sont les suivantes : int compareTo(String b): Compare deux String. a.compareTo(b) fournit :

<0 si a est plus petit que b

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 15

= 0 si les deux String sont égaux. <0 si a est plus grand que b

boolean equals(String b): Compare deux String. a.equals(b) fournit true, si a et b sont égaux

int length(): Fournit la longueur du String. a.length(); Les autres méthodes sont décrites sous « java.lang.String ». Un String peut être copier dans un autre String avec l’opérateur « = » (ce qui n’était pas possible dans C !). L’opérateur « + » permet d’enchaîner des String (par exemple pour des affichages). Exemple: public class StringTest

{

public static void main(String args[])

{

String student_1 = "John";

String student_2 = new String("Tom");

String student_3 = student_1;

System.out.println(student_1 + " " + student_2 + " " + student_3);

}

}

2.5.2 StringBuffer La classe StringBuffer est mise à disposition pour la construction complexe de chaînes de caractères. Cette classe contient des méthodes pour insérer ou ajouter des chaînes de caractères. Les méthodes, les plus importantes, qui peuvent être appliquées sur un objet StringBuffer sont les suivantes : StringBuffer append(Type b): Ajoute une chaîne de caractères ou un type de données élémentaire

à la fin du tampon (buffer) existant. StringBuffer insert( int offset, Type b):

Insère une chaîne de caractères ou un type de données élémentaires à la position offset dans le tampon existant.

int length(): Fournit la longueur du StringBuffer. a.length(); Un objet du type StringBuffer est créé à sa définition avec une longueur de 16 caractères. Cette longueur sera agrandie dynamiquement en cas de nécessité. Exemple: public class StringBufferTest

{

public static void main(String args[])

{

int i = 7;

StringBuffer buffer = new StringBuffer();

buffer.append("John ");

buffer.append("Kennedy");

buffer.insert(3, i);

System.out.println("Contains of the buffer: " + buffer);

System.out.println("Length of the buffer: " + buffer.length());

}

}

Affichage du programme: Contains of the buffer: Joh7n Kennedy

Length of the buffer: 13

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 16

2.6 Les tableaux

2.6.1 Les tableaux unidimensionnels Les notions d’array, de tableau et de vecteur sont synonymes. Les tableaux servent à stocker des variables qui ont le même type. Un élément est une cases du tableau et est accessible à l’aide de son indexe (ex. myArray[2]). Le premier élément possède l’indexe 0. Les tableau doivent toujours être déclarés, alloués et initialisées :

2.6.1.1 Déclaration du tableau Le premier pas est la création d’une variable de référence pour adresser le tableau. Syntaxe: <Array type> <Array name> [];

Ou: <Array type> [] <Array name>;

Exemple : int intArray[];

boolean boolArray[];

Important: Les tableaux sont toujours gérés à l’aide de leur référence. Toutefois, la création de la variable de référence n’alloue pas l’espace mémoire nécessaire au stockage des éléments du tableau.

2.6.1.2 Allocation du tableau Le bloque de mémoire nécessaire au stockage des éléments du tableau est créé durant cette étape. Le nombre d’élément n’est donc défini que durant l’exécution du programme, mais ce nombre ne peut plus être changé après l’allocation. Les éléments sont initialisés durant l’allocation avec la valeur défaut (0). La taille de l’array est fournit par la méthode lenght(), qui retourne son nombre d’éléments. Syntaxe: <Array name> = new <Array type>[<number of elements>];

Exemple : intArray = new int [5]; // allocate memory for 5 elements of type int,

// intArray is the reference, which address the array

boolArray = new boolean [10]; // allocate memory for 10 elements of type boolean

Important : Les tableaux sont générés dynamiquement avec l’opérateur « new » durant l’exécution du programme. Ils sont éliminés automatiquement par le collecteur d’ordure (Garbage Collection) à la fin du programme. Dans C/C++, les programmeurs sont eux même responsables de la libération de l’espace mémoire alloué aux différents objets. Dans Java, c’est le collecteur d’ordure qui reprend cette tâche. Il faut donc être très prudent, lorsqu’on s’est habitué à Java et que l’on passe à la programmation en C/C++ ! La déclaration et l’allocation de tableau peuvent être effectuées en une seule étape. Syntaxe: <Array type> <Array name> [] = new <Array type>[<number of elements>];

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 17

2.6.1.3 Initialisation du tableau Les éléments du tableau doivent être initialisés durant la dernière étape, si ces derniers doivent contenir une valeur différente de 0. Cela est réalisé par attribution d’une valeur à chaque élément du tableau de la manière suivante : intArray[i] = wert;

Un tableau peut cependant être initialisé durant sa déclaration, comme cela est également le cas en C. La déclaration, l’allocation et l’initialisation du tableau s’effectuent alors simultanément : Syntaxe: <Array type> <Array name> [] = {<value1>, <value2>, ..... , <valueN>};

Exemple : int intArray [] = {1,2,3,4,5}; // allocate memory for 5 int elements and initialize them

Les valeurs attribuées peuvent également résulter d’un calcul, pourvu que ces dernières soient connues durant l’attribution. Exemple : public class OneDimArray

{

public static void main(String args[])

{

int intArray[]; // Declaration

intArray = new int[2]; // Allocation

intArray[0] = 12; // Initialization

intArray[1] = 17;

boolean boolArray[] = {true, false}; // Declaration, Allocation & Initialization

System.out.println("intArray[]: " + intArray[0] + " " + intArray[1]);

System.out.println("boolArray[]: " + boolArray[0] + " " + boolArray[1]);

}

}

2.6.1.4 Les erreurs d’indexages Les erreurs d’indexage sont les erreurs qui apparaissent le plus souvent en C/C++ (dépassement de limites) durant l’accès aux éléments d’un tableau. Cette erreur engendre la sur écriture des données, qui se situent dans les environs du tableau dans la mémoire. Ces erreurs sont très difficiles à trouver, car les problèmes qu’ils engendrent ne se situent pas en générale à l’endroit ou le code est en train d’être exécuté, mais à un tout autre endroit. En Java les erreurs d’indexage génèrent une exception du type : « ArrayIndexOutOfBoundsException » Exemple : public class ArrayException

{

public static void main(String args[])

{

int intArray[]; // Declaration

intArray = new int[2]; // Allocation

intArray[0] = 12; // Initialization

intArray[1] = 17;

System.out.println("intArray[2]: " + intArray[2]);

}

}

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 18

Dans la dernière instruction de cet exemple, un accès au 3ème éléments du tableau qui n’existe pas a lieu. Par conséquent, le programme générera durant son exécution à cet endroit l’exception suivante : ArrayIndexOutOfBoundsException: 2

2.6.2 Les tableaux multidimensionnelles Java contient également les tableaux multidimensionnels. Ces derniers doivent être déclarés, alloués et initialisés, comme ce fut le cas avec les tableaux unidimensionnelles. Syntaxe pour les tableaux à deux dimensions : <Array type> <Array name> [][];

<Array name> = new <Array type>[<number of rows>] [<number of columns>];

Ou : <Array type> <Array name> [][] = new <Array type>[<number of rows>] [<number of columns>];

Accès aux différents éléments s’effectue de la manière suivante : <Array name> [row][column] = <value>;

Ici la déclaration, l’allocation et l’initialisation peuvent également être effectuées en une seule étape : <Array type> <Array name> [] [] = {

{<value11>, <value12>,.... ,<value1N>},

{<value21>, <value22>,.... ,<value2N>}

};

Exemple : public class TwoDimdArray

{

public static void main(String args[])

{

int array1[][] = {{1,2,3},{10,11,12},{20,21,22}};

int array2[][] = {{100,101,102},{110,111,112},{120,121,122}};

int array3[][] = new int[3][3];

// Addition of the matrix array1 and array2, result into array3

for(int i = 0; i < 3; i++)

{

for(int j = 0; j < 3; j++)

{

array3[i][j] = array1[i][j] + array2[i][j];

System.out.print(array3[i][j] + " ");

}

System.out.println("");

}

}

}

2.7 Les constantes Les constantes sont formées dans Java avec le mot clé final. final permet de définir et d’initialiser une variable, qui ne peut plus être changée durant toute l’exécution du programme. Exemple : final float PI = 3.1415f;

Les constantes suivantes peuvent être formées : • Les constantes entières, ex. : final int i = 1234; final long l = 1234L;

• Les constantes à virgule flottante, ex. : final float f = 1.23f; final double d = 1.23d; • Les constantes sous forme de caractère, ex. : final char c = 'a';

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 19

• Les constantes sous forme de chaîne de caractères, ex. : final String str = "Hello"; Important : L’instruction pour le preprocesseur #define, qui est supportée par C, ne peut pas être utilisée en Java.

2.8 Les opérateurs Dans Java comme en C/C++, une expression est l’unité minimale, qui peut être interprétés. Une expression contient une ou plusieurs opérandes et au moins un opérateur, qui exécute un fonction sur les opérandes. Les opérateurs unaires nécessitent un seul opérande, alors que les opérateurs binaires en nécessitent deux. Une expression retourne toujours un résultat, dont le type dépend de l’opérateur et des opérandes. Lorsqu’une expression contient plusieurs opérateurs, la priorité de ces derniers devient déterminante. La priorité et l’associativité entre les opérateurs de priorité identique sont également définies dans Java : Priorité (précédence)

Opérateur Complément Associativité

1 (le plus haut) [] . (params) expr++ expr-- ++,-- postfix Gauche à droite

2 ++expr --expr +expr -expr ~ ! unair Droite à gauche

3 new (type)expr Cast

4 * / % Gauche à droite

5 + - binaire Gauche à droite

6 << >> >>> Gauche à droite

7 < > <= >= instanceof Gauche à droite

8 == != Gauche à droite

9 & Gauche à droite 10 ^ Gauche à droite 11 | Gauche à droite 12 && Gauche à droite

13 || Gauche à droite 14 ?: Droite à gauche

15 (le plus bas) = += -= *= /= %= &= ^= |= <<= >>= >>>=

Droite à gauche

Tableau 8 : Les opérateurs Java triés selon leur priorité

2.8.1 Les opérateurs arithmétiques Les opérateurs arithmétiques nécessitent des opérandes numériques (en générale un opérateur de chaque côté de l’opérateur). Le type du résultat correspond toujours au type de l’opérande, qui est le plus grand (par exemple : une addition entre des opérande de types int et long fournit un résultat de type long). Opérateur Désignation Description - op1 Signe négatif Changement de signe op1 + op2 Addition Somme de op1 et op2 op1 – op2 Soustraction Différence entre op1 et op2 op1 * op2 Multiplication Produit entre op1 et op2 op1 / op2 Division Quotient entre op1 et op2 op1 % op2 Modulo Reste de la division entière op1++ Post-incrément Incrémenter op1 après exécution de l’instruction ++op1 Pre-increment Incrémenter op1 avant exécution de instruction op1-- Post-décrément Décrémenter op1 après exécution de instruction --op1 Pre-dekcement Décrémenter op1 avant exécution de instruction

Tableau 9 : Les opérateurs arithmétiques

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 20

Les opérateurs arithmétiques sont exécutés de gauche à droite en fonction des règles de priorité définies au chapitre 2.8. Des parenthèses devraient être insérées en cas de doutes. Les parenthèses facilitent également la compréhension du code. L’écriture des opérateurs arithmétiques, qui sont combinés aux opérateurs d’affectation, peut être simplifiée (voir chapitre 2.8.5).

2.8.2 Les opérateurs de comparaison Les opérateurs de comparaison (appelé également opérateur relationnel) comparent deux opérandes numériques ou deus expressions. Ils fournissent un résultat de type booléen. Opérateur Désignation Description op1 = = op2 Egalité Fournit true lorsque op1 est égal à op2. op1 != op2 Inégalité Fournit true lorsque op1 n’est pas égal à op2. op1 < op2 Plus petit Fournit true lorsque op1 est plus petit que op2. op1 <= op2 Plus petit ou égale Fournit true lorsque op1 est plus petit ou égal à op2. op1 > op2 Plus grand Fournit true lorsque op1 est plus grand que op2. op1 >= op2 Plus grand ou égale Fournit true lorsque op1 est plus grand ou égal à op2.

Tableau 10 : Les opérateurs de comparaison

2.8.3 Les opérateurs logiques Les opérateurs logiques permettent d’assembler des valeurs booléennes. Les opérandes et le résultat doivent absolument avoir le type booléen : Opérateur Correspondance Description !op1 NOT Fournit false lorsque op1 est true et inversement op1 && op2 AND Ne fournit true que lorsque op1 et op2 sont true op1 || op2 OR Fournit true lorsqu’au moins un opérateur est true

Tableau 11 : Les opérateurs logiques

Important: Avec l’opérateur « && », le résultat est false dès que l’opérateur de gauche l’est aussi. Dans ce cas la condition de droit n’est pas testée. Avec l’opérateur « || », le résultat est true dès que celui de gauche l’est aussi. Ici, la condition de droite n’est également pas testée.

2.8.4 Les opérateurs de traitement des bits Les opérateurs de traitement des bits réalisent des manipulations au niveau des bits. Ils sont souvent utilisés pour masquer des valeurs ou pour les déplacer de façon binaire. Les opérateurs doivent être entier. Opérateur Désignation Description ~op1 Complément à un Inverse tous les bits de l’opérande op1 & op2 AND Et binaire entre op1 et op2 op1 | op2 OR Ou binaire entre op1 et op2 op1 ^ op2 EXOR Ou exclusif binaire entre op1 et op2 op1 << op2 Déplacement vers la gauche op1 est déplacé de op2 bits vers la gauche.

Des bits « 0 » sont insérés depuis la droite. op1 >> op2 Déplacement vers la droite

avec bit de signe op1 est déplacé de op2 bits vers la droite. Des bits de signe sont insérés depuis la gauche.

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 21

op1 >>> op2 Déplacement vers la droite avec bit « 0 »

op1 est déplacé de op2 bits vers la droite. Des bits « 0 » sont insérés depuis la gauche.

Tableau 12 : Les opérateurs logiques binaires

Les opérateurs te traitement des bits ont été repris à partir du C/C++, le résultat de ces opérations correspondent également à ceux du C/C++. L’écriture des opérateurs te traitement des bits, qui sont combinés aux opérateurs d’affectation, peut être simplifiée (voir chapitre 2.8.5).

2.8.5 Les opérateurs d’affectation L’opérateur d’affectation attribue à l’opérateur de sa gauche la valeur de l’expression de sa droite. L’expression de droite est ainsi évaluée avant l’affectation. L’opérateur d’affectation peur être combiné avec des opérateurs arithmétiques, binaires et de traitement des bits, afin de simplifier l’écriture. Opérateur Désignation Description op1 = <expr> Affectation Attribue à op1 le résultat de l’expression de droite. op1 += op2 Affectation avec addition Attribue à op1 la somme de op1 + op2. op1 -= op2 Affectation avec soustraction Attribue à op1 la différence op1 - op2. op1 *= op2 Affectation avec multiplication Attribue à op1 le produit de op1 * op2. op1 /= op2 Affectation avec division Attribue à op1 le quotient de op1 / op2. op1 %= op2 Affectation avec modulo Attribue à op1 le reste de op1 % op2. op1 &= op2 Affectation avec AND binaire Attribue à op1 le résultat de l’opération binaire Et entre

op1 et op2. op1 |= op2 Affectation avec OR binaire Attribue à op1 le résultat de l’opération binaire Ou entre

op1 et op2. op1 ^= op2 Affectation avec EXOR binaire Attribue à op1 le résultat de l’opération binaire Ou

exclusif entre op1 et op2. op1 <<= op2 Affectation avec décalage vers

la gauche Déplace op1 de op2 bits contre la gauche et stocke le résultat dans op1.

op1 >>= op2 Affectation avec décalage vers la droite et dulcification du bit de signe

Déplace op1 de op2 bits contre la droite, en duplifiant le bit de signe, et stocke le résultat dans op1.

op1 >>>= op2 Affectation avec décalage vers la droite et dulcification du bit nul

Déplace op1 de op2 bits contre la droit, en duplifiant le bit nulle, et stocke le résultat dans op1.

Tableau 13 : Les opérateurs d’affectation

Remarque : Toutes les expressions du Tableau 13 retournent un résultat, qui est identique à celui attribué à op1. Exemple: int op1 = 5;

int op2 = 8;

int op3;

op3 = (op1 += op2);

Fournit le résultat suivant: op1 = op3 = 13

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 22

2.8.6 L’opérateur point d’interrogation L’opérateur point d’interrogation est l’unique opérateur qui nécessite 3 opérandes. Syntaxe: expr1 ? expr2 : expr3 expr1 est une expression logique. Lorsque expr1 est true, l’opérateur retourne la valeur de l’expression expr2. Par contre lorsque expr1 est false, ce dernier retourne la valeur de l’expression expr3. expr2 et expr3 peuvent être de type booléen, numériques ou référence. Exemple: boolean BigSalary = (Salary > 10000) ? true : false;

L’opérateur point d’exclamation n’est rein d'autre qu’une structure if-else (voir chapitre 2.9.2). Il est essentiellement utilisé lorsque des notations compactes sont souhaitées, afin d’améliorer la compréhension du code.

2.8.7 L’opérateur cast L’opérateur cast permet de changer le type d’une expression A dans celui de l’expression B. Le casting a déjà été traité dans le chapitre 2.4.3.

2.8.8 Les opérateurs supplémentaires pour la programmation OO Java contient des opérateurs destinés à la programmation orientée objet. Ces derniers seront décrits plus en détails dans la partie OO de cette documentation. Toutefois, ils sont introduits dans ce chapitre pour des raisons de complémentarités. Opérateur + pour enchaîner des chaînes de caractères Si un des deux opérandes de l’expression « a + b » est un String, alors le résultat de cette expression est un String composés. Par conséquent l’opérande, qui n’est pas un String avant l’enchaînement, sera changé en String. Les opérateurs = = et != pour les références Ces opérateurs contrôlent, si deux références adressent le même objet ou pas. Toutefois, il n’y a pas de contrôle en ce qui concerne le contenu des objets. L’opérateur instanceof L’opérateur instanceof permet de contrôler si un objet appartient à une classe ou pas. Ce contrôle peut être effectué soit pendant la traduction ou durant l’exécution du programme (les objets ont des informations supplémentaires durant exécution du programme (runtime information). L’opérateur new Les tableaux et les objets peuvent être créés avec l’opérateur new. L’opérateur new retourne une référence sur l’objet, qui vient d’être instancié. L’opérateur point L’opérateur point permet l’accès aux variables et aux méthodes de classe et d’objet.

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 23

2.9 Les structures de contrôle

2.9.1 Introduction Les structures de contrôle de Java sont identiques à celles de C/C++. Ces structures de contrôle permettent d’influence le déroulement du programme en fonction des conditions. Les sous chapitres suivants traitent brièvement ces structures de contrôle, à l’aide des structogrammes (Nassi-Shneidermann), des représentations graphiques du type Backus-Naur, des brèves descriptions et des exemples.

2.9.2 L’instruction if Syntaxe : if(<Expression>) {

<Instruction>;

}

else {

<Instruction>;

}

Structogramme :

Instruction_1 Instruction_2

Expression true false

Forme graphique Backus-Naur :

if ( Expression ) Statement else Statement

Description : if réalise une ramification du programme en fonction d’une condition. L’expression de la condition est évaluée au début de la structure. Lorsque cette dernière fournit true, le programme exécute les instructions du bloque if, dans ce cas contraire, il exécute les instructions du bloque else. Exemple: if(val < 0)

{

System.out.println("The value is negative");

}

else

{

System.out.println("The value is positive");

}

Remarque : • La branche else peut être omise. • Les accolades peuvent être omises, lorsque le bloque if ou else ne contient qu’une instruction.

• Les instructions if peuvent être emboîtées :

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 24

if(<Expression_1>)

{

if(<Expression_2>)

{

<Instruction>;

}

}

else

{

<Instruction>;

}

• Des séries de conditions peuvent également être testées : if(<Expression_1>)

<Instruction_1>;

else if(<Expression_2>)

<Instruction_2>;

else

<Default-Instruction>;

• Contrairement à C/C++, la condition doit retourner impérativement un résultat du type booléen : int value = Wert;

if(value) {} // Error in Java, but correct in C

if(value != 0) {} // correct

2.9.3 L’instruction switch Syntaxe: switch(<Expression>) {

case <Constant_expression_1>: <Instruction>;

break;

case <Constant_expression_2>: <Instruction>;

break;

...

default: <Instruction>;

}

Structogramme :

Instruction_1

Expression Const_1 Const_2

Instruction _2 ... Instruction

Default

Forme graphique de Backus-Naur :

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 25

switch ( Expression )

case

{ }

Expression :

default :

Statement

Description : switch réalise une ramification multiple en fonction d’une expression, qui est évaluée tout au début de l’instruction. Le résultat de cette évaluation est alors comparé avec les valeurs des étiquettes « case ». Lorsqu’il y a correspondance avec une de ces valeurs d’étiquette, toutes les instructions à partir de cette dernière sont alors exécutées. Par conséquent le bloque d’instructions associé à une étiquette doit toujours se terminer avec l’instruction break, afin d’empêcher l’exécution des instructions suivantes. Le bloque défaut est exécuté lorsque aucune valeur d’étiquette ne correspond à celle de l’expression, Exemple : int value;

...

switch(value)

{

case (1): System.out.println("Value one"); break;

case (2): System.out.println("Value two"); break;

...

default: System.out.println("Value default");

}

Remarque : • La partie défaut est en option. Le programme exécute aucune instruction, lorsqu’il n’y a pas de

correspondance entre la valeur d’une des étiquette et celle de l’expression. • Plusieurs cas à traiter peuvent être rassemblés dans un groupe de différentes étiquettes. Les instructions à

exécuter sont alors définies après la dernière étiquette. Le « Fall through » devrait être toujours commenté ! Exemple : case 'o': // Fall through

case 'O':

Sysetm.out.println("Caractère o ou O");

break;

• Le type de l’expression de switch et les types des constantes des étiquettes case doivent être entiers, comme par exemple byte, char, short ou int. Les comparaisons avec d’autres types ne sont pas possibles.

2.9.4 La boucle while Syntaxe : while(<Expression>) {

<Instruction>;

}

Structogramme :

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 26

Instruction

while (Expression)

Forme graphique de Backus-Naur :

while ( Expression ) Statement

Description: while est une boucle, où la condition est évaluée à son début. Lorsque cette dernière est true, le programme exécute les instructions du corps de la boucle. Il s’en suit une réévaluation de la condition. Le corps de la boucle while est ainsi exécuté jusqu’à ce que la condition de départ devienne false. Exemple: int i = 0;

while( i < 10)

{

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

i++;

}

L’instruction println() est exécutée 10 fois dans cet exemple (i = 0 jusqu’à et avec i = 9) Remarque : • Aucune instruction n’est exécutée, lorsque la condition est false dès le départ. • La condition à évaluer doit impérativement retourner un résultat du type booléen! • La valeur de la condition doit être modifiée impérativement dans la boucle. Si non la boucle devient infini. • Les boucles while peuvent être emboîtées. • Les accolades peuvent être omises, lorsqu’une seule instruction est contenue dans le corps de la boucle.

2.9.5 La boucle do while Syntaxe : do {

<Instruction>;

} while(<Expression>);

Structogramme:

while (Expression)

Instruction do

Forme graphique de Backus-Naur :

do ( Expression ) Statement while ;

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 27

Description: do-while est une boucle, où la condition est évaluée à sa fin. Le bloque contenant les instructions est exécuté une première fois. Ensuite le programme évalue la condition. Lorsque cette dernière est true, le programme exécute de nouveau les instructions du corps de la boucle. Il s’en suit une réévaluation de la condition. Le corps de la boucle do-while est ainsi exécuté jusqu’à ce que la condition à sa fin devienne false. Exemple: int i = 0;

do

{

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

i++;

} while( i < 10);

L’instruction println() est exécutée également 10 fois dans cet exemple (i = 0 jusqu’à et avec i = 9) Remarque : • En comparaison avec la boucle while, le bloque des instructions de la boucle do-while est toujours

exécuté au moins une fois. • La condition à évaluer doit impérativement retourner un résultat du type booléen ! • La valeur de la condition doit être modifiée impérativement dans la boucle. Si non la boucle devient infini. • Les boucles do-while peuvent être emboîtées. • Les accolades peuvent être omises, lorsqu’une seule instruction est contenue dans le corps de la boucle.

2.9.6 La boucle for Syntaxe : for(<Expression_1>; <Expression_2>; <Expression_2>) {

<Instruction>;

}

Structogramme :

Instruction

for (Expression_1; Expression_2; Expression_3)

Forme graphique de Backus-Naur :

for ( Expression

) Statement

; Expression ; Expression

Variable declaration

Description: La variable de boucle est initialisée tout au début à l’aide de l’expression « Expression_1 ». En Java il est également possible de définir cette variable à cet endroit. Il s’en suit l’évaluation de la condition fournie par l’expression « Expression_2 ». Lorsque cette dernière est true, le programme exécute les instructions du corps de la boucle et évalue ensuite l’expression « Expression_3 ». Normalement cette dernière est utilisée

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 28

pour incrémenter la variable de boucle. Le corps et les instructions d’itération de la boucle for sont ainsi exécutés jusqu’à ce que la condition dans Expression_2 devienne false. Exemple: for(int i = 0; i < 10; i += 2)

{

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

}

L’instruction println() est exécutée 5 fois dans cet exemple ( i = 0, 2, 4, 6 et 8) Remarque : • Lorsque la variable de boucle est déclarée en interne de la boucle, sa visibilité se limite à cette dernière • Les accolades peuvent être omises, lorsqu’une seule instruction est contenue dans le corps de la boucle. • La condition à évaluer doit impérativement retourner un résultat du type booléen ! • La boucle for peut être remplacée par une boucle while de la manière suivante :

<Expression_1>;

while(<Expression_2>)

{

<Instruction>;

< Expression_3>;

}

• Certaines expressions de la boucle for peuvent être omises (Expression_1; Expression_2; Expression_2). Toutefois les points-virgules doivent absolument rester. Exemple : for( ; i < 10; ) { } // i ist not initialised and not modified!

• Les boucles for peuvent être emboîtées.

2.9.7 Contrôle des boucles avec les instructions break et continue L’instruction break a été introduite ci-dessus avec les ramifications switch, pour terminer les étiquettes case. Dans ce cas break est vivement recommandé. break et continue sont des instructions, qui permettent d’influencer le déroulement des boucles. L’utilisation de ces instruction est considéré comme un très mauvais style de programmation (visibilité et entretient réduits). Cependant dans certain cas, l’application de ces instructions peut s’avérer très utile (par exemple pour réduire la profondeur d’un emboîtement). Mais, le code devrait être bien commenté dans ces cas.

2.9.7.1 L’instruction break L’instruction break permet de quitte une boucle, indépendamment de la condition d’arrêt de la boucle. Les instructions du corps de la boucle qui suivent break ne sont ainsi plus exécutées. Lorsque les boucles sont emboîtées l’une dans l’autre, seule la dernière boucle est quittée, réduisant ainsi l’emboîtement de 1. Théoriquement l’instruction break peut également mener à un label. Ce qui permet de quitter des boucles emboîtées l’une dans l’autre d’un seul coup et ce qui correspond à l’instruction goto du C. L’instruction break ne devrait être utilisé de manière réservée (en combinaison avec une instruction if). Exemple: int array[] = new int[10];

... // read the array

// search if the array contains the value 55:

for(int i = 0; i < array.length; i++) //

{

if(array[i] = = 55)

{

System.out.println("got it");

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 29

break; // the search operation ends here, if the value 55 has been found! }

System.out.println(array[i]);

}

2.9.7.2 L’instruction continue L’instruction continue permet de quitter le corps de la boucle, sans exécuter les instructions suivantes. Contrairement à l’instruction break, la boucle n’est pas quittée, mais le programme continue avec l’évaluation d’une nouvelle condition. Dans le cadre des boucles for, les variables de boucles qui sont modifiées avant l’évaluation de la condition. L’instruction continue devrait également être exécuté de manière réservée (combiné avec une instruction if). L’instruction continue permet aussi des sauts sur des labels. Ce qui permet de quitter les boucles emboîtées. Exemple: éviter la division par zéro int array[] = new int[10];

... // read the array

// Display the inverse of the element values :

for(int i = 0; i < array.length; i++) //

{

if(array[i] = = 0)

{

System.out.println("Element is 0 ");

continue; // the inverse of 0 should not be computed! }

System.out.println("Inverse of " + array[i] + "is: " + (1 / array[i]));

}

2.10 Les méthodes

2.10.1 Nom, Liste de paramètres et valeur de restitution Java contient fondamentalement des méthodes de classe et d’objet. Le chapitre 3 « Introduction à la POO avec Java » traitera ce sujet plus en détails. Ce chapitre ne traite que les méthodes (statique) de classe. En Java il est possible de programmer de façon purement procédurale avec les méthodes statiques. Les méthodes statiques du Java ont les mêmes propriétés que les fonctions de C. Toutefois, les méthodes appartiennent toujours à une classe et, par conséquent, elles ne peuvent pas être définies en dehors des classes. Le code, qui doit être exécuté plusieurs fois, peut être ainsi rassemblé dans une méthode. Ces méthodes peuvent être appelé depuis des autres méthodes et elles peuvent également s’appeler elle-même (récursion). Les méthodes procurent une structure claire et modulaire au programme. Le code devient ainsi plus facile à tester à modifier et à entretenir. Syntaxe pour la définition d’une méthode : modifier restitution_type method_name (parameter_list)

{

// Instructions of the method

}

Propriétés des méthodes • L’entête de la méthode définie son interface. Les méthodes appelantes doivent se tenir à cette interface. • Le modificateur (modifier) spécifie la visibilité de la méthode. Le mot clé « static » peur être ajouter à

cet endroit, pour indiquer que la méthode est statique. • Le type de restitution indique le type de la valeur qui sera retourné par la méthode. Cette valeur est fournie à

la fin de la méthode avec l’instruction « return ». La valeur de restitution est utilisée pour communiquer le résultat d’un calcul ou des message d’erreur. Le chapitre Exception Handling traitera des autres techniques de traitement d’erreurs. Une seule valeur peut être restituée au maximum. Le type de restitution « void » indique que la méthode ne retourne pas de paramètres. Les valeurs de restitution peuvent être des

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 30

données de type élémentaire, des tableaux et des objets créés à partir des classes. Les données de type élémentaire sont retournées « by value » alors que les tableaux et les objets sont retournés « by reference ».

• Le nom de la méthode sert à son identification. Le nom symbolique de la méthode doit respecter les règles qui régissent la composition des identificateurs introduites au chapitre 2.2.2.

• La liste des paramètres permet de transmettre des valeurs aux méthodes. Cette liste doit contenir les types et les noms de tous les paramètres, qui sont visibles dans tout le corps de la méthode. Les paramètres peuvent être des données de type élémentaire, des tableaux et des objets créés à partir des classes. La transmission des paramètres de type élémentaire s’effectue par valeur (by value). C. à d. que des copies des paramètres sont transmises à la méthode. La méthode peut ainsi modifier les paramètres sans que leur valeur originale ne soit affectée. Toutefois, Java ne permet pas une transmission par référence des données de type élémentaire, comme en C. Lorsque aucun paramètre n’est transmis à la méthode, la paire de parenthèse de l’entête doit être vide.

• Le corps de la méthode entre les accolades, contient une suite de définitions de variable et d’instructions. Les variables, qui sont définies dans une méthode, ne sont visibles que dans cette méthode. Plus précisément, les variable ne sont visible qu’à partir de leur définition jusqu’à la fin de la méthode, ou respectivement du bloque, qui contient leur définition. Toutes les variables locales ne sont plus valables à partir du moment ou le programme quitte la méthode. Les variables qui ont été créé dynamiquement sont détruisent par le collecteur d’ordure (Garbage Collection).

• L’ordre de la définition des méthodes dans une classe est libre. La définition de prototype pour les méthodes n’est par conséquent pas nécessaire. Java n’a ainsi pas besoin des fichier d’entête (Header) ou d’insertion (Includes) comme en C/C++.

Exemple: public class Methodes_1

{

static final float PI = 3.1415f;

/**

* Example for call by value and return of a value

* computeAreaCircle() computes the area of a Circle

*/

static float computeAreaCircle (float r)

{

return(r*r*PI);

}

/**

* Example for call by reference

* clearArray() clear all elements of an array

*/

static void clearArray (int array[])

{

for(int i = 0; i < array.length; i++)

{

array[i] = 0;

}

}

/**

* Example for return of a reference

* createBooleanArray creates a Boolean array and

* returns the reference of this array.

*/

static boolean []createBooleanArray ()

{

boolean bool[] = new boolean[3];

bool[0] = true; bool[1] = true; bool[2] = false;

return(bool);

}

/**

* Main programm

*/

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 31

public static void main(String[] args)

{

// Test: call by value and return of a value

float r = 2.12f; // Radius of the Circle

float f; // Area of the Circle

f = computeAreaCircle (r);

System.out.println("Radius = " + r + " ; area Circle = " + f);

// Test: call by reference

int intArray[] = {1, 6, 83}; // Originale array

clearArray(intArray);

System.out.print("Int array: ");

for(int i = 0; i < intArray.length; i++)

System.out.print(intArray[i] + " ");

System.out.println("");

// Test: return of a reference

boolean booleanArray[];

booleanArray = createBooleanArray ();

System.out.print("Boolean array: ");

for(int i = 0; i < booleanArray.length; i++)

System.out.print(booleanArray [i] + " ");

System.out.println("");

}

}

Affichage sur l’écran: Radius = 2.12 ; area Circle = 14.119156 Int array: 0 0 0 Boolean array: true true false

2.10.2 Signature, prototype et sur chargement (overloading) La notion de signature d’une méthode représente son nom et sa liste des paramètres. Exemple : funcName (int, int). Ici, la liste des paramètres ne doit pas obligatoirement contenir les noms des paramètres. La notion de prototype d’une méthode représente sa signature et son type de restitution. Exemple : public static void funcName (int, int). Les méthodes avec des noms similaires mais avec des listes de paramètres différentes ont des signatures différentes. Ces méthodes sont considérées comme différentes et cette distinction est qualifiée de sur chargement (overloading). Java a repris le concept de sur chargement du C++. L’application du concept de sur chargement est très utile avec des méthodes, qui réalisent la même tâche avec des paramètres différents, comme par exemple le calcul du maximum : public class Overloading

{

static int max(int i, int j)

{

System.out.println("Call off int max (int, int)");

return(i > j) ? i : j;

}

static long max(long i, long j)

{

System.out.println("Call off long max (long, long)");

return(i > j) ? i : j;

}

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 32

public static void main(String[] args)

{

int a1 = 1, a2 = 2, max_int;

long b1 = 22L, b2 = 33L, max_long;

max_int = max(a1, a2); // Call the method int max(int, int)

max_long = max(b1, b2); // Call the method long max(long, long)

System.out.println("max_int = " + max_int + " max_long = " + max_long);

}

}

Remarque : La définition de la méthode « static long max (int i, int j) » gégène dans cet exemple un message d’erreur, car cette dernière a la même signature que la méthode « statique int max (int i, int j) ».

2.10.3 La récursion La récursion ou l’appel récursif signifie qu’une méthode s’appelle elle-même. Les variables locales sont de nouveau créées et initialisées à chaque appel récursif. Il est très important de définir un critère d’arrêt atteignable pour la récursion ! Une approche récursive est intéressante lorsqu’un problème peut être divisés en sous problèmes, dont la solution est identique à celle du problème principale (exemple : calcul de la faculté d’un nombre). Le critère arrêt est très important ici, si non la solution du problème nécessiterait plus de mémoire que celle mises à disposition par l’ordinateur ou le programme entrerait dans une boucle infinie ! Il existe toujours des solutions non récursives pour des problèmes récursifs. Remarque : Il faut faire très attention avec les approches récursives ! Dans certain l’approche non récursive est préférable, même si cette dernière n’apparaît pas comme étant très élégante. Les approches récursives sont interdites dans les applications, où la sécurité est très importante ! Exemple : Le calcul du plus grand diviseur en commun (Greatest Commun Divider : gcd) avec l’algorithme d’Euclide : public class Euclid

{

static int gcd(int a, int b)

{

if(b != 0) // Test the break criteria

return(gcd(b, a%b)); // recursive call, gcd() calls herself

return(a);

}

public static void main(String args[])

{

int a, b, res;

a = Integer.parseInt(args[0]);

b = Integer.parseInt(args[1]);

res = gct (a, b);

System.out.println("gcd of " + a + " and " + b + " is: " + res);

}

}

2.11 La méthode principale main() Des paramètres peuvent être transmis au programme à son démarrage : java <Programmname> <Parameter_1> <Parameter_2> .... <Parameter_n> Les paramètres sont séparés par des espaces.

Introduction à la programmation Java Aspect procédural de la programmation Java

Version 1.0, 05.03.07 Page 33

Chaque programme Java possède une méthode principale main(), qui est appelé au démarrage de dernier. Le nom de la classe contenant main() doit être identique à celui du programme. La méthode main() possède le prototype suivant : public statique void main(String args[]).

Les paramètres introduits par l’utilisateur sont transmis à la méthode main() à l’aide d’un tableau de String. L’accès séparé aux paramètres s’effectue ainsi à l’aide de args[i]. Contrairement à C/C++, dans Java args[0] ne contient pas le nom de la fonction mais le premier paramètre ! Le deuxième paramètre est transmis par conséquent avec args[1] etc. Les paramètres sont toujours transmis sous forme de String. Des changements sont donc nécessaires de temps en temps, comme par exemple lorsqu’un paramètre doit être interprété comme entier : int parameter_1 = Integer.parseInt(args[1]); args.length fournit le nombre de paramètres, qui ont été tranmis à la méthode main(). Il est recommandé de toujours contrôler le nombre des paramètres, qui sont fournis au programme, et de générer éventuellement des messages d’erreurs. Exemple : public class MainArgs

{

public static void main(String[] args)

{

for(int i = 0; i < args.length; i++)

{

System.out.println("Parameter args[" + i + "] =" + args[i]);

}

}

}

Lorsque le programme est appelé de la manière suivante : java MainArgs Hallo 2

Les objets suivants sont affichés dans ce cas sur l’écran : Parameter args[0] = Hallo

Parameter args[1] = 2

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 34

3 Introduction à la POO avec Java

3.1 Introduction Aujourd’hui il existe deux groupes de langage de programmation : 1) Les langage de programmation fonctionnel ou procédural (C, Pascal, Fortran etc.) : L’aspect principale de

ces langages de programmation est le déroulement fonctionnel. Le programme est ainsi exécuté de manière Top-Down. Les données sont également importantes, mais elles sont considérées de manière secondaire, par rapport au déroulement fonctionnel.

2) Les langages de programmation orienté objet (Java, C++, Smalltalk etc.) : Ici on essaye de modéliser la réalité à l’aide d’objets. Les langages de programmation orienté objet soutiennent beaucoup plus cet demande que les langages de programmation procédural.

Exemple: Dans une application graphique il faut dessiner des cercles. Avec les langages de programmation fonctionnels, il faudrait définir des variables pour le rayon, le centre et peut être même la couleur des cercles. Idéalement, toutes ces données devraient être rassemblées dans une structure. Ensuite, il faudrait définir les fonctions pour dessiner ou déplacer ces cercles sur l’écran. Ainsi, les données des cercles seraient transmises à ces fonctions afin de les représenter sur l’écran. Toutefois, dans cet aspect du traitement du problème, il manque une structure qui rassemble les fonctions et les données en une seule entité. Un deuxième pas serait l’application des types de donnée abstrait (voire chapitre 3.1.2). Ici les données des cercles seraient protégées par rapport à l’extérieur et des fonctions seraient mis à disposition pour modifier ces données (ex. setRadius() etc.). Cet aspect est relativement bon, mais n’est quasi pas soutenu par les langages de programmation procédurale Avec les langages de programmation orientée objet, une classe Circle serait définie. Une classe est en quelque sorte un plan de construction, qui définit ce qu’un objet possède et peut faire. Cette classe serait capable de gérer les données du cercle, qui seraient protégées de l’extérieur, et fournirait toutes les fonctions (dans les langages de programmation OO on parle de méthode) pour traiter ces données. Ainsi, il serait possible de créer plusieurs objets de cette classe (c. à d. que sous un aspect software, des objets « vivants » sont créés en fonction du plan de construction). L’utilisateur du programme pourrait ainsi dessiner plusieurs cercles, qui seraient tous des objets de la classe cercle avec toutefois des rayons et des couleurs différents. Ce qui a été introduit brièvement dans cet exemple, sera traité de manière détaillée dans ce chapitre.

3.1.1 Les problèmes des langage de programmation procédural Avec des langages de programmation procédural conventionnel, les problèmes suivants apparaissent avec le développement de gros projets, qui doivent être entretenus et complétés au cours du temps : 1) Les structures de donnée sont définies de manière globale. Les fonctions qui ont accès à ces structures de

donnée sont en générale répartie dans tous les modules du programme. Si une structure de donnée doit être adaptée, toutes les fonctions qui ont accès à cette structure de donnée doivent également être modifiées.

2) Les nouvelles fonctionnalités, qui doivent être ajoutées au programme et qui sont identiques à des fonctions préexistantes, seront toujours insérées au code par des opérations copie et adaptation. Ces nouvelles fonctions doivent systématiquement être testées et le programme devient de plus en plus redondant. De plus, si une erreur est découverte dans une fonction « d’origine » du code, il faudra corriger toutes les fonctions qui ont été définie à partir de cette fonction.

3.1.2 Les types de donnée abstraits Les types de données abstraites (ADT, Abstract Data Types) peuvent également être utilisé avec des langages de programmation procédurale. La principale caractéristique de ces types de donnée est la séparation de l’interface par rapport à l’implémentation.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 35

Fondamentalement la structure des types de données abstraites est la suivante : • Donnée: La structure de donnée est seulement connue à l’intérieur de l’ADT, et est masquée par rapport à

l’extérieur (information hiding). • Méthode: Les méthodes traitent les données. L’utilisateur ne peut accéder aux données internes qu’avec ces

méthodes. La modernisation du programme et l’encapsulement des données peuvent être effectué proprement à l’aide des ADT. Les changements de code sont ainsi possibles par adaptation de la structure de donnée et des méthodes qui traitent ces dernières, à l’intérieur de l’ADT. Tant que l’interface de l’ADT reste identique, le programme ne doit pas être changé à des autres endroits. Le changement se limite ainsi uniquement à l’ADT. Comme ce fut déjà mentionné dans ce document, les langages de programmation fonctionnelle ne soutiennent presque pas les ADT.

3.1.3 Exigences pour les langage de programmation OO A partir des connaissances de ci-dessus, les demandes suivantes peuvent être formulées pour les langages de programmation OO : 1) Il faut pouvoir définir des « types de donnée » orientés problèmes. Les données et les méthode des ces

derniers doivent former une entité. 2) Les structures des données internes ne doivent être accessible qu’en cas de nécessité. Dans les autres cas,

ces dernières devraient être protégées. 3) Uniquement les interfaces des méthodes doivent être visibles de dehors. Leurs implémentations doivent être

masquées. 4) Les parties du code, qui sont communes, doivent pouvoir être isolées. 5) Des techniques de changement de code préexistant doivent être mises à disposition.

3.2 Caractéristiques des langages OO Le but de la programmation OO est de reproduire le monde réel à l’aide d’objets. Ces derniers peuvent être des plantes, des animaux, des hommes, des machines, des véhicules etc. La plupart de ces objets ont des propriétés communes et des relations avec d’autres objets. Il en résulte une forme d’hiérarchie d’objets (par ex. un cercle et un rectangle sont des objets géométriques, qui ont des coordonnées et des couleurs). La programmation OO est basée sur les principes suivants : • Abstraction • Encapsulation • Héritage et polymorphisme

3.2.1 Abstraction à l’aide d’objet Le programmeur va essayer de reproduire la réalité avec des objets appropriés dans son programme. Cette affirmation est basée sur le mot « essayer », car ce pas peut être très difficile et demande beaucoup d’expérience avec les problèmes complexes. Un objet représente une unité software. Il contient des attributs et des méthodes : Les attributs sont les éléments variables d’un objet. Ils peuvent être changés pendant la durée de vie de l’objet. Typiquement, les attribut peuvent être: la grandeur, la longueur, le poids, la couleur, la vitesse etc. Les attributs peuvent également être des objets : comme par exemple un cercle possède un attribut point central, qui est objet point). Les méthodes sont les fonctions, qui peuvent être exécutées sur ces objets. Par conséquent, ils définissent le comportement d’un objet. Typiquement les méthodes peuvent être, additionner, soustraire, mettre à 1, démarrer, dessiner, rouler etc. Exemple objet Circle :

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 36

Attribut : x_coord, y_coord, radius, isVisible etc. Méthode : setCoord(), draw(), move() etc. Plusieurs cercles « vivants » peuvent être gérés par le programme. Ces derniers ont tous les mêmes attributs et les mêmes méthodes. Toutefois, les valeurs des attributs peuvent être différentes. Le cercle 1 peut par exemple avoir un autre rayon et des autres coordonnées que le cercle 2. Si l’utilisateur du programme graphique souhaite dessiner un nouveau cercle, le programme génère dans un premier temps un nouveau objet du type cercle, ensuite il défini le centre et le rayon de ce cercle et finalement il appelle la méthode « draw() » afin d’afficher le cercle sur l’écran.

x_coord y_coord radius isVisible setCoord() draw() move()

Programm

Ecran

Cercle 1

r = 4

Cercle 2

r = 10

Cercle3

r = 5

Figure 1 : Objets du type cercle

Les objets seront traités plus en détail au chapitre 3.3.

3.2.2 Encapsulation Les attributs d’un objet ne sont normalement pas visibles à l’extérieur de l’objet. Ils ne peuvent être modifiés que par des méthode, qui sont mises à disposition par l’objet lui même. Par ailleurs, seul l’interface des méthodes est connue et leurs implémentations restent masquée. Par conséquent, la structure interne des données et l’implémentation des méthodes de l’objet peut être modifiées, sans devoir changer les séquences de codes en relation avec l’objet. Naturellement, la condition pour cela est que les interfaces des méthodes restent inchangées. Exemple: La méthode calculate() pour l’exécution d’un algorithme complexe doit être améliorée. La méthode et les types de donnée des attributs peuvent ainsi être réadaptés, sans qu’il y ait des conséquences sur les autres parties du programme. Remarque: Le concept de l’encapsulation des données permet d’une part d’augmenter la sécurité des données et d’autre part de faciliter les changements ultérieurs du programme.

3.2.3 Héritage et polymorphisme Le but de l’héritage est la recherche de similitude entre différents objets pour définir une hiérarchie des objets. Les parties similaires du code peuvent ainsi être rassemblées, afin de réduire la redondance du programme. Ainsi, des nouveaux objets pourront être définis à partir d’objets déjà existants. L’exemple des objets géométriques Circle et Rectangle, qui a été introduit au début de ce chapitre, peut être utilisé ici pour illustrer le principe d’héritage et de polymorphisme. Pour résoudre ce problème de manière

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 37

structurée, il faut définir au départ un objet géométrique avec les attributs coordonnées (X et Y) et isVisible, qui permet de dernier la visibilité de l’objet sur l’écran. L’objet géométrique sert d’objet de base pour les objets dérivés Circle et Rectangle, qui héritent les caractéristiques de l’objet géométrique (attributs et méthodes). Ainsi Circle possède déjà les coordonnées x_coord et y_coord, qui sont complétés par son rayon. Le rectangle hérite également les coordonnées, qui sont complétés par sa largeur et sa hauteur.

Objet géométrique

x_coord y_coord isVisisble

Cercle radius

Rectangle width height

Figure 2 : Hiérarchie des objets graphiques

Les méthodes ont été omises dans cette figure. Ainsi, Circle possède, en complément de son attribut radius, les attributs x_coord, y_coord et isVisible, qui ont été hérités de l’objet géométrique. Parallèlement, le rectangle possède les attributs suivants : x_coord, y_coord, isVisible, width et height. Le thème héritage et polymorphisme sera traité plus en détail aux chapitres 3.4 et 3.4.4.

3.2.4 Caractéristiques de Java Java est un langage de programmation orienté objet avec les caractéristiques suivantes: • Java est basé sur les classes (voir chapitre 3.3) • Toutes les classes Java dérivent d’une classe de base commune : Object • Java ne soutient pas l’héritage multiple (voir chapitre 3.4) • Java soutient le concept d’interface (Interfaces, voir chapitre 3.6) • Java soutient le polymorphisme (voir chapitre 3.4.4) • Les méthodes peuvent être sur écrite dans Java

3.3 Les classes et les objets

3.3.1 Définition Considérons l’exemple des objets géométriques Circle et rectangle. Les attributs et les méthodes doivent être définis à un endroit dans le code. Les classes permettent de réaliser cela. Les classes sont ainsi des plans de construction ou des recettes de cuisine pour les objets et constituent ainsi la partie statique du programme. Ce qui permet de créer des objets à partir d’une classe (instancier, voir chapitre 3.3.8), afin de produire des exemplaires ou instances de cette classe. En comparaison avec le langage de programmation C, la classe correspondrait à la déclaration d’une structure de donnée, et l’objet à la variable dont le type correspond à cette structure de donnée. L’appel de méthode est également qualifié « d’envoie d’information » à une instance.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 38

3.3.2 La syntaxe Une classe est définie à l’aide du mot clé class : modifier class Classname {

// Déclaration des attributs

// Déclaration des méthodes

}

Le nom de la classe doit être unique dans tout le projet et correspondre à celui du fichier contenant le code source. Une classe Circle peut être définie dans un fichier « Circle.java » pour nos objets cercles.

3.3.3 Les attributs Les attributs sont identiques aux variables des méthodes, qui ont été introduites au chapitre 2. Toutefois, leur accessibilité ne se limite pas uniquement à une seule méthode, mais ils appartiennent à la classe en entier. Lors de la création d’une instance d’une classe, le programme attribue de l’espace mémoire pour les attributs de cet objet. La durée de vie des attributs est identique à celle de l’instance de la classe.

modifier class Classname

{

// Déclaration des attributs

modifier datatype name_1;

modifier datatype name_2;

...

// Déclaration des méthodes

...

}

Les attributs sont déclarés avec un modificateur (modifier en anglais : voir chapitre 3.3.5), le type de donnée et le nom de l’attribut. L’accès à un attribut d’une instance s’effectue avec l’opérateur point : Instancename.Attributname

3.3.4 Les méthodes Les méthodes statiques ont déjà été introduites dans le chapitre 2. En générale, les méthodes exécutent des fonctions sur un objet. Ces fonctions peuvent être de nature à modification un attribut ou à exécuter une action, comme par exemple draw() pour Circle. En java, les méthodes ne peuvent être définies que dans les classes. Il n’est pas possible de définir des méthodes globales. Les méthodes sont définies de la manière suivante :

modifier class Classname

{

...

// Déclaration de la méthode

modifier returntype methodename (liste_des_paramètres)

{

// Corps de la méthode

}

...

}

La déclaration de la méthode s’effectue à l’aide du modificateur (voir chapitre 3.3.5), le type de restitution, le nom de la méthode et la liste des paramètres pour la transmission des valeurs. L’accès à une méthode d’une instance s’effectue avec l’opérateur point : Instancename.Methodename()

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 39

3.3.5 Modificateur d’accès La visibilité des classes, des méthodes et des attributs peut être définie à l’aide des mots clés public, protected et private. Pour des raisons de complémentarité, la visibilité au niveau des paquets (packages, voir chapitre 3.7) est également traité dans cette section. La visibilité définit l’accessibilité des attributs ou des méthodes d’une classe (<Objet>.<Attribut> respectivement <Object>.<Méthode>). On distique ici 4 cas : code de la même class, code d’une classe dérivée, code du même paquet ou de code générale. La visibilité peut être partagé en 4 niveaux Mot clé Accès possible Description public De partout Accessible de partout sans restriction.

N’est pas recommandé pour les attributs. Pas de mot clé De la même classe et des classes

du même paquet. Mais pas des classes dérivés.

Pas d’accès en dehors du paquet.

protected De la même classe, des classes dérivées et des classes du même paquet

Les attributs et les méthodes sont accessibles à partir de la classe, contenant leurs déclarations, et à partir des classes dérivées. Cependant cet accès n’est pas possible à partir des instances de cette classe.

private Seulement de la même classe Les attributs et les méthodes privés sont masqués. Ce qui est très restrictif car même les classes dérivées n'y ont pas accès. Ce type de modificateur est souvent utilisé avec les attributs.

Figure 3 : Modificateur d’accès

Remarque concernant les mode d’accès pour les classe (class) et les interfaces (interface) : Ici il n’existe que les accès de partout (public) ou depuis le même paquet (absence de mot clé, défaut). Pour les classes internes (voir chapitre 3.3.11) les modificateurs private et protected sont également autorisés. Exemple:

public class Circle

{

private int x_coord;

private int y_coord;

private int radius;

public boolean isVisible;

public void setCoord(int x, int y)

{

x_coord = x;

y_coord = y;

}

protected void draw()

{

// draws the Circle

}

private void move(int x, int y)

{

x_coord += x;

y_coord += y;

draw();

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 40

}

public class TestAccess

{

public static void main(String[] args)

{

Circle myCircle = new Circle ();

// myCircle.x_coord = 5; // Compiler: The field myCircle.x_coord is not visible

myCircle.isVisible = true; // always ok

myCircle.setCoord(5, 7); // always ok

myCircle.draw(); // ok for the same Package

// myCircle.move(1,2); // Compiler: The method myCircle.move() is not visible

}

}

Description de cet exemple: La méthode principale main(), avec laquelle le programme est démarrée, est définie dans la classe TestAccess. Au début de cette méthode, une instance myCircle est créée à partir de la classe Circle. Ensuite, suivent plusieurs exemples où l’on essaye d’accéder, à l’aide de l’opérateur point, aux différents attributs et méthodes de myCircle. L’accès à l’attribut x_coord n’est pas possible, car ce dernier est déclaré comme private dans la classe Circle. L’accès à l’attribut isVisible est par contre possible, car ce dernier est public. La même chose est valable pour la méthode setCoord(), qui est également public. L’appel de la méthode draw() est également possible, car les classes TestAccess et Circle sont déclarées dans le même paquet. Si cela n’était pas le cas, draw() serait également inaccessible ici. L’appel de la méthode move() génère également une erreur du compilateur. En effet, cette dernière est déclarée comme private dans la classe Circle et, par conséquent, n’est accessible que dans cette classe.

3.3.6 Les diagrammes de classe L’analyse et le design des programmes orientés objet s’effectuent le plus souvent avec des UML (Unified Modeling Language). Les diagrammes de classe font parti des UML, les autres diagrammes sont décrits dans le chapitre 3.8.1. Les diagrammes de classe permettent de représenter graphiquement les différentes classes et leurs relations entre elles. Une classe est modélisée de la manière suivante avec les diagrammes de classe :

Nom de la classe

Attributs Methodes

Figure 4 : Design d’une classe

L’exemple suivant montre le digramme de la classe pour la classe Circle, introduite à la section 3.3.5 :

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 41

Circle

x_coord y_coord radius isVisible setCoord() draw() move()

Figure 5 : Diagramme de classe de la classe Circle

Les diagrammes de classes (diagramme UML) sont générés avec des outils informatiques. Les outils professionnel performant facilitent les phase d’analyse, de design et de codage. Ils sont capable de générer du code à partir des diagrammes et inversement de générer un diagramme à partir de code (Reverse Engineering). Ils indiquent également les éventuelles inconsistances aux programmeurs. Certains outils représentent également les modificateurs à l’aide de symboles graphiques (par exemple un clé pour private). Un programmeur professionnel définira toujours un diagramme de classe avant de coder le programme.

3.3.7 Les méthodes et les attributs de classe Les attributs et les méthodes d’une classe sont toujours attachés à une instance « vivante ». Cela a été illustré dans l’exemple de la section 3.3.5. Il faut d’abord instancier un objet du type Circle, afin d’en initialiser les attributs ou d’en appeler les méthodes. Il existe également des attributs et des méthodes, qui ne sont pas attachés une instance et qui existent depuis le début jusqu’à la fin du programme. Ces derniers sont nommés des attributs et des méthodes de classe et sont déclarés à l’aide du mot clé static. Les méthodes de classe ont été souvent utilisées dans ce manuscrit, sans que cela ait été explicitement dit. La méthode main est toujours recherchée au démarrage d’un programme. Toutefois, cette dernière doit être appelée sans qu’aucun objet existe : public static void main(String[] args)

main() est par conséquent une méthode de classe. Les méthodes de classe peuvent également appeler des autres attributs et méthodes de classe, qui sont également déclarés avec le mot clé static. Le second chapitre (Aspect fonctionnel de la programmation Java) traite uniquement des attributs et les méthodes de classe. Exemple : La classe Circle de l’exemple de la section 3.3.5 doit être complété avec des attributs et des méthodes de classe : public class Circle

{

private int x_coord;

private int y_coord;

private int radius;

public boolean isVisible;

public static int myClassAttr = 8; // Attribute of the class

public void setCoord (int x, int y)

{

x_coord = x;

y_coord = y;

myClassAttr++; // Access possible to the class attribute

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 42

public static void printInfo() // Method of the class {

//isVisible = false; // Error, the access to the class attribute

// is not possible from the class method!

System.out.println("myClassAttr = " + myClassAttr); // is ok.

}

}

public class ClassMethod

{

public static void main(String[] args)

{

// Test the access to the class method of Circle,

// no object Circle has been instantiated !

Circle.printInfo(); // Ok

//myClassAttr = 6; // Error

Circle.myClassAttr = 5; // Ok //Circle.isVisible = true; // Error, it is not a class attribute

Circle.printInfo(); // Ok //Circle.setCoord(5,7); // Error, it is not a class attribute

// Test the access to the object method

Circle myCircle = new Circle();

meinCircle.isVisible = true; // Ok

meinCircle.myClassAttr = 6; // Ok

meinCircle.printInfo(); // Ok

meinCircle.setCoord(5,7); // Ok

}

}

Affichage sur l’écran: myClassAttr = 8

myClassAttr = 5

myClassAttr = 6

Remarque: Les méthodes et les attributs de classe sont accessibles à l’aide du nom de la classe et de l’opérateur point. Il est également possible de les accéder à l’aide du nom de l’instance. Toutefois, cela est moins courant.

3.3.8 Instancier un objet, constructeur La création d’un objet concret à partir d’une classe et qualifié d’instancier. Pour cela on utilise l’opérateur new. Une instance de la classe Circle a été créée dans l’exemple du chapitre 3.3.5 : Circle myCircle = new Circle();

La formulation générale est la suivante : <Classtyp> <Instance_Name>;

<Instance_Name> = new <Classtyp ()>;

Ou : <Classtyp> <Instance_Name> = new <Classtyp()>;

Instance_Name est une référence, qui adresse l’instance créée à partir de la classe Classtyp. Les attributs et les méthodes de cette instance peuvent être accédées à l’aide de cette référence. new créé un nouveau objet, et attribue son adresse à la référence Instance_Name. Le collecteur d’ordure (Garbage Collection) élimine cette instance, lorsqu’il n’est plus utile.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 43

Durant la création d’instance, la quantité de mémoire nécessaire pour le nouvel objet est déterminée par la machine virtuelle. Cette quantité dépend des attributs, qui ont été définies dans la classe. Par conséquent, la même quantité de mémoire sera allouée pour des objets de même classe. Les constructeurs sont des méthodes spéciales, qui sont appelées durant la création d’instance avec new, afin d’initialiser l’objet. Les constructeurs ont les caractéristiques suivantes : • Ils ont le même nom que la classe • Ils ne possèdent pas de type de retour et pas de modificateur • Ils continent une liste de paramètre, pour la transmission des arguments • Ils peuvent être sur écrites Exemple: La classe Cirlce avec deux constructeurs et la méthode main(): public class Circle {

private int x_coord;

private int y_coord;

private int radius;

private boolean isVisible;

// 1. constructor, without parameter

Circle() {

System.out.println("1. constructor without parameter");

x_coord = 1;

y_coord = 1;

radius = 1;

isVisible = false;

}

// 2. constructor, with parameter

Circle(int x, int y, int r, boolean isVisible) {

System.out.println("2. constructor with parameter");

x_coord = x;

y_coord = y;

radius = r;

this.isVisible = isVisible;

}

// Printing all the arguments on the screen

public void printCircle()

{

System.out.println("x_coord = " + x_coord);

System.out.println("y_coord = " + y_coord);

System.out.println("radius = " + radius);

System.out.println("isVisible = " + isVisible);

System.out.println("");

}

// Beginning of the main program

public static void main(String[] args)

{

System.out.println("Start Program");

Circle Circle1 = new Circle(); // Instance of 1. Circle Circle1.printCircle();

Circle Circle2 = new Circle(3,7,10,true); // Instance of 2. Circle Circle2.printCircle();

}

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 44

Affichage sur l’écran: Start Programm

1. constructor withou parameter

x_coord = 1

y_coord = 1

radius = 1

isVisilbe = false

2. constructor with parameter

x_coord = 3

y_coord = 7

radius = 10

isVisilbe = true

Un instance de Circle est créé au départ dans main(). Ici, le premier constructeur de Circle est appelé, car aucun argument n’est transmis à l’opérateur new. Ensuite, la méthode printCircle() de l’instance Circle1 est appelé, afin d’afficher les valeurs défaut des attributs. Une deuxième instance Circle2 est créée. Dans ce second cas, des arguments sont transmis à l’opérateur new. Le deuxième constructeur est ainsi appelé, afin d’initialiser les attributs. Le nom du 4ème paramètre du 2ème constructeur (isVisible) est identique à celui d’un des attributs. Cela est très utile pour ne pas devoir toujours rechercher des nouveaux noms pour les paramètres. Toutefois, dans ce cas il faut utiliser le mot clé this pour l’opération d’attribution : this.isVisible = isVisible;

this est une référence sur l’objet courant. Ainsi il est possible de définir en Java des noms de paramètres identiques à ceux des attributs. Important: • Lorsqu’une classe ne possède pas de constructeur, le système crée automatiquement un constructeur défaut

sans paramètre. • Lorsqu’une classe possède au mois un constructeur, le système ne crée pas de constructeur défaut sans

paramètre. Ainsi, si un tel constructeur est nécessaire, il faut le programmer (voir exemple de ci-dessus) Remarque: Un programme OO n’est finalement qu’une collection d’instances, qui ont les propriétés suivantes : • Elles sont créés à un instant donné et sont de nouveau détruites lorsqu’elles ne sont plus utiles. • Elles communiquent entre elles par appel de méthode.

3.3.9 Destructeur et collecteur d’ordure (Garbage Collection) Une instance a besoin d’espace mémoire pour ses attributs. La fin de vie de cette instance est reconnue par le collecteur d’ordure, qui la détruit pour libérer à nouveau de l’espace mémoire. Ce mécanisme empêche la saturation de l’espace mémoire et permet ainsi de continuer d’instancier des nouveaux objets. Le collecteur d’ordure détruit une instance, lorsque cette dernière n’est plus adressée par une référence. Le programmeur est responsable de cela. Dans certain cas il faut réaliser également des travaux de rangement durant la destruction des instances. Cela est notamment le cas lorsque des instances occupent des ressources (appareils, fichiers, sockets etc.). La première solution pour ce problème est la programmation d’une méthode close(), pour libérer ces ressources Toutefois, l’appel de cette méthode est sous la responsabilité de l’utilisateur ! Une solution plus élégante est l’utilisation de destructeurs. En analogie avec les constructeurs, les destructeurs sont appelés avant la destruction de l’instance par le collecteur d’ordure. Dans java le destructeur est une méthode, qui s’appelle finalize() et qui possède les propriétés suivantes :

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 45

• Elle s’appelle finalize() • Elle possède le type de restitution void • Elle n’a pas de paramètres • finalize(), contrairement au constructeur, peut être appelée par des méthodes standards. finalize()

devrait être protégée des appels multiples. Exemple : public class Test

{

private int count;

Test(int count) // Constructor

{

this.count = count;

System.out.println("Constructor " + count + ". Object");

}

protected void finalize() // Destructor

{

System.out.println("Destructor " + count + ". Object");

}

}

public class TestDestructor

{

public static void print(int i)

{

Test localTest = new Test(i); // Creation of the 1. object

} // Destruction of the 1. object

public static void main(String[] args)

{

System.out.println("Start of Program");

Test myTest;

myTest = new Test(1); // Creation of the 1. object

print(2); // Creation of the 2. object

System.gc(); // Calling garbage collection

System.out.println("Middle of Program");

myTest = null; // Release the 1. object

System.gc(); // Calling garbage collection

System.out.println("End of Program");

}

}

Affichage sur l’écran:

Start Programm

Constructor 1. Object

Constructor 2. Object

Destructor 2. Object

Middle of Programm

Destructor 1. Objekt

End of Programm

Au début de main(), un objet local myTest est crée à partir de la class Test. L’appel de la méthode print() génère une deuxième instance de Test, qui sera de nouveau libérée, car elle n’apparaît que dans print(). Le premier objet sera libéré à son tour avec l’annulation de sa référence (myTest = null). Le collecteur d’ordure (Garbage Collection) est appelé normalement en arrière plan à des moments quelconques par le système. Toutefois pour mieux illustrer la destruction des objets dans cet exemple, le destructeur d’ordure a été appelé explicitement avec l’instruction « System.gc ». Normalement, cela ne devrait pas être nécessaire.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 46

Important : Même si cela a déjà été mentionné dans ce cours : Lorsque vous passez de Java à C++, vous devez vous habituer à libérer explicitement la mémoire allouée aux objets (souvent dans le destructeur). Dans C++ chaque classe devrait ainsi contenir un destructeur, afin de pouvoir libérer toutes les ressources mises à disposition pour elle. Alors que dans Java, cette libération ne devrait se limite qu’aux ressources autres que la mémoire.

3.3.10 Transmission et retour des objets Les objets peuvent également être transmis comme paramètre aux méthodes ou retournés par ces dernières. Comme chaque objet est toujours adressé par une référence, il suffit de transmettre la référence. public class Fraction

{

// Attribute

int numerator;

int denumerator;

// Constructor

Fraction(int numerator, int denumerator)

{

if(denumerator != 0) // is denumerator different from null

{

this.numerator = numerator;

this.denumerator = denumerator;

}

else

{

System.out.println("Division with null");

this.numerator = 0;

this.denumerator = 1;

}

}

// Multiplication

public Fraction mul(Fraction para) {

Fraction res = new Fraction(0, 1); // new instance for result

res.numerator = numerator * para.numerator; // multiplication with numerator

res.denumerator = denumerator * para.denumerator; // multiplication with denumerator

return(res);

}

public void print()

{

System.out.println(numerator + "/" + denumerator);

}

public static void main(String[] args)

{

int z1, n1;

int z2, n2;

if(args.length == 4)

{

z1 = Integer.parseInt(args[0]); // reading the parameter

n1 = Integer.parseInt(args[1]);

z2 = Integer.parseInt(args[2]);

n2 = Integer.parseInt(args[3]);

Fraction b1 = new Fraction(z1, n1); // create Fraction 1 and 2

b1.print();

Fraction b2 = new Fraction(z2, n2);

b2.print();

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 47

Fraction b3 = b1.mul(b2); // multiplication b3.print();

}

else

{

System.out.println("Please enter 4 parameters:");

System.out.println("Numerator1, Denumerator1, Numerator2, Denumerator2");

}

}

}

Appel de la fonction avec les paramètres suivants : "3" "5" "7" "8"

Affichage sur l’écran : 3/5

7/8

21/40

L’intérêt principale de cet exemple est la méthode mul(), qui reçoit un objet Fraction comme argument. La multiplication y est réalisée entre ces arguments et les valeurs internes de l’objet. Au début de cette méthode un objet de la classe Fraction est créé pour le stockage du résultat. Ce dernier sera retourné comme référence à la fin de la méthode. La méthode mul() est appelé dans le programme principal avec l’instruction suivante : Fraction b3 = b1.mul(b2); // Multiplication

Une multiplication entre les instances b1 et b2 est alors réalisé et le résultat est stocké dans b3. Remarquez que l’objet b3 est créé dans la méthode mul().

3.3.11 Les classes internes Dans Java les classes peuvent également être définies à l’intérieur d’autres classes. Ces classes sont appelées « classes internes » et possèdent les propriétés suivantes : • Elles peuvent accéder aux attributs et aux méthodes de la classe externe (même les éléments privés). • Des instances de la classe interne peuvent être créées dans la classe externe. Les éléments de ces instances

sont accessibles par la classe externe. • Les classes internes ne sont visible en dehors du bloque, qui contient leur définition, qu’avec un nom

qualifié. Ce dernier est « ClasseExtren.ClasseInterne ». Exemple: public class ExternClass {

private int ExternVariable = 10;

// Intern class

public class InternClass {

public int InternVariable = 10;

public void test(int i)

{

InternVariable = ExternVariable * 2;

System.out.println("test() InternClass " + i);

}

}

public void test(int i)

{

System.out.println("test() ExternClass " + i);

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 48

InternClass internClass = new InternClass(); internClass.test(i); }

}

public class TestInternClass

{

public static void main(String[] args)

{

// Call the extern class

ExternClass extern = new ExternClass(); extern.test(1);

// Call the intern class

ExternClass.InternClass intern = extern.new InternClass(); intern.test(2); }

}

Affichage sur l’écran: test() ExternClass 1

test() InternClass 1

test() InternClass 2

Au début du programme principale, une instance de la classe ExternClass est créée et la méthode test() en est appelée. Dans cette méthode, une instance de la classe interne est à nouveau créée et la méthode test de cette instance est également appelée. Ensuite, une instance de la classe interne est directement créée dans main(). Remarquez le nom qualifié da la classe et l’opérateur new. Normalement il n’y a pas d’accès depuis l’extérieur de la classe externe sur la classe interne.

3.4 Héritage

3.4.1 Fondement La programmation OO sans héritages serait comme des pâtes italienne sans verres de vin rouge. Le but de l’héritage est de rassembler le codes identique des différents classes dans une super classe (que l’on nomme également classe parent). La super classe peut transmettre ainsi ses propriétés (attributs et méthodes) aux sous classes. Des nouvelles propriétés peuvent être ajoutées dans les sous classes. Une sous classe peut également sur écrire une méthode héritée de la super classe. C. à d. qu’elle peut redéfinir cette méthode. L’héritage est également qualifié de dérivation ou de spécialisation. Le principe d’héritage apporte les avantages suivants : • L’héritage permet de réduire la redondance du code. Le code en commun est défini dans une super classe.

L’effort de programmation peut ainsi être réduit. • Le code ajouté dans une super classe (comme par ex. une nouvelle méthode) est également disponible dans

les basses classes. • Les changements de code dans les hautes classes sont également valables pour les basses classes. Ce qui

permet de réduire de manière significative l’effort de test. • Des nouvelles basses classes peuvent toujours être ajoutées dans une bonne hiérarchie de classes. Le

programme peut être ainsi étendu, sans changement du code existant. • La hiérarchie des classes correspond au monde réel (objets graphiques, personnes, véhicules, le monde

animal, le monde végétal etc.). le programme devient ainsi plus accessible et plus compréhensible. • Le code est ainsi réutilisable pour d’autres applications. Il est possible d’utiliser des classes existantes et les

modifier à l’aide du principe d’héritage.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 49

Propriétés de l’héritage dans Java : • Dans Java une sous classe ne peut hériter que d’une seule super classe. Par conséquent, « l’héritage

multiple » n’est pas possible. • Lorsqu’une classe ne possède pas de super classe, elle héritera automatiquement de la classe Object.

Toutes les classes possèdent ainsi les propriétés de la classe Object, car les classes supérieures héritent les propriétés d’Object et les transmettent aux classes inférieures.

• Dans la sous-classe le mot clé extends sert à faire connaître la super classe, à partir de laquelle l’héritage doit avoir lieu.

• Les constructeurs des super classes sont appelés avec le mot clé super. super est également utilisé pour désigner dans une méthode de la sous-classe une méthode de la super classe ayant le même nom (méthode sur écrite).

Important: Le design d’une hiérarchie des classes, c. à d. la recherche du code en commun des différentes classes, est une tâche très exigeante et intéressante. Un bon diagramme de classe dans un projet complexe nécessite beaucoup de temps et d’expérience. Le résultat est en général une structure stable et un entretient facilité du programme. L’héritage est illustré de la manière suivante dans les diagrammes de classe :

Classe parent

Classe enfant

Figure 6 : Héritage avec les diagrammes de classe

Exemple pour une super classe Parent et une sous classe Child: La super classe doit contenir les 3 attributs p1, p2 et p3. Ces derniers ont respectivement les modificateurs public, protected et private. En plus elle contient un constructeur ainsi que les méthodes do() et print(). La classe Child hérite tous ces propriétés et possède en plus un attribut c1, un constructeur Child() ainsi que les méthode doChild() et print(). La méthode print() de la classe Child sur écrit la méthode print() de la super classe. Le diagramme de classe est ici le suivant :

Parent

int p1 int p2 int p3 Parent() doParent() print()

Child

int c1 Child() doChild() print()

Figure 7 : Diagramme de classe pour l’exemple Parent et Child

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 50

public class Parent

{

// Attribut

public int p1;

protected int p2;

private int p3;

// Constructor

Parent(int p1, int p2, int p3)

{

System.out.println("Constructor of class Parent");

this.p1 = p1;

this.p2 = p2;

this.p3 = p3;

}

protected void doParent()

{

System.out.println("doParent() of class Parent");

}

public void print()

{

System.out.println("print() of class Parent");

System.out.println("p1: " + p1 + " p2: " + p2 + " p3: " + p3);

}

}

public class Child extends Parent {

// Attribut

protected int c1;

// Constructor

Child(int c1, int p1, int p2, int p3)

{

super(p1, p2, p3); // Call constructor of Parent System.out.println("Constructor of class Child");

this.c1 = c1;

}

protected void doChild()

{

System.out.println("doChild() of class Child");

doParent(); // Methode doParent() of Parent

}

public void print() // Redefine print of Parent

{

System.out.println("print() of class Child");

super.print(); // Call print() of Parent System.out.println("c1: " + c1);

}

public static void main(String[] args)

{

Child child = new Child(1, 2, 3, 4); // Create a instance of Child

child.doChild();

child.print();

child.p1 = 0; // ist ok because p1 is public

child.p2 = 0; // ist ok because p2 is protected

//child.p3 = 0; // error because p3 is private

}

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 51

Affichage sur l’écran : Constructor of class Parent

Constructor of class Child

doChild() of classe Child

doParent() of class Parent

print() of class Child

print() or class Parent

p1: 2 p2: 3 p3: 4

c1: 1

Un instance de la classe Child est créée au début du programme principale main(). Le constructeur de la classe Child est ainsi appelé par le système. Tout au début de cette méthode, le constructeur de la super classe Parent est appelé. Cela est important, car il faut d’abord initialiser la super classe Parent, avant que la sous classe Child puisse hériter les propriétés de Parent. En général un constructeur doit toujours appeler au début le constructeur de la super classe, lorsque cette dernière est disponible, et ensuite exécuter ses propres instructions. La seconde instruction de main() est l’appel de la méthode doChild(). Cette dernière appel à son tour la méthode doParent() de la super classe. Ce qui est correct, car Child ne contient pas de méthode du même nom. Dans Java, il est possible d’appeler dans une sous-classe toutes les attributs et les méthodes de la super classe, pourvu que les appels soient uniques. La méthode print() de Child sur écrit la méthode print() de Parent. C. à d. qu’ici la méthode print() de la super classe n’est pas complète pour la sous classe et doit par conséquent être adaptée ou sur écrite. Souvent le code de la méthode de la super classe peut être utilisé dans la sous-classe, moyennant quelques adaptations, comme cela est le cas dans cet exemple avec l’affichage de c1. Ainsi la méthode print() de la super classe est appelée depuis la méthode print() de la sous classe. Toutefois cet appel n’est pas unique (cela voudrait dire que l’on appel la méthode print() de Child), par conséquent, cette dernière est appelé avec super.print(). Ainsi la méthode print() de la super classe affiche au début les attributs de cette dernière, suivi de l’affichage de l’attribut c1 par la méthode print() de la sous classe. L’accès à l’attribut child.p1 est correct dans main(), car p1 a été déclaré comme public. L’accès à child.p2 est également correct, car p2 a été décelé comme protected. Toutefois l’accès à child.p3 n’est pas possible, car p3 a été déclaré comme private. L’accès à p3 n’est que possible dans la super classe.

3.4.2 Ordre des constructeurs et des destructeurs L’ordre de l’appel des constructeurs et des destructeurs est régit par les règles suivantes : 1) La première instruction dans un constructeur doit être l’appel du constructeur de la super classe avec le mot

clé super. Si cela n’est pas définit explicitement, c’est le constructeur par défaut qui va être appelé. Ce dernier doit par conséquent exister inévitablement, si non le compilateur génère un message d’erreur.

2) La conséquence du point ci dessus est qu’un seul constructeur de la super classe ne peut être appelé. Le constructeur de la super classe est ainsi toujours appelé en premier suivi du constructeur de la sous-classe. Cet ordre est inversé avec les destructeurs. Ici le destructeur de la sous-classe est exécuté en premier, suivi du destructeur de la super classe. Toutefois, le méthode finalize() de la super classe doit être appelée explicitement. Exemple: public class Parent

{

// Attribut

public int p1;

protected int p2;

private int p3;

// Constructor

Parent(int p1, int p2, int p3) {

System.out.println("Constructor class Parent");

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 52

this.p1 = p1;

this.p2 = p2;

this.p3 = p3;

}

// Destructor

protected void finalize() {

System.out.println("Destructor class Parent");

}

public void print()

{

System.out.println("print() class Parent");

}

}

public class Child extends Parent {

// Attribut

protected int c1;

// Constructor

Child(int c1, int p1, int p2, int p3) {

super(p1, p2, p3); // Call the constructor of class Parent System.out.println("Constructor classe Child");

this.c1 = c1;

}

// Destructor

protected void finalize() {

System.out.println("Destructor classe Child");

super.finalize(); // Call destructor of class Parent }

public void print() // Redefine the methode print of Parent

{

System.out.println("print() class Child");

super.print(); // call print() of class Parent

}

}

public class TestOrder

{

public static void main(String[] args)

{

Child child = new Child(1, 2, 3, 4); // Instanciate Child child.print();

child = null; // Release object child System.gc(); // Call Carbage Collection

}

}

Affichage sur l’écran: Constructor class Parent

Constructor class Child

print() class Child

print() class Parent

Destructor class Child

Destructor class Parent

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 53

Une instance de la classe Child est créée dans le programme principal. Le code du constructeur de la super classe est ainsi exécuté en premier, suivi de celui du constructeur de la sous-classe. L’instance child est libéré avec l’instruction « child = null » et éliminé à l’aide du collecteur d’ordure. Le code du destructeur de la sous-classe est ainsi exécuté en premier suivi du celui du destructeur de la super classe.

3.4.3 Les classes et méthodes abstraites Dans certain cas, des objets abstraits peuvent être obtenus de l’assemblage des propriétés communes de différentes classes dans une super classe. Ces supers classes sont alors qualifiées d’abstraites. Il n’existe ainsi pas d’objets géométriques concrets, mais seulement des cercles, des rectangles etc. Une méthode abstraite est une méthode, qui est déclarée uniquement avec sa signature, et doit par conséquent être implémentée dans la sous-classe. Propriétés des classes abstraites: • Chaque classe abstraite doit contenir au moins une méthode abstraite. • Il n’est possible de créer des instances à partir des classes abstraites. • Les méthodes abstraites doivent être implémentées dans les sous classes. • Un objet de la sous-classe ne peut être instancié que si cette dernière implémente toutes les méthodes

abstraites, héritées de la super classe. Ci cela n’est pas le cas, la sous classe est également une classe abstraite.

En Java les classes et les méthodes abstraites sont définies à l’aide du mot clé abstract : public abstract class SuperClass {

public abstract void method(); // Abstract method

}

public class SubClass extends SuperClass

{

public void method() // Implementation in the SubClass {

// Implementation

}

}

L’exemple des objets géométriques peut être complété à présent avec l’introduction d’une classe abstraite « GeometricalObject ». Cette classe doit contenir une méthode area() pour le calcul de la surface. Cette méthode est également abstraite, car il n’est pas possible de calculer la surface d’un objet géométrique sans en connaître la forme. La méthode area() doit ainsi être implémentée dans la sous-classe. La déclaration de la méthode area() fournit ici une interface commune pour toutes les objets géométriques. Ce sujet est traité plus en au chapitre 3.4.4. Exemple:

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 54

abstract

GeometricalObject x_coord y_coord isVisible GeometricalObject() setCoord() draw() move() area()

Circle radius Circle() area() getRadius()

Rectangle width height Rectangle() area() getWidth() getHeight()

Figure 8 : Diagramme de classe des objets géométriques

public abstract class GeometricalObject {

// Attribut

protected double x_coord;

protected double y_coord;

protected boolean isVisible;

// Constructor

GeometricalObject(double x, double y, boolean isVisible)

{

x_coord = x;

y_coord = y;

this.isVisible = isVisible;

}

public void setCoord(double x, double y)

{

x_coord = x;

y_coord = y;

}

public void draw()

{

// do something

}

public void move(double x, double y)

{

x_coord += x;

y_coord += y;

}

public abstract double area(); // Abstract methode

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 55

public class Circle extends GeometricalObject {

// Attribut

protected double radius;

protected static final double PI = 3.1415;

// Consructor

Circle(int x, int y, int r, boolean isVisible)

{

super(x, y, isVisible);

radius = r;

}

public double area() {return(radius * radius * PI);} // Implementation of area()

public double getRadius() {return(radius);}

}

public class Rectangle extends GeometricalObject {

// Attribut

protected double width;

protected double height;

// Constructor

Rectangle (double x, double y, double width, double height, boolean isVisible)

{

super(x, y, isVisible);

this.width = width;

this.height = height;

}

public double area() {return(width * height);} // Implementation of area() public double getWidth() {return(width);}

public double getHeight() {return(height);}

}

public class TestAbstract

{

public static void main(String[] args)

{

// Instanciate the objects

Rectangle rectangle = new Rectangle (1,3,10,5,true); Circle Circle = new Circle(3,7,5,true);

// Display the area

System.out.println("Rectangle area: " + rectangle.area()); System.out.println("Circle area: " + Circle.area()); }

}

Affichage sur l’écran: Rectangle area: 50.0

Circle area: 78.53750000000001

Dans l’exemple ci-dessus, la classe GeometricalObject et sa méthode area sont abstraites. Les classes Circle et Rectangle dérivent de cette super classe et implémentent par conséquent la méthodes area(), en fonction du calcul de leur surface. Pour chaque classe une instance est créée dans la méthode principale main() afin de tester l’appel de la méthode area().

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 56

3.4.4 Polymorphisme Le chapitre précédent illustre l’implémentation d’une méthode abstraite de la super classe dans une sous-classe. Mais il est également possible de sur écrire les méthodes héritées de la super classe dans une sous-classe. Cela est également connu sous le nom de Overriding. Chaque classe peut ainsi adapter spécifiquement une méthode pour son propre besoin, même si cette dernière a déjà été implémentée dans la super classe. Durant l’exécution du code, le mécanisme du polymorphisme appellera la méthode adéquate en fonction du type de l’objet. Le polymorphisme (appelé également association dynamique ou « late binding ») apporte les avantages suivants : • Le choix de la bonne méthode en fonction du type de l’objet se fait automatiquement durant exécution du

programme. Les distinctions de type de donnée dans le code pour effectuer le choix de la bonne méthode ne sont ainsi pas nécessaires.

• Les modifications de code sont beaucoup plus simples. Car il est possible d’hériter à partir des classes existantes et d’en modifier spécifiquement certaines méthodes par des opération de sur écriture.

Toutefois le polymorphisme possède également des désavantagés : • exécution du programme nécessite plus de ressources. Le code devient notamment plus lent, car la bonne

méthode doit être déterminée durant l’exécution du programme. • Le débuggage des méthodes appelées devient plus difficile. Dans l’exemple du chapitre 3.4.4, deux instances du type Circle et Rectangle ont été créées dans la méthode principale main(). Ensuite, la méthode area() a été appelé pour ces deux objets. Ce code n’est pas encore très élégant. A l’aide du polymorphisme les deux instances Circle et Rectangle peuvent être créées dans un container pour objets géométriques. La méthode area() pourra ainsi être appelée à partir de ces objets géométriques. Le choix de la bonne méthode s’effectuera automatiquement durant exécution du programme. C. à d. que pour l’objet Circle ce sera la méthode de la classe Circle et pour l’objet Rectangle la méthode de l’objet Rectangle . Exemple: public class TestPolymorphism

{

public static void main(String[] args)

{

GeometricalObject geo []; geo = new GeometricalObject[2]; geo[0] = new Rectangle (1,3,10,5,true); geo[1] = new Circle(3,7,5,true);

for (int i = 0; i < geo.length; i++)

System.out.println("Surface: " + geo[i].area());

}

}

Affichage sur l’écran: Surface : 50.0

Surface: 78.53750000000001

Un tableau pour deux objets géométriques est défini au début de l’exemple de ci dessus. Ensuite des instances de Rectangle et Circle sont créé et déposé dans ce tableau. La méthode area() est appelée pour chaque objet à l’aide d’un boucle à la fin de cet exemple. La bonne méthode sera défini automatiquement durant exécution du programme, c. à d. d’abord la méthode pour l’objet Rectangle et ensuite celle pour l’objet Circle. Ce code est très facile à entretenir : Des nouvelles classes peuvent être définies pour les objets géométriques (ex. Triangle) et leurs instances peuvent être déposées de la même manière dans le tableau.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 57

3.4.5 Les casting des classes Admettons que les classes Circle et Rectangle possèdent beaucoup de méthode en commun et qu’a coté elles possèdent des méthodes plus spécifiques, qui n’apparaissent que dans les sous-classes. Par exemple la classe Rectangle pourrait avoir une méthode rotate(), qui ne serait pas définie dans la classe Circle. Si les instances des objets étaient stockées dans un tableau, comme dans l’exemple du chapitre 3.4.4, le code suivant pour un rectangle serait faux et générerait une erreur de compilation : geo[0].rotate();

Ce code est faux, car la méthode rotate() n’est pas définie pour les objets géométriques. Il faut donc transformer l’objet géométrique en rectangle, afin de pouvoir en appeler la méthode rotate(). Cela est réalisé avec un opérateur cast de la manière suivante : ((Rectangle )geo[0]).rotate();

Ce code est dangereux car il peut être exécuté avec des objets du type Circle, qui ne possèdent pas la méthode rotate(). Ce qui va générer des exceptions du type ClassCastException durant l’exécution du programme. Il est donc nécessaire de vérifier le type de l’instance avant d’appeler la méthode rotate(). Cela peur être réalisé de la manière suivante : if(geo[0] instanceof Rectangle ) ((Rectangle )geo[0]).rotate();

Exemple : Le code de l’exemple 3.4.4 doit être complété de la manière suivante : • La classe rectangle ait une méthode rotate() • Le programme fournisse également la forme de l’objet géométrique durant la phase de calcul de la surface public class Rectangle extends GeometricalObject

{

// Attribute

protected double width;

protected double height;

// Constructor

Rectangle (double x, double y, double width, double height, boolean isVisible)

{

super(x, y, isVisible);

this.width = width;

this.height = height;

}

public double area() {return(width * height);}

public double getWidth() {return(width);}

public double getHeight() {return(height);}

public void rotate(int angle) {System.out.println("rotate");} }

public class TestClassCast

{

public static void main(String[] args)

{

GeometricalObject geo [];

geo = new GeometricalObject[2];

geo[0] = new Rectangle (1,3,10,5,true);

geo[1] = new Circle(3,7,5,true);

//geo[0].rotate(); // method rotate() is undefined ((Rectangle )geo[0]).rotate(30); // is ok

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 58

//((Rectangle )geo[1]).rotate(30); // ClassCastException

for (int i = 0; i < geo.length; i++)

{

if(geo[i] instanceof Rectangle ) System.out.println("Surface Rectangle : " + geo[i].area());

else if(geo[i] instanceof Circle) System.out.println("Surface Circle: " + geo[i].area());

}

}

}

Affichage sur l’écran: rotate

Surface Rectangle : 50.0

Surface Circle: 78.53750000000001

Au début du programme principal des essais de rotation ont lieu. Cela entraîne une erreur de compilation, car les objets géométriques ne possèdent pas de méthode rotate(). Il s’en suit une opération de cast sur le premier objet géométrique, qui modifie le type de ce dernier en Rectangle . Ce qui est correct, car le premier objet géométrique dans le tableau est un rectangle, et la méthode rotate() peut être appelé pour cet objet. Une seconde opération de cast est également exécutée sur le deuxième objet géométrique, qui est un Circle, pour en faire un Rectangle . Ce qui permet également d’appeler la méthode rotate()pour cet objet. Au niveau de la syntaxe cette instruction est absolument correcte. Toutefois, durant l’exécution du programme une exception du type ClassCastException sera lancée ici. Dans la boucle for, un control a lieu afin de déterminer le type de l’objet géométrique. Ce qui est la meilleure variante pour appeler les méthodes spécifiques aux classes. Remarque: Le casting n’est fondamentalement pas une forme élégante de codage. Toutefois, ce dernier ne peut pas toujours être évité. Dans ce cas, il faudrait d’abord réévaluer toutes les variantes du design avant d’utiliser un opérateur cast. Le casting peut être évité dans le code ci-dessus. Dans un premier temps il faudrait définir dans la classe GeometricalObject la méthode non abstraite rotate(), qui n’aurait aucune tâche. Cette méthode devrait alors être sur écrite dans la classe Rectangle. Dans un deuxième temps, le texte pour l’affichage de la surface devrait être transféré dans les sous classes.

3.5 Relation entre les classes Les classes peuvent avoir des relations différentes entre elles. Ces relations sont représenté dans les diagrammes de classe. Les relations les plus importantes sont les suivantes : Relation Description Diagramme de classe en UML Héritage "est un"

Cette relation découle de l’héritage. On dit: B est un A, lorsque B dérive de A. Exemple: Un Circle est un objet géométrique.

A

B

Aggregation "contient"

Un objet de la classe B fait partie d’un objet de la classe A, mais son existence ne dépend pas de celle de l’objet de la classe A. Exemple : Un étudiant possède une machine à calculer.

A B

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 59

Composition "possède"

Un objet de la classe B fait partie d’un objet de la classe A et son existence dépend de celle de l’objet de la classe A. Exemple: Un arbre possède un tronc et des racines.

A B

Association "utilise"

Une association est une relation structurelle entre deux classes. Exemple : La classe GraphicalObject peut utiliser la méthode print() de la classe Printer, pour afficher les objets géométriques.

A B

Figure 9 : Relation entre différentes classes

Remarque: Les relations entre les classes peuvent induire en erreur ! Un cercle n’est pas un point avec des propriétés supplémentaire, mais contient un point comme centre. Exemple: Une classe A doit posséder un attribut de la classe C. La classe C utilise la classe D pour s’afficher. Une classe B hérite les propriétés de la classe A.

A C c Method_A()

C Method_C()

D Method_D()

B Method_B()

Figure 10 : Diagramme de classe illustrant les relations entre les classes

public class D

{

public static void Method_D(String str)

{

System.out.println(str);

}

}

public class C

{

public void Method_C()

{

D.Method_D("Hallo"); }

}

public class A

{

C c; // Composition

A() { c = new C();} // Constructor

protected void Method_A()

{

c.Method_C(); }

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 60

public class B extends A

{

public static void main(String[] args)

{

B b = new B();

b.Method_A(); // Method of the super class }

}

Un objet de la classe B est instancié dans la méthode principale main(). La méthode Method_A() de la super classe y est ensuite appelée. Cela est possible car la classe B est une classe A et que, par conséquent, il hérite les méthodes de la super classe. La classe A possède un attribut de la classe C (composition), qui sera instancié dans son constructeur. L’existence de l’instance c dans A est ainsi identique à celle de l’objet b du programme principal. La méthode Method_C() de c est appelé dans la méthode Method_A(). Cette dernière appelle à son tour la méthode Method_D(), qui a été déclarée comme static dans la classe D. D est indépendant de C.

3.6 Les interfaces Le principe d’héritage a été introduit au chapitre 3.4. Toutefois, l’héritage multiple n’est pas soutenu en Java et, par conséquent, une classe ne peut étendre qu’une seule super classe. Exemple : Un programme contient une classe GeometricalObject et une classe Printer, qui contient une interface pour imprimante. Il n’est donc pas possible de définir une classe Rectangle, qui puisse hériter les propriétés de ces deux classes.

GeometricalObjet

Rectangle

Printer

Figure 11 : Héritage multiple n’est pas possible en Java

Ce problème peut être résolu à l’aide des interfaces (héritage d’interface). Une interface est une forme spéciale de classe, qui ne contient que les déclarations des méthodes et des constantes mais pas leurs implémentations (comme une classe abstraite, avec comme différence que cette dernière peut contenir des implémentations de méthode). Remarque pour les programmeurs C++. L’héritage multiple est soutenu dans C++. Par conséquent, C++ ne connaît pas les interfaces. La syntaxe pour définir une interface est la suivante : public interface Printer {

void method1(); }

La syntaxe de la classe qui implémente l’interface est la suivante : public class Name implements InterfaceName1, InterfaceName2 {

// Implementation of the interfaces:

void method1() { ... } ...

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 61

Les interfaces possèdent les propriétés suivantes : • Interfaces contient des méthodes et des constantes abstraites. Ces dernières définissent l’interface. • Une classe, qui implémente une interface, doit implémenter toutes les méthodes ce cette interface. • Une classe, qui implémente une interface, est alors du même type que cette interface. • Les classes dérivées peuvent également implémenter les interfaces. • Les interfaces peuvent être héritées. • Une classe peut implémenter plusieurs interfaces. Ces interfaces doivent être définies à la suite du mot clé

implements, séparée par des virgules UML : Une interface est représentée comme une classe. La flèche entre l’interface et l’implémentation est toutefois représentée en trait tillé.

A B

Figure 12 : La classe B implémente l’interface A

Exemple : L’exemple de l’introduction de ce chapitre doit être modifié : Une classe Rectangle hérite les propriétés de la super classe GeometricalObjet (voir chapitre 3.4.3) et implémente en même temps l’interface « Printer ».

abstract Printer

style print() feedPaper()

abstract GeometricalObject

x_coord y_coord isVisible GeometricalObject() setCoord() draw() move() area()

Rectangle width height Rectangle() area() getWidth() getHeight()

Figure 13 : Exemple pour interface

L’exemple suivant ne contient pas le code pour la classe GeometricalObject. En effet, ce dernier reste identique à celui du chapitre 3.4.3. // Declaration of the Interface public interface Printer {

public void print(String str); public void feedPaper();

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 62

public class Rectangle extends GeometrischesObjekt implements Printer {

// Attribute

protected double width;

protected double height;

// Constructor

Rectangle (double x, double y, double width, double height, boolean isVisible)

{

super(x, y, isVisible);

this.width = width;

this.height = height;

}

// Method

public double area() {return(width * height);}

public double getWidth() {return(width);}

public double getHeight() {return(height);}

// Implementation of the interface public void print(String str) {

System.out.println(str);

}

public void feedPaper(){};

}

// Application for test

public class TestInterface

{

public static void main(String[] args)

{

// Instanciate the object

Rectangle rectangle = new Rectangle (1,3,10,5,true);

// Print the area

rectangle.print("Area of rectangle: " + rectangle.area()); }

}

L’impression dans ce programme de test ne s’effectue pas sur imprimante mais sur écran : Area of rectangle: 50.0

Remarque: Dans cet exemple, il est également possible que la super classe GeometricalObject implémente l’interface Printer (ce qui est même recommandé). Ainsi, toutes les sous classes de GeometricalObject aurait également la méthode print().

3.7 Les paquets Un paquet (package) est une collection de différentes classes avec des fonctions semblables. Les paquets sont utilisés essentiellement dans des projets de plus grande importance, afin d’y améliorer la structure du programme. En cas de nécessité, des sous paquets peuvent également être définis. Les raisons suivantes justifient l’utilisation des paquets : • Ils une structure plus claire en rassemblant différentes classes. • Ils permettent d’identifier les classes dans des très grands projets. • Ils contrôlent la visibilité des classes, des méthodes et des attributs dans un projet.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 63

Les classes et les paquets peuvent être adressés de la manière suivante : packagename.classname

Ou : packagename.subpackagename.classname

Important: Les noms des paquets et des sous paquets correspondent toujours aux noms des répertoires, qui contiennent les fichiers du type classe de ces derniers. Ainsi le paquet « java.awt.image » se trouve dans le répertoire « java\awt\image ». La recherche de ces fichiers s’effectue toujours relatif au répertoire d’installation (par exemple « c:\java.1.4.2\bin »), dont le chemin d’accès est déposé dans les variables d’environnements CLASSPATH.

3.7.1 Utilisation et importation Avant de pouvoir utiliser une classe, il faut définir le paquet qui la contient de la manière suivante : 1) Indication du nom complet de la classe, paquet et éventuellement sous paquets inclus. 2) Importation de la classe au début de code avec le mot clé import. 3) Importation du paquet complet au début de code, également avec le mot clé import.

3.7.1.1 Indication du nom complet de la classe La classe est utilisée directement dans le programme avec l’indication de son nom en complet, paquet et éventuellement sous paquets : Package.Class variable = new Package.Class();

Ou : Package.Subpackage.Class variable = new Package.Subpackage.Class();

Exemple : public class Date01

{

public static void main(String[] args)

{

java.util.GregorianCalendar date = new java.util.GregorianCalendar(); System.out.println(date.getTime());

}

}

Affichage sur l’écran: Mon Feb 23 09:08:46 CET 2004

3.7.1.2 Importation de la classe au début du code La classe est importée au début du programme avec le mot clé import, en idiquant son nom complet : Exemple: // Importation of the class

import java.util.GregorianCalendar;

public class Date02

{

public static void main(String[] args)

{

GregorianCalendar date = new GregorianCalendar(); System.out.println(date.getTime());

}

}

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 64

3.7.1.3 Importation du paquet au début du code Le paquet contenant la classe est importé au début du programme avec le mot clé import. Cette variante exige moins visibilité de la part du programmeur. Elle ne demande également pas de mémoire, car la recherche de la classe ne s’effectue qu’au démarrage du programme. Exemple: // Importation of the package

import java.util.*;

public class Date03

{

public static void main(String[] args)

{

GregorianCalendar date = new GregorianCalendar(); System.out.println(date.getTime());

}

}

3.7.2 Les paquets mis à disposition par Java La bibliothèque standard de J2SDK fournit de nombreuses classes, qui sont réparties sur plus de 20 paquets. Les paquets les plus importants sont les suivants : java.applet Implémentation des applets java.awt Interfaces graphiques java.io Entrées et sorties standards et avec les fichiers java.lang Eléments généraux du langage, est importé implicitement au début de chaque classe java.net Pour les applications en réseaux java.util Pour l’utilisation des structures de données (calendrier, tabelle de Hash etc.)

3.7.3 Définition des paquets propres Les paquets propres peuvent être définis de la manière suivante : 1) Choix d’un nom significatif pour le paquet (nom doit commencé avec une minuscule) 2) Création de la structure de répertoire correspondante 3) Définition au début de chaque fichier (avec le mot clé package) du nom du paquet, auquel appartient la

classe Exemple : Il faut définir une classe Test_A dans le paquet « package1 ». Une seconde classe Test_B doit être également définie dans le sous paquet « package1_subpackage1 ». L’application est définie dans le répertoire principal dans le fichier « Test.java ». La structure du répertoire est la suivante :

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 65

PackageTest.java

package1

Test_A.java

package1_subpackage1

Test_B.java

Fichier PackageTest.java: // Importation of packages and subpackages

import package1.*; import package.subpackage1.*;

public class PackageTest

{

public static void main(String[] args)

{

// Instantiate and call object a of Test_A

Test_A a = new Test_A(); a.sayHello();

// Instantiate and call object of Test_B

new Test_B().sayHello(); }

}

Fichier Test_A.java: package package1;

public class Test_A

{

public void sayHello()

{

System.out.println("My name is Bond, ");

}

}

Fichier Test_B.java: package package1.subpackage1;

public class Test_B

{

public void sayHello()

{

System.out.println("James Bond");

}

}

Le paquet par défaut Le paquet par défaut est utilisé avec les classes, qui n’ont pas été attribué à un paquet. Toutes les classes, appartenant au paquet par défaut, peuvent être utilisées sans que cela soit spécifié explicitement.

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 66

3.7.4 Visibilité La visibilité en fonction des mots clés public, protected et private a également été décrite à la Figure 3 pour les paquets. Pour résumer il existe deux possibilité d’attacher une classe B à la classe A : 1) Soit A et B appartient au même paquet 2) B a été déclaré comme public Les deux classes se trouvent dans le même paquet avec l’utilisation des paquets par défaut. Ce qui économise la déclaration public.

3.8 Le design OO

3.8.1 UML Plusieurs tentatives pour essayer de définir une méthode de représentation de systèmes software orienté objet ont été effectuées jusqu’à la deuxième moitié des années 90. Les méthodes les plus connues étaient celles de Grady Booch, Ivar Jacobson et Jim Rumbaugh, qui ont essayé de définir indépendamment leur méthode de représentation. La société Rational Rose réussi alors d’engager ces trois « amigos », pour qu’ils essayent d’unissent leur méthode de représentation. Il en résulte alors le langage de modélisation unifié (en anglais : Unified Modeling Language, et abrégé par : UML), qui est une méthode pour décrire des systèmes universels (non seulement des systèmes software) de manière formelle. UML permet de visualiser un système de différentes manières. Les représentations, les plus importantes pour le développement des programmes, sont les suivantes : • Vision de l’utilisateur � modèle use-case • Vision de la structure statique du programme � Diagrammes des classes • Vision du système dynamique � Diagrammes d’état et de séquence Les diagrammes de classe ont été introduits dans les chapitres précédents. Un résumé se trouve au chapitre 3.5. Les chapitres suivants traitent la représentation des paquets et les diagrammes de séquence.

3.8.1.1 Les paquets Les diagrammes des paquets sont utilisés pour représenter la hiérarchie des paquets et notamment leur emboîtement (Subpackages). Un diagramme des paquets peut être défini de la manière suivante :

Package 2

Package 4

Package 1

Package 3

Package 4

Héritage

Relation de compilation

Class 1 Class 2

Class 3

Figure 14 : Diagramme des paquets

Introduction à la programmation Java Introduction à la POO avec Java

Version 1.0, 05.03.07 Page 67

3.8.1.2 Les diagramme de séquence Les diagrammes de séquence permettent une vision dynamique du système. Les diagrammes de séquences montrent l’ordre dans lequel les objets appèlent les autres objets.

5. operation

4. operation (parameter list)

2. operation 3. operation (parameter list)

1. event

Object1:Class name

Object2 Object3 Object4

Figure 15: Diagramme de séquence

Les diagrammes de séquence possèdent 2 dimensions. L’axe verticale représente normalement le temps. Les poutres grises illustrent la durée de vie des objets. Les différents objets sont représentés sur l’axe horizontal. Les appels mutuels des objets sont représentés par des flèches.