Cours gratuits » Cours informatique » Cours programmation » Cours JAVA » Cours de JAVA et les bases de donnees pas a pas

Cours de JAVA et les bases de donnees pas a pas

Problème à signaler:

Télécharger



★★★★★★★★★★1 étoiles sur 5 basé sur 1 votes.
1 stars
1 votes

Votez ce document:

Cours de JAVA et les bases de donnees pas à pas

...

Une classe suffit

Les méthodes sont des fonctions

Transmission des paramètres en Java Visibilité des variables

Avant d'utiliser les possibilités offertes par les classes et les objets en Java, apprenons à utiliser et exécuter des applications simples Java ne nécessitant pas la construction de nouveaux objets, ni de navigateur pour s'exécuter.

Comme Java est un

langage orienté objet, un programme Java est composé de plusieurs classes, nous nous limiterons à une seule classe.

1 - Une classe suffit

On peut très grossièrement assimiler un programme Java ne possédant qu'une seule classe, à un programme principal classique d'un langage de programmation algorithmique.

  • Une classe minimale commence obligatoirement par le mot class suivi de l'identificateur de la classe puis du corps d'implémentation de la classe dénommé bloc de classe.
  • Le bloc de classe est parenthésé par deux accolades "{" et "}".

Syntaxe d'une classe exécutable Exemple1 de classe minimale :

class Exemple1 { }

Cette classe ne fait rien et ne produit rien.

Comme en fait, une classe quelconque peut s'exécuter toute seule à condition qu'elle possède dans ses déclarations internes la méthode main qui sert à lancer l'exécution de la classe (fonctionnement semblable au lancement du programme principal).

Exemple2 de squelette d'une classe minimale exécutable :

class Exemple2

{

public static void main(String[ ] args)

{ // c'est ici que vous écrivez votre programme principal

}

}

Exemple3 trivial d'une classe minimale exécutable :

class Exemple3

{

public static void main(String[ ] args)

{ System.out.println("Bonjour !");

}

}

Exemples d'applications à une seule classe

Nous reprenons deux exemples de programme utilisant la boucle for, déjà donnés au chapitre sur les instructions, cette fois-ci nous les réécrirons sous la forme d'une application exécutable.

Exemple1

class Application1

{

public static void main(String[ ] args)

{ /* inverse d'une suite de caractère dans un tableau par

permutation des deux extrêmes */

char [ ] Tablecar ={'a','b','c','d','e','f'} ;

int i, j ;

System.out.println("tableau avant: " + String.valueOf(Tablecar));

for ( i = 0 , j = 5 ; i<j ; i++ , j-- )

{ char car ;

car = Tablecar[i];

Tablecar[i ]= Tablecar[j];

Tablecar[j] = car;

}

System.out.println("tableau après: " + String.valueOf(Tablecar));

}

}

Il est impératif de sauvegarder la classe dans un fichier qui porte le même nom (majuscules et minuscules inclues) ici "Application1.java". Lorsque l'on demande la compilation (production du bytecode) de ce fichier source "Application1.java" le fichier cible produit en bytecode se dénomme "Application1.class", il est alors prêt à être interprété par une

 machine virtuelle java.

Le résultat de l'exécution de ce programme est le suivant :

tableau avant: abcdef tableau après: fedcba

Exemple2

class Application2

{

public static void main(String[ ] args)

{ // recherche séquentielle dans un tableau

int [ ] table= {12,-5,7,8,-6,6,4,78};

int elt = 4, i ;

for ( i = 0 ; i<8 ; i++ )

if (elt= =table[i]) break;

if (i = = 8) System.out.println("valeur : "+elt+" pas trouvée.");

else System.out.println("valeur : "+elt+" trouvée au rang :"+i);

}

}

Après avoir sauvegardé la classe dans un fichier qui porte le même nom (majuscules et minuscules incluses) ici "Application2.java", la compilation de ce fichier "Application2.java" produit le fichier "Application2.class" prêt à être interprété par notre machine virtuelle java.

Le résultat de l'exécution de ce programme est le suivant :

valeur: 4 trouvée au rang :6

Conseil de travail:

Reprenez tous les exemples simples du chapitre sur les instructions de boucle et le switch en les intégrant dans une seule classe (comme nous venons de le faire avec les deux exemples précédents) et exécutez votre programme.

2 - Les méthodes sont des fonctions

Les méthodes ou fonctions représentent une encapsulation des instructions qui déterminent le fonctionnement d'une classe. Sans méthodes pour agir, une classe ne fait rien de particulier, dans ce cas elle ne fait que contenir des attributs.

Méthode élémentaire de classe

Bien que Java distingue deux sortes de méthodes : les méthodes de classe et les méthodes d'instance, pour l'instant dans cette première partie nous décidons à titre pédagogique et simplificateur de n'utiliser que les méthodes de classe, l'étude du chapitre sur Java et la programmation orientée objet apportera les compléments adéquats sur les méthodes d'instances.

Une méthode de classe commence obligatoirement par le mot clef static.

Donc par la suite dans ce chapitre, lorsque nous emploierons le mot méthode sans autre adjectif, il s'agira d'une méthode de classe, comme nos application ne possèdent qu'une seule classe, nous pouvons assimiler ces méthodes aux fonctions de l'application et ainsi retrouver une utilisation classique de Java en mode application.

Déclaration d'une méthode

La notion de fonction en Java est semblable à celle du C et à Delphi, elle comporte une en-tête avec des paramètres formels et un corps de fonction ou de méthode qui contient les instructions de la méthode qui seront exécutées lors de son appel. La déclaration et l'implémentation doivent être consécutives comme l'indique la syntaxe ci-dessous :

Syntaxe :

corps de fonction :

Nous dénommons en-tête de fonction la partie suivante :

<qualificateurs><type du résultat><nom de fonction> (<liste paramètres formels>)

Sémantique :

  • Les qualificateurs sont des mots clefs permettant de modifier la visibilité ou le fonctionnement d'une méthode, nous n'en utiliserons pour l'instant qu'un seul : le mot clef static permettant de désigner la méthode qu'il qualifie comme une méthode de classe dans la classe où elle est déclarée. Une méthode n'est pas nécessairement qualifiée donc ce mot clef peut être omis.
  • Une méthode peut renvoyer un résultat d'un type Java quelconque en particulier d'un des types élémentaires (int, byte, short, long, boolean, double, float, char) et nous verrons plus loin qu'elle peut renvoyer un résultat de type objet comme en Delphi. Ce mot clef ne doit pas être omis.
  • Il existe en Java comme en C une écriture fonctionnelle correspondant aux procédures des langages procéduraux : on utilise une fonction qui ne renvoie aucun résultat. L'approche est inverse à celle du pascal où la procédure est le bloc fonctionnel de base et la fonction n'en est qu'un cas particulier. En Java la fonction (ou méthode) est le seul bloc fonctionnel de base et la procédure n'est qu'un cas particulier de fonction dont le retour est de type void.
  • La liste des paramètres formels est semblable à la partie déclaration de variables en Java (sans initialisation automatique). La liste peut être vide.
  • Le corps de fonction est identique au bloc instruction Java déjà défini auparavant. Le corps de fonction peut être vide (la méthode ne représente alors aucun intérêt).

Exemples d'en-tête de méthodes sans paramètres en Java

int calculer( ){                   }              renvoie un entier de type int

boolean tester( ){                           }              renvoie un entier de type boolean

void uncalcul( ){                              }              procédure ne renvoyant rien

Exemples d'en-tête de méthodes avec paramètres en Java

int calculer(byte a, byte b, int x )

{              }              fonction à 3 paramètres

boolean tester( int k)

{              }              fonction à 1 paramètre

void uncalcul(int x, int y, int z )

{              }              procédure à 3 paramètres

Appel d'une méthode

L'appel de méthode en Java s'effectue très classiquement avec des paramètres effectifs dont le nombre doit obligatoirement être le même que celui des paramètres formels et le type doit être soit le même, soit un type compatible ne nécessitant pas de transtypage.

 Exemple d'appel de méthode-procédure sans paramètres en Java

class Application3 {                         Appel de la méthode afficher

public static void main(String[ ] args)

{

afficher( );

}

static void afficher( )

{

System.out.println("Bonjour");

}

}                             

Exemple d'appel de méthode-procédure avec paramètres de même type en Java

class Application4

{ public static void main(String[ ] args)

{ // recherche séquentielle dans un tableau

int [ ] table= {12,-5,7,8,-6,6,4,78};

long elt = 4;

int i ;

for( i = 0 ; i<=8 ; i++ )

if (elt= =table[i]) break;

afficher(i,elt);

1

static void afficher (int rang , long val)

{ if (rang == 8)

System.out.println("valeur : "+val+" pas

trouvée.");

else

System.out.println("valeur : "+val+" trouvée

au rang :"+ rang);

1

1

3 - Transmission des paramètres

Rappelons tout d'abord quelques principes de base :

Dans tous les langages possédant la notion de sous-programme (ou fonction ou procédure), il se pose une question à savoir, les paramètres formels décrits lors de la déclaration d'un sous-programme ne sont que des variables muettes servant à expliquer le fonctionnement du sous-programme sur des futures variables lorsque le sous-programme s'exécutera effectivement.

La démarche en informatique est semblable à celle qui, en mathématiques, consiste à écrire la fonction f(x) = 3*x - 7, dans laquelle x alors une variable muette indiquant comment f est calculée : en informatique elle joue le rôle du paramètre formel. Lorsque l'on veut obtenir une valeur effective de la fonction mathématique f, par exemple pour x=2, on écrit f(2) et l'on calcule f(2)=3*2 - 7 = -1. En informatique on "passera" un paramètre effectif dont la valeur vaut 2 à la fonction. D'une manière générale, en informatique, il y a un sous-programme appelant et un sous-programme appelé par le sous-programme appelant.

Compatibilité des types des paramètres

Resituons la compatibilité des types entier et réel en Java. Un moyen mnémotechnique pour retenir cette compatibilité est indiqué dans les figures ci-dessous, par la taille en nombre décroissant de bits de chaque type que l'on peut mémoriser sous la forme "qui peut le plus peut le moins" ou bien un type à n bits accueillera un sous-type à p bits, si p est inférieur à n.

Les types entiers compatibles : Les types réels compatibles :

Exemple d'appel de la même méthode-procédure avec paramètres de type compatibles en Java

class Application5

{ public static void main(String[ ] args)

{ // recherche séquentielle dans un tableau

int [ ] table= {12,-5,7,8,-6,6,4,78};

byte elt = 4;

short i ;

for( i = 0 ; i<8 ; i++ )

if (elt= =table[i]) break;

afficher(i,elt);                   Appel de la méthode afficher afficher(i,elt);

Les deux paramètres effectifs "i" et "elt" sont d'un type compatible avec celui du paramètre formel associé.

- Le paramètre effectif "i" est associé au paramètre formel rang.(short = entier signé sur 16 bits et int = entier signé sur 32 bits)

}

static void afficher (int rang , long val) { if (rang == 8)                    

System.out.println("valeur : "+val+" pas trouvée.");

else

System.out.println("valeur : "+val+" trouvée au rang :"+ rang);                               - Le paramètre effectif "elt" est associé au paramètre formel val.(byte = entier signé sur 8 bits et long = entier signé sur 64 bits)

} }                          

Les deux modes de transmission des paramètres

Un paramètre effectif transmis au sous-programme appelé est en fait un moyen d’utiliser ou d’accéder à une information appartenant au bloc appelant (le bloc appelé peut être le même que le bloc appelant, il s’agit alors de récursivité).

En Java, il existe deux modes de transmission (ou de passage) des paramètres (semblables à Delphi).

Le passage par valeur uniquement réservé à tous les types élémentaires (int, byte, short, long, boolean, double, float, char).

Le passage par référence uniquement réservé à tous les types objets.

Remarque :

Le choix de passage selon les types élimine les inconvénients dûs à l'encombrement mémoire et à la lenteur de recopie de la valeur du paramètre par exemple dans un passage par valeur, car nous verrons plus loin que les tableaux en Java sont des objets et qu'ils sont donc passés par référence.

Les retours de résultat de méthode-fonction

Les méthodes en Java peuvent renvoyer un résultat de n'importe quel type élémentaire ou objet. Bien qu'une méthode ne puisse renvoyer qu'un seul résultat, l'utilisation du passage par référence d'objets permet aussi d'utiliser les paramètres de type objet d'une méthode comme des variables d'entrée/sortie.

En Java le retour de résultat est passé grâce au mot clef return placé n'importe où dans le corps de la méthode.

Syntaxe :

Sémantique :

  • L'expression lorsqu'elle est présente est quelconque mais doit être obligatoirement du même type que le type du résultat déclaré dans l'en-tête de fonction (ou d'un type compatible).
  • Lorsque le return est rencontré il y a arrêt de l'exécution du code de la méthode et retour du résultat dans le bloc appelant.
  • Lorsqu'il n'y a pas d'expression après le return, le compilateur refusera cette éventualité sauf si vous êtes dans une méthode-procédure (donc du type void), le return fonctionne comme un break pour la méthode et interrompt son exécution.

Exemple la fonction f(x)=3x-7

class Application6

{ public static void main(String[ ] args) { // ...

int x , y ;

x = 4 ;

y = f(5) ;

y = f(x) ;

System.out.println("f(x)="+ f(x) ); System.out.println("f(5)="+ f(5) );                  Appel de la méthode f

f ( 5 ) ; ou bien f ( x ) ;

Dans les deux cas la valeur 5 ou la valeur 4 de x est recopiée dans la zone de pile de la machine virtuelle java.

}

static int f (int x )

{ return 3*x-7;

}

}                             

Exemple de méthode-procédure

class Application7

{ public static void main(String[ ] args) {                               Appel de la méthode procedure

Dans le cas du premier appel (x ==0) est true donc ce sont les instructions: System.out.println("avant return"); return ;

qui sont exécutées, puis interruption de la méthode.

int a = 0 ;

procedure ( a );

procedure ( a+4 );

}

static void procedure(int x)                       

{

if (x = = 0)

{ System.out.println("avant return");

return ;

}

System.out.println("après return");

}

}                              Dans le cas du second appel (x ==0) est false c'est donc l'instruction: System.out.println("avant return"); qui est exécutée, puis fin normale de la méthode.

4 - Visibilités des variables

Le principe de base est que les variables en Java sont visibles (donc utilisables) dans le bloc dans lequel elles ont été définies.

Visibilité de bloc

Java est un langage à structure de blocs ( comme pascal et C ) dont le principe général de visibilité est :

Toute variable déclarée dans un bloc est visible dans ce bloc et dans tous les blocs imbriqués dans ce bloc.

En java les blocs sont constitués par :

  • les classes,
  • les méthodes,
  • les instructions composées,
  • les corps de boucles,
  • les try...catch

Le masquage des variables n'existe que pour les variables déclarées dans des méthodes :

Il est interdit de redéfinir une variable déjà déclarée dans une méthode soit :

comme paramètre de la méthode,

comme variable locale à la méthode,

dans un bloc inclus dans la méthode.

Il est possible de redéfinir une variable déjà déclarée dans une classe.

Variables dans une classe, dans une méthode

Les variables définies (déclarées, et/ou initialisées) dans une classe sont accessibles à toutes les méthodes de la classe, la visibilité peut être modifiée par les qualificateurs public ou private que nous verrons au chapitre POO.

Exemple de visibilité dans une classe

class ExempleVisible1 { int a = 10;                           La variable "a" définie dans int a =10; :

                               - Est une variable de la classe ExempleVisible.

int g (int x )                       

                { return 3*x-a; }               - Elle est visible dans la méthode g et dans la méthode f. C'est elle qui est utilisée dans la méthode g pour évaluer l'expression 3*x-a.

- Dans la méthode f, elle est masquée par le paramètre du même nom qui est utilisé pour évaluer l'expression 3*x-a.

}              int f (int x, int a ) { return 3*x-a; }           

Contrairement à ce que nous avions signalé plus haut nous n'avons pas présenté un exemple fonctionnant sur des méthodes de classes (qui doivent obligatoirement être précédées du mot clef static), mais sur des méthodes d'instances dont nous verrons le sens plus loin en POO.

Remarquons avant de présenter le même exemple cette fois-ci sur des méthodes de classes, que quelque soit le genre de méthode la visibilité des variables est identique.

Exemple identique sur des méthodes de classe

class ExempleVisible2 { static int a = 10;                               La variable "a" définie dans static int a =10; :

                               - Est une variable de la classe ExempleVisible.

- Elle est visible dans la méthode g et dans la méthode f. C'est elle qui est utilisée dans la méthode g pour évaluer l'expression 3*x-a.

- Dans la méthode f, elle est masquée par le paramètre du même nom qui est utilisé pour évaluer l'expression 3*x-a.

static int g (int x ) { return 3*x-a; }

static int f (int x, int a ) { return 3*x-a; }

}                             

Les variables définies dans une méthode (de classe ou d'instance) subissent les règles classiques de la visibilité du bloc dans lequel elles sont définies :

Elles sont visibles dans toute la méthode et dans tous les blocs imbriqués dans cette méthod et seulement à ce niveau (les autres méthodes de la classe ne les voient pas), c'est pourquoi on emploie aussi le terme de variables locales à la méthode.

Reprenons l'exemple précédent en adjoignant des variables locales aux deux méthodes f et g. Exemple de variables locales

class ExempleVisible3 { static int a = 10;                               La variable de classe "a" définie dans static int a = 10; est masquée dans les deux méthodes f et g.

static int g (int x )                           

                { char car = 't'; long a = 123456; ....

return 3*x-a;     Dans la méthode g, c'est la variable locale longa = 123456 qui masque la variable de classe static int a. char car ='t'; est une variable locale à la méthode g.

                }

static int f (int x, int a )

{ char car ='u';

....

return 3*x-a;

}             

}                              - Dans la méthode f, char car ='u'; est une variable locale à la méthode f, le paramètre inta masque la variable de classe static int a.

Les variables locales char car n'existent que dans la méthode où elles sont définies, les variables "car" de f et celle de g n'ont aucun rapport entre elles, bien que portant le même nom.

Variables dans un bloc autre qu'une classe ou une méthode

Les variables définies dans des blocs du genre instructions composées, boucles, try..catch ne sont visibles que dans le bloc et ses sous-blocs imbriqués, dans lequel elle sont définies.

Toutefois attention aux redéfinitions de variables locales. Les blocs du genre instructions composées, boucles, try..catch ne sont utilisés qu'à l'intérieur du corps d'une méthode (ce sont les actions qui dirigent le fonctionnement de la méthode), les variables définies dans de tels blocs sont automatiquement considérées par Java comme des variables locales à la méthode. Tout en respectant à l'intérieur d'une méthode le principe de visibilité de bloc, Java n'accepte pas le masquage de variable à l'intérieur des blocs imbriqués.

Nous donnons des exemples de cette visibilité : Exemple correct de variables locales

class ExempleVisible4 { static int a = 10, b = 2; static int f (int x ) { char car = 't';

for (int i = 0; i < 5 ; i++) {int a=7;

if (a < 7) {int b = 8; b = 5-a+i*b;

La variable de classe "a" définie dans static int a = 10; est masquée dans la méthode f dans le bloc imbriqué for.

La variable de classe "b" définie dans static int b = 2; est masquée dans la méthode f dans le bloc imbriqué if.

Dans l'instruction { intb = 8; b = 5-a+i*b; } , c'est la variable b interne à ce bloc qui est utilisée car elle masque la variable b de la classe.

Dans l'instruction else b = 5-a+i*b; , c'est la variable b de la classe qui est utilisée (car la variable int b = 8 n'est plus visible ici) .

Exemple de variables locales générant une erreur

Toutes les remarques précédentes restent valides puisque l'exemple ci-contre est quasiment identique au précédent. Nous avons seulement rajouté dans le bloc if la définition d'une nouvelle variable interne a à ce bloc.

Java produit une erreur de compilation int b = 8, a = 9; sur la variable a, en indiquant que c'est une redéfinition de variable à l'intérieur de la méthode f, car nous avions déjà défini une variable a ({ int a=7;...) dans le bloc englobant for {...}.

Remarquons que le principe de visibilité des variables adopté en Java est identique au principe inclus dans tous les langages à structures de bloc y compris pour le masquage, s'y rajoute en Java uniquement l'interdiction de la redéfinition à l'intérieur d'une même méthode (semblable en fait, à l'interdiction de redéclaration sous le même nom, de variables locales à un bloc).

Synthèse : utiliser une méthode static dans une classe

v             Les méthodes représentent les actions

En POO, les méthodes d'une classe servent à indiquer comment fonctionne un objet dans son environnement d'exécution. Dans le cas où l'on se restreint à utiliser Java comme un langage algorithmique, la classe représentant le programme principal, les méthodes représenteront les sous programmes du programme principal. C'est en ce sens qu'est respecté le principe de la programmation structurée.

Attention, il est impossible en Java de déclarer une méthode à l'intérieur d'une autre méthode comme en pascal; toutes les méthodes sont au même niveau de déclaration : ce sont les méthodes de la classe !

Typiquement une application purement algorithmique en Java aura donc cette forme : (un programme principal "main" et ici, deux sous-programmes methode1 et methode2)

Les méthodes type procédure (méthode pouvant avoir plusieurs paramètres en entrée, mais ne renvoyant pas de résultat) sont précédées du mot clef void :

 Les autres méthodes (précédées d'un mot clef typé comme : int, char, byte, boolean,...) sont des fonctions pouvant avoir plusieurs paramètres en entrée qui renvoient obligatoirement un résultat du type déclaré par le mot clef précédant le nom de la fonction :

 La méthode précédente possède 2 paramètres en entrée int a et char b, et renvoie un paramètre de type int.

v             Les paramètres Java sont passés par valeur

Le passage des paramètres par valeur entre un programme appelant (main ou tout autre méthode) et un sous programme (les méthodes) s'effectue selon le schéma ci-dessous :

En Java tous les paramètres sont passés par valeur (même si l'on dit que Java passe les objets par référence, en fait il s'agit très précisément de la référence de l'objet qui est passée par valeur). Pour ce qui est de la vision algorithmique de Java, le passage par valeur est la norme.

Ainsi aucune variable ne peut être passée comme paramètre à la fois d'entrée et de sortie comme en Pascal.

Comment faire en Java si l'on souhaite malgré tout passer une variable à la fois en entrée et en sortie ?

Il faut la passer comme paramètre effectif (passage par valeur ), et lui réaffecter le résultat de la fonction. L'exemple suivant indique comment procéder : soit la méthode précédente recevant un int et un char et renvoyant un int

Les instructions ci-après permettent de modifier la valeur d'une variable x à l'aide de la méthode "methode2" :

int x = 10;

// avant l'appel x vaut 10 x = methode2 ( x , '@');

// après l'appel x vaut 15

v             Appeler une méthode en Java

  1. Soit on appelle la méthode comme une procédure en Pascal (avec ses paramètres effectifs éventuels), soit on l'appelle comme une fonction en utilisant son résultat. Reprenons les deux méthodes précédentes et appelons les :
  2. Soit on peut appeler ces deux méthodes dans la méthode "main" :
  3. Soit on peut les appeler dans une autre méthode "methode3" :

v             Exemple de programme : calcul d'une somme avec méthodes procédure et fonction

 Résultats d'exécution de ce programme: Bonjour

Somme = 12

La classe String

Le type de données String (chaîne de caractère) n'est pas un type élémentaire en Java, c'est une classe. Donc une chaîne de type String est un objet qui n'est utilisable qu'à travers les méthodes de la classe String.

Pour accéder à la classe String et à toutes ses méthodes, vous devez mettre avant la déclaration de votre classe l'instruction d'importation de package suivante :

import java.lang.String ;

Un littéral de chaîne est une suite de caractères entre guillemets : " abcdef " est un exemple de littéral de String.

Etant donné que cette classe est très utilisée les variables de type String bénéficient d'un statut d'utilisation aussi souple que celui des autres types élémentaires. On peut les considérer comme des listes de caractères numérotés de 0 à n-1 (si n figure le nombre de caractères de la chaîne).

Déclaration d'une variable String             String str1;

Déclaration d'une variable String avec initialisation         String str1 = " abcdef "; Ou

String str1 = new String("abcdef ");

On accède à la longueur d'une chaîne par la méthode :

int length( )        String str1 = "abcdef"; int longueur;

longueur = str1.length( ); // ici longueur vaut 5

Toutefois les String de Java sont moins conviviales en utilisation que les string de pascal ou celles de C#, il appartient au programmeur d'écrire lui-même ses méthodes d'insertion, modification et suppression.

Toutes les autres manipulations sur des objets String nécessitent l'emploi de méthodes de la classe String. Nous donnons quelques exemples d'utilisation de méthode classique sur les String.

Le type String possède des méthodes classiques d'extraction, de concaténation, de changement de casse, etc.

Concaténation de deux chaînes Un opérateur ou une méthode Opérateur : + sur les chaînes ou

Méthode : String concat(String s)

Les deux écritures ci-dessous sont donc équivalentes en Java :

str3 = str1+str2 C* str3 = str1.concat(str2)           String str1,str2,str3; str1="bon"; str2="jour"; str3=str1+str2;

On accède à un caractère de rang fixé d'une chaîne par la méthode :

char charAt(int rang)

Il est possible d'accéder en lecture seulement à chaque caractère d'une chaîne, mais qu'il est impossible de modifier un caractère directement dans une chaîne.       String ch1 = "abcdefghijk                                                            ";                                                          

char car = ch1.charAt(4);

// ici la variable car contient la lettre 'e'

position d'une sous-chaîne à l'intérieur d'une chaîne donnée :

méthode :

int indexOf ( String ssch)             String ch1            = "                          abcdef                 "              ,                              ssch=

"cde";

int rang ;

rang = ch1.indexOf ( ssch );

// ici la variable rang vaut 2

Les fondements du langage Java - ( rév. 28.05.2005 )     page 69

Les String Java ne peuvent pas être considérées comme des tableaux de caractères, il est nécessaire, si l'on souhaite se servir d'une String, d'utiliser la méthode toCharArray pour convertir la chaîne en un tableau de caractères contenant tous les caractères de la chaîne.

Enfin, attention ces méthodes de manipulation d'une chaîne ne modifient pas la chaîne objet qui invoque la méthode mais renvoient un autre objet de chaîne différent. Ce nouvel objet est obtenu après action de la méthode sur l'objet initial.

Soient les quatre lignes de programme suivantes :

String str1 = "abcdef" ;

char [ ] tCarac ;

tCarac = str1.toCharArray( ) ;

tCarac = "abcdefghijk".toCharArray( );

Illustrons ci-dessous ce qui se passe relativement aux objets créés :

String str1 = "abcdef" ;                 chaîne.

                               objet de             

                str1 référence un                          

char [ ] tCarac ;

tCarac = str1.toCharArray( ) ;                     tableau à 6

un objet de       

                tCarac référence éléments.                      

tCarac = "abcdefghijk".toCharArray( );                                                

tCarac référence tableau à 11 éléments, perdu (éligible              maintenant un nouvel objet de l'objet précédent est au Garbage collector)   

L'exemple précédent sur la concaténation ne permet pas de voir que l'opérateur + ou la méthode concat renvoie réellement un nouvel objet en particulier lors de l'écriture des quatre lignes suivantes :

String str1,str2; str1="bon";

str2="jour";

str1=str1+str2;

Illustrons ici aussi ce qui se passe relativement aux objets créés :

String str1,str2; str1="bon"; str2="jour";                            

str1=str1+str2; 

                un nouvel objet de chaîne a été créé et str1 "pointe" maintenant vers lui.

Opérateurs d'égalité de String

v             L'opérateur d'égalité = = , détermine si deux objets String spécifiés ont la même référence et non la même valeur, il ne se comporte pas en Java comme sur des éléments de type de base (int, char,...)

String a , b ;

(a = = b ) renvoie true si les variables a et b référencent chacune le même objet de chaîne sinon il renvoie false.

v             La méthode boolean equals(Object s) teste si deux chaînes n'ayant pas la même référence ont la même valeur.

String a , b ;

a.equals ( b ) renvoie true si les variables a et b ont la même valeur sinon il renvoie false.

En d'autres termes si nous avons deux variables de String ch1 et ch2, que nous ayons écrit ch1 = "abcdef"; et plus loin ch2 = "abcdef"; les variables ch1 et ch2 n'ont pas la même référence mais ont la même valeur (valeur = "abcdef").

Voici un morceau de programme qui permet de tester l'opérateur d'égalité = = et la méthode equals :

String s1,s2,s3,ch; ch = "abcdef";

s1 = ch;

s2 = "abcdef";

s3 = new String("abcdef".toCharArray( ));

System.out.println("s1="+s1); System.out.println ("s2="+s2); System.out.println ("s3="+s3); System.out.println ("ch="+ch); if( s1 == ch ) System.out.println ("s1=ch");

else System.out.println ("s1<>ch");

if( s1 == s3 ) System.out.println ("s1=s3");

else System.out.println ("s1<>s3");

if( s1.equals(s2) ) System.out.println ("s1 même val. que s2"); else System.out.println ("s1 différent de s2");

if( s1.equals(s3) ) System.out.println ("s1 même val. que s3"); else System.out.println ("s1 différent de s3");

if( s1.equals(ch) ) System.out.println ("s1 même val. que ch"); else System.out.println ("s1 différent de ch");

Après exécution on obtient :

ATTENTION

En fait, Java a un problème de cohérence avec les littéraux de String. Le morceau de programme ci-dessous montre cinq évaluations équivalentes de la String s2 qui contient après l'affectation la chaîne "abcdef", puis deux tests d'égalité utilisant l'opérateur = = . Nous avons mis en commentaire, après chacune des cinq affectations, le résultat des deux tests :

String ch;

ch = "abcdef" ;

String s2,s4="abc" ;

s2 = s4.concat("def") ; /* après tests : s2<>abcdef, s2<>ch */ s2 = "abc".concat("def"); /* après tests : s2<>abcdef, s2<>ch */ s2 = s4+"def"; /* après tests : s2<>abcdef, s2<>ch */

s2="abc"+"def"; /* après tests : s2 ==abcdef, s2 == ch */ s2="abcdef"; /* après tests : s2 == abcdef, s2 == ch */

//-- tests d'égalité avec l'opérateur = =

if( s2 == "abcdef" ) System.out.println ("s2==abcdef");

else System.out.println ("s2<>abcdef");

if( s2 == ch ) System.out.println ("s2==ch");

else System.out.println ("s2<>ch");

Nous remarquons que selon que l'on utilise ou non des littéraux les résultats du test ne sont pas les mêmes.

CONSEIL

Pour éviter des confusions et mémoriser des cas particuliers, il est conseillé d’utiliser la méthode equals pour tester la valeur d'égalité de deux chaînes.

Rapport entre String et char

Une chaîne String contient des éléments de base de type char comment passe-t-on de l'un à l'autre type.

1°) On ne peut pas considérer un char comme un cas particulier de String, le transtypage suivant est refusé :

char car = 'r'; String s;

s = (String)car;

Les fondements du langage Java - ( rév. 28.05.2005 )     page 73

Il faut utiliser la méthode de conversion valueOf des String :

s = String.valueOf(car);

2°) On peut concaténer avec l'opérateur +, des char à une chaîne String déjà existante et affecter le résultat à une String :

String s1 , s2 ="abc" ; char c = 'e' ; s1 = s2 + 'd' ; s1 = s2 + c ;

L'écriture suivante sera refusée :            Ecriture correcte associée :

String s1 , s2 ="abc" ; char c = 'e' ;

s1 = 'd' + c ; // types incompatibles s1 = 'd' + 'e'; // types incompatibles               String s1 , s2 ="abc" ; char c = 'e' ;

s1 = "d" + String.valueOf (c) ; s1 = "d" + "e";

v             Le caractère 'e' est de type char,

v             La chaîne "e" est de type String (elle ne contient qu'un seul caractère)

Pour plus d'information sur toutes les méthode de la classe String voici telle qu'elle est présentée par Sun dans la documentation du JDK 1.4.2 (http://java.sun.com), la liste des méthodes de cette classe.

Les fondements du langage Java - ( rév. 28.05.2005 )     page 74

Dès que l'on travaille avec de nombreuses données homogènes ( de même type) la première structure de base permettant le regroupement de ces données est le tableau. Java comme tous les langages algorithmiques propose cette structure au programmeur. Comme pour les String, pour des raisons d'efficacité dans l'encombrement mémoire, les tableaux sont gérés par Java, comme des objets.

  • Les tableaux Java sont comme en Delphi, des tableaux de tous types y compris des types objets.
  • Il n'y a pas de mot clef spécifique pour la classe tableaux, mais l'opérateur symbolique [ ] indique qu'une variable de type fixé est un tableau.
  • La taille d'un tableau doit obligatoirement avoir été définie avant que Java accepte que vous l'utilisiez !

Les tableaux à une dimension

Déclaration d'une variable de tableau :

int [ ] table1; char [ ] table2; float [ ] table3;

...

String [ ] tableStr;

Déclaration d'une variable de tableau avec définition explicite de taille : int [ ] table1 = new int [5]; char [] table2 = new char [12]; float [ ] table3 = new float [8];

...

String [ ] tableStr = new String [9];

Le mot clef new correspond à la création d'un nouvel objet (un nouveau tableau) dont la taille est fixée par la valeur indiquée entre les crochets. Ici 4 tableaux sont créés et prêts à être utilisés : table1 contiendra 5 entiers 32 bits, table2 contiendra 12 caractères, table3 contiendra 8 réels en simple précision et tableStr contiendra 9 chaînes de type String.

On peut aussi déclarer un tableau sous la forme de deux instructions : une instruction de déclaration et une instruction de définition de taille avec le mot clef new, la seconde pouvant être mise n'importe où dans le corps d'instruction, mais elle doit être utilisée avant toute manipulation du tableau. Cette dernière instruction de définition peut être répétée plusieurs fois dans le programme, il s'agira alors à chaque fois de la création d'un nouvel objet (donc un nouveau tableau), l'ancien étant détruit et désalloué automatiquement par le ramasse-miettes (garbage collector) de Java.

Déclaration et initialisation d'un tableau avec définition implicite de taille :

int [ ] table1 = {17,-9,4,3,57};

char [ ] table2 = {'a','j','k','m','z'};

float [ ] table3 = {-15.7f,75,-22.03f,3,57};

String [ ] tableStr = {"chat","chien","souris","rat","vache"};

Dans cette éventualité Java crée le tableau, calcule sa taille et l'initialise avec les valeurs fournies.

Il existe un attribut général de la classe des tableaux, qui contient la taille d'un tableau quelque soit son type, c'est l'attribut length.

Exemple :

int [ ] table1 = {17,-9,4,3,57};

int taille;

taille = table1.length; // taille = 5

Il existe des classes permettant de manipuler les tableaux :

  • La classe Array dans le package java.lang.reflect.Array, qui offre des méthodes de classe permettant de créer dynamiquement et d'accéder dynamiquement à des tableaux.

Les fondements du langage Java - ( rév. 28.05.2005 )     page 76

  • La classe Arrays dans le package java.util.Arrays, offre des méthodes de classe pour la recherche et le tri d'éléments d'un tableau.

Utiliser un tableau

Un tableau en Java comme dans les autres langages algorithmiques, s'utilise à travers une cellule de ce tableau repérée par un indice obligatoirement de type entier ou un char considéré comme un entier (byte, short, int, long ou char).

Le premier élément d'un tableau est numéroté 0, le dernier length-1.

On peut ranger des valeurs ou des expressions du type général du tableau dans une cellule du tableau.

Exemple avec un tableau de type int :

int [ ] table1 = new int [5];

// dans une instruction d'affectation:

table1[0] = -458;

table1[4] = 5891;

table1[5] = 72; <--- erreur de dépassement de la taille ! (valeur entre 0 et 4)

// dans une instruction de boucle:

for (int i = 0 ; i<= table1.length-1; i++)

table1[i] = 3*i-1; // après la boucle: table1 = {-1,2,5,8,11}

Même exemple avec un tableau de type char:

char [] table2 = new char [7];

table2[0] = '?' ;

table2[4] = 'a' ;

table2[14] = '#' ; <--- est une erreur de dépassement de la taille

for (int i = 0 ; i<= table2.length-1; i++)

table2[i] =(char)('a'+i);

//-- après la boucle: table2 = {'a', 'b', 'c' ,'d', 'e', 'f'}

Remarque :

Dans une classe exécutable la méthode main reçoit en paramètre un tableau de String nommé args qui correspond en fait aux éventuels paramètres de l'application elle-même:

public static void main(String [ ] args)

Les tableaux à deux dimension : matrices

Les tableaux en Java peuvent être à deux dimensions (voir même à plus de deux) auquel cas on peut les appeler des matrices, ce sont aussi des objets et ils se comportent comme les tableaux à une dimension tant au niveau des déclarations qu'au niveau des utilisations. La déclaration s'effectue avec deux opérateurs crochets [ ] [ ] . Les matrices Java ne sont pas en réalité des vraies matrices, elles ne sont qu'un cas particulier des tableaux multi indices.

Leur structuration n'est pas semblable à celle des tableaux pascal, en fait en java une matrice est composée de plusieurs tableaux unidimensionnels de même taille (pour fixer les idées nous les appellerons les lignes de la matrice) : dans une déclaration Java le premier crochet sert à indiquer le nombre de lignes (nombre de tableaux à une dimension), le second crochet sert à indiquer la taille de la ligne.

Un tel tableau à deux dimensions, peut être considéré comme un tableau unidimensionnel de pointeurs, où chaque pointeur référence un autre tableau unidimensionnel.

Voici une manière imagée de visualiser une matrice à n+1 lignes et à p+1 colonnes int [ ][ ] table = new int [n+1][p+1];

 Les tableaux multiples en Java sont utilisables comme des tableaux unidimensionnels. Si l'on garde bien présent à l'esprit le fait qu'une cellule contient une référence vers un autre tableau, on peut alors écrire en Java soient des instructions pascal like comme table[i,j] traduite en java par table[i][j], soient des instructions spécifiques à java n'ayant pas d'équivalent en pascal comme dans l'exemple ci-après :

table[0] = new int[p+1]; table[1] = new int[p+1];

Dans chacune de ces deux instructions nous créons un objet de tableau unidimensionnel qui est référencé par la cellule de rang 0, puis par celle de rang 1.           

Ou encore, en illustrant ce qui se passe après chaque instruction :

int [ ][ ] table = new int [n+1][p+1]; table[0] = new int[p+1];    

int [ ] table1 = new int [p+1];    

table[1] = table1 ;          

Rien n'oblige les tableaux référencés d'avoir la même dimension, ce type de tableau se dénomme tableaux en escalier ou tableaux déchiquetés en Java :

Les fondements du langage Java - ( rév. 28.05.2005 )     page 79

int [ ][ ] table = new int [3][ ]; table[0] = new int[2]; table[1] = new int[4]; table[2] = new int[3];

Si l'on souhaite réellement utiliser des matrices (dans lequel toutes les lignes ont la même dimension) on emploiera l'écriture pascal-like, comme dans l'exemple qui suit.

Exemple d'écritures conseillées de matrice de type int :

int [ ][ ] table1 = new int [2][3];// deux lignes de dimension 3 chacune

// dans une instruction d'affectation:

table1[0][0] = -458;

table1[2][5] = -3; <--- est une erreur de dépassement ! (valeur entre 0 et 1)

table1[1][4] = 83; <--- est une erreur de dépassement ! (valeur entre 0 et 4)

// dans une instruction de boucle: for (int i = 0 ; i<= 2; i++) table1[1][i] = 3*i-1;

// dans une instruction de boucles imbriquées: for (int i = 0 ; i<= 2; i++)

for (int k= 0 ; i<= 3; i++) table1[i][k] = 100;

Information sur la taille d'un tableau multi-indices :

Le même attribut général length de la classe des tableaux, contient la taille du tableau :

Exemple : matrice à deux lignes et à 3 colonnes int [ ][ ] table1 = new int [2][3];

int taille;

taille = table1.length; // taille = 2 (nombre de lignes)

taille = table1[0].length; // taille = 3 (nombre de colonnes)

taille = table1[1].length; // taille = 3 (nombre de colonnes)

Java initialise les tableaux par défaut à 0 pour les int, byte, ... et à null pour les objets.

Tableaux dynamiques et listes

Java2

Tableau dynamique

Un tableau array à une dimension, lorsque sa taille a été fixée soit par une définition explicite, soit par une définition implicite, ne peut plus changer de taille, c'est donc une structure statique.

char [ ] TableCar ;

TableCar = new char[8]; //définition de la taille et création d'un nouvel objet tableau à 8 cellules TableCar[0] = 'a';

TableCar[1] = '#';

...

TableCar[7] = '?';

Si l'on rajoute l'instruction suivante aux précédentes

<TableCar= new char[10]; > il y a création d'un nouveau tableau de même nom et de taille 10, l'ancien tableau à 8 cellules est alors détruit. Nous ne redimensionnons pas le tableau, mais en fait nous créons un nouvel objet ayant la même reférence que le précédent :

Ce qui nous donne après exécution de la liste des instructions ci-dessous, un tableau TabCar ne contenant plus rien :

char [] TableCar ;

TableCar = new char[8];

TableCar[0] = 'a';

TableCar[1] = '#';

...

TableCar[7] = '?';

TableCar= new char[10];

Si l'on veut "agrandir" un tableau pendant l'exécution il faut en déclarer un nouveau plus grand et recopier l'ancien dans le nouveau.

Il est possible d'éviter cette façon de faire en utilisant un vecteur (tableau unidimensionnel dynamique) de la classe Vector, présent dans le package java.util.Vector. Ce sont en fait des listes dynamiques gérées comme des tableaux.

Un objet de classe Vector peut "grandir" automatiquement d'un certain nombre de cellules pendant l'exécution, c'est le programmeur qui peut fixer la valeur d'augmentation du nombre de cellules supplémentaires dès que la capacité maximale en cours est dépassée. Dans le cas où la valeur d'augmentation n'est pas fixée, c'est la machine virtuelle Java qui procède à une augmentation par défaut (doublement dès que le maximum est atteint).

Vous pouvez utiliser le type Vector uniquement dans le cas d'objets et non d'éléments de type élémentaires (byte, short, int, long ou char ne sont pas autorisés), comme par exemple les String ou tout autre objet de Java ou que vous créez vous-même.

Les principales méthodes permettant de manipuler les éléments d'un Vector sont :

void addElement(Object obj)    ajouter un élément à la fin du vecteur

void clear( )        effacer tous les éléments du vecteur

Object elementAt(int index)     élément situé au rang = 'index'

int indexOf(Object elem)            rang de l'élément 'elem'

Object remove(int index)           efface l'élément situé au rang = 'index'

void setElementAt(Object obj, int index)            remplace l'élément de rang 'index' par obj

int size( )             nombre d'éléments du vecteur

Voici un exemple simple de vecteur de chaînes utilisant quelques unes des méthodes précédentes

:

static void afficheVector(Vector vect)

//affiche un vecteur de String

{

System.out.println( "Vector taille = " + vect.size( ) );

for ( int i = 0; i<= vect.size( )-1; i++ )

System.out.println( "Vector[" + i + "]=" + (String)vect.elementAt( i ) );

}

static void VectorInitialiser( )

// initialisation du vecteur de String

{ Vector table = new Vector( );

String str = "val:";

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

table.addElement(str + String.valueOf( i ) );

afficheVector(table);

}

Voici le résultat de l'exécution de la méthodeVectorInitialiser :

Les fondements du langage Java - ( rév. 28.05.2005 )     page 82

Vector taille = 6 Vector[0] = val:0 Vector[1] = val:1 Vector[2] = val:2 Vector[3] = val:3 Vector[4] = val:4 Vector[5] = val:5

Les listes chaînées

Rappelons qu'une liste linéaire (ou liste chaînée) est un ensemble ordonné d'éléments de même type (structure de donnée homogène) auxquels on accède séquentiellement. Les opérations minimales effectuées sur une liste chaînée sont l'insertion, la modification et la suppression d'un élément quelconque de la liste.

Les listes peuvent être uni-directionnelles, elles sont alors parcourues séquentiellement dans un seul sens :

ou bien bi-directionnelles dans lesquelles chaque élément possède deux liens de chaînage, l'un sur l'élément qui le suit l'autre sur l'élément qui le précède, le parcours s'effectuant en suivant l'un ou l'autre sens de chaînage :

La classe LinkedList présente dans le package java.util.LinkedList, est en Java une implémentation de la liste chaînée bi-directionnelle, comme la classe Vector, les éléments de la classe LinkedList ne peuvent être que des objets et non de type élémentaires (byte, short, int, long ou char ne sont pas autorisés),


438