0
Programmation objet et JAVA
Bibliographie
0. Bibliographie
1. Programmation objet
2. Le langage Java 1.6
Livre de r
ef
erence
3. Les classes fondamentales (API)
Gilles Roussel, Etienne
Duris, Nicolas Bedon, Remi Forax,
Java et Internet : Concepts et Programmation, Tome 1 :
cote client, 2`eme edition , Vuibert, novembre 2002.
4. Les flots
5. Les bases de donnees avec JDBC
Notes de cours et transparents dEtienne
Duris, Remi Forax, Dominique Perrin, Gilles Roussel.
6. Introduction `a lintrospection
7. La programmation concurrente
Autres ouvrages sur Java
Cay S. Horstmann, Gary Cornell, Au coeur de Java 2, Sun
Microsystem Press (Java Series).
Volume I - Notions fondamentales, 1999.
Volume II - Fonctions avancees, 2000.
Ken Arnold, James Gosling, The Java Programming Language Second edition, Addison Wesley, 1998.
Samuel N. Kamin, M. Dennis Mickunas, Edward M. Reingold,
An Introduction to Computer Science Using Java, McGrawHill, 1998.
Marie-Pierre Beal
Jean Berstel
Marie-Pierre Beal
Jean Berstel
Patrick Niemeyer, Joshua Peck (Traduction de Eric Dumas),
Java par la Pratique, OReilly International Thomson, 1996.
Matthew Robinson and Pavel Vorobiev, Swing, Manning Publications Co., december 1999.
(voir [Link]
Sur les Design Pattern Le livre de reference est
Programmation objet
Erich Gamma, Richard Helm, Ralph Johnsons, John Vlissides,
Design Patterns, Addison-Wesley, 1995. Traduction francaise
chez Vuibert, 1999.
1. Styles de programmation
Souvent designe par GoF (Gang of Four).
2. Avantages du style objet
3. Premiers exemples
Marie-Pierre Beal
Jean Berstel
Marie-Pierre Beal
Jean Berstel
Styles de programmation
Avantages du style objet
Style applicatif
Facilite la programmation modulaire
Fonde sur levaluation dexpressions, o`u le resultat ne depend
que de la valeurs des arguments (et non de letat de la memoire).
La conception par classes conduit `a des composants
reutilisables.
Donne programmes courts, faciles `a comprendre.
Un composant offre des services, et en utilise dautres.
Usage intensif de la recursivite.
Il expose ses services `a travers une interface.
Langage typique : Lisp, Caml.
Il cache les details dimplementations (encapsulation ou datahiding).
Style imp
eratif
Fonde sur lexecution dinstructions modifiant letat de la
memoire.
Ceci le rend reutilisable.
Facilite labstraction
Utilise une structure de controle et des structures de donnees.
Labstraction separe la definition de son implementation.
Usage intensif de literation.
Labstraction extrait un mod`ele commun `a plusieurs composants.
Langages typiques : Fortran, C, Pascal.
Le mod`ele commun est partage par le mecanisme dheritage.
Style objet
Un programme est vu comme une communaute de composants
autonomes (objets) disposant de ses ressources et de ses moyens
dinteraction.
Utilise des classes pour decrire les structures et leur comportement.
Facilite la sp
ecialisation
La specialisation traite de cas particuliers.
Le mecanisme de derivation rend les cas particuliers transparents.
Usage intensif de lechange de message (metaphore).
Langages typiques : Simula, Smalltalk, C++, Java, Ocaml.
Marie-Pierre Beal
Jean Berstel
Marie-Pierre Beal
Premier exemple
Jean Berstel
Le langage
Le fichier
[Link] :
class HelloWorld {
public static void main (String[] args) {
[Link]("Bonjour `
a tous !");
}
}
Java (nom derive de Kawa) a vu le jour en 1995. Actuellement version JDK 1.6 (aussi appelee Java 6). Environnements dexecution :
J2ME, J2SE, J2EE.
Java
est fortement type,
est oriente objet,
Compilation :
javac [Link]
est compileinterprete,
cree le fichier [Link]
est sans heritage multiple,
Execution :
java HelloWorld
`a partir de la version 1.5, Java offre de la genericite (les
generics sont differents des template du C++)
int`egre des thread ou processus legers,
Resultat :
Bonjour `
a tous !
Compilation Interpretation
Source compilee en langage intermediaire (byte code)
independant de la machine cible.
Il est usuel de donner une initiale majuscule aux classes, et une
initiale minuscule aux attributs et aux methodes.
Le nom du fichier qui contient le code source est en general le
nom de la classe suffixe par .java.
Byte code interprete par une machine virtuelle Java
(dependant de la plateforme).
Avantages : lexecution peut se faire
plus tard,
ailleurs (par telechargement).
Marie-Pierre Beal
Jean Berstel
Marie-Pierre Beal
Jean Berstel
Exemple 2
de base :
Structures de donnees : vecteurs, listes, ensembles ordonnes,
arbres, tables de hachage, grands nombres;
Outils de communication, comme les URL, client-serveur;
Facilites audiovisuelles, pour images et son;
Des composants de creation dinterfaces graphiques;
Traitement de fichiers;
Acc`es `a des bases de donnees.
class Hello {
public static void main (String[] args) {
String s = "Hello ";
s = s + args[0]; // contan
enation des cha^
nes
[Link](s);
}
}
Execution :
java Hello David
Variables denvironnements :
JAVA HOME correspond au repertoire racine du JDK.
CLASSPATH correspond aus repertoires contenant des classes
du developpeur.
Resultat :
Hello David
ou encore
class Hello2 {
public static void main (String[] args) {
StringBuilder sb = new StringBuilder();
[Link]("Hello ");
[Link](args[0]);
[Link](sb);
}
}
Voir aussi les options du compilateurs.
Meme resultat. Les classes StringBuilder et StringBuffer
permettent de manipuler les chanes de facon plus efficaces. La
classe StringBuffer est securisee pour les threads.
Les entrees sorties sont facilitees avec la classe
[Link].
Marie-Pierre Beal
Jean Berstel
Marie-Pierre Beal
import [Link].*;
Jean Berstel
Exemple 3
class Hello3 {
public static void main (String[] args) {
String s;
Scanner sc = new Scanner([Link]);
while ([Link]()){
s = [Link]();
[Link](s);
}
[Link]();
}
}
import [Link].*;
/**
* Classe affichant une fenetre de nom "Hello David"
* contenant "Hello David".
* @author Beal
* @version 1.0
*/
public class HelloWorldCanvas extends Canvas{
/**
* Constructeur
*/
public HelloWorldCanvas() {
super();
}
/**
* Methode de dessin de la fenetre
* @param graphics contexte daffichage
*/
public void paint(Graphics graphics) {
[Link]([Link]);
[Link]("Hello David",65,60);
}
/**
* Methode main
* @param args arguments de la ligne de commande
*/
public static void main(String[] args) {
HelloWorldCanvas c = new HelloWorldCanvas();
Frame f = new Frame("Hello David");
[Link](200,200);
[Link](c);
[Link](true);
}
}
On peut lire un entier facilement.
import [Link].*;
class MyRead {
public static void main (String[] args) {
Scanner sc = new Scanner([Link]);
int i = [Link]();
[Link](i);
[Link]();
}
}
Marie-Pierre Beal
10
11
Jean Berstel
Marie-Pierre Beal
12
Jean Berstel
Exemple des points
Heritage et composition
public class Pixel {
private int x;
private int y;
Par h
eritage, une classe d
eriv
ee b
en
eficie des attributs et des m
ethodes de la superclasse.
La classe derivee poss`ede les attributs et les methodes de la
classe de base.
public Pixel (int x, int y) {
this.x = x; this.y = y;
}
public int getX() {
return x;
}
public int getY() {
return y;
}
public void setX(int x) {
this.x = x;
}
public void setY(int y) {
this.y = y;
}
public void move(int dx, int dy) {
x += dx; y += dy;
}
@Override
public String toString() {
return(this.x + ", " + this.y);
}
public static void main(String[] args) {
Pixel a = new Pixel(3,5);
[Link](6);
// a = (3,6)
[Link](1,1);
// a = (4,7)
[Link](a);
}
La classe derivee peut en ajouter, ou en masquer.
Facilite la programmation par raffinement.
Facilite la prise en compte de la specialisation.
Par la composition, une classe utilise un autre service.
Un composant est souvent un attribut de la classe utilisatrice.
Lexecution de certaines taches est delegue au composant le
plus apte.
Le composant a la responsabilite de la bonne execution.
Facilite la separation des taches en modules specialises.
}
Marie-Pierre Beal
13
Jean Berstel
Marie-Pierre Beal
14
Exemple : disques et anneaux
public class Disk {
protected Pixel center; // composition
protected int radius;
public Disk(int x, int y, int radius) {
center = new Pixel(x,y);
[Link] = radius;
}
@Override
public String toString() {
return [Link]() + " ," + radius;
}
public void move(int dx, int dy) {
[Link](dx, dy); // d
el
egation
}
}
Le langage Java 1.6
1. Structure dun programme
2. Classes et objets
3. Types primitifs et enveloppes
4. Tableaux
5. Exemple avec une documentation
public class Ring extends Disk { // d
erivation
private int internalRadius;
public Ring(int x, int y, int radius, int internalRadius) {
super(x, y, radius);
[Link] = internalRadius;
}
@Override
public String toString() {
return [Link]() + " ," + internalRadius;
}
}
class Test {
public static void main(String[] args) {
Ring a = new Ring(3, 5, 7, 2);
[Link](5,-2); // h
erit
ee de Disk, qui d
el`
egue `
a Pixel
[Link](a); // 8, 3 , 7, 2
}
}
Marie-Pierre Beal
15
Jean Berstel
Jean Berstel
6. Methodes et constructeurs
7. Heritage : generalites
8. Heritage : exemples
9. Heritage : interfaces
10. Exceptions
11. Exemple de types parametres
12. Visibilite et paquetages
13. Programmation des listes
Marie-Pierre Beal
16
Jean Berstel
Structure dun programme
declarations de variables (attributs);
definitions de fonctions (methodes);
declarations dautres classes (nested classes);
class HelloWorld {
public static void main (String[] args) {
[Link]("Hello World !");
}
}
Les membres sont
des membres de classe (static);
des membres dobjet (ou dinstance).
Programme Java : constitue dun ensemble de classes
Une classe a trois roles:
groupees en paquetages (packages);
1. de typage, en declarant de nouveaux types;
reparties en fichiers;
2. dimplementation, en definissant la structure et le comportement dobjet;
chaque classe compilee est dans son propre fichier (un fichier
dont le nom est le nom de la classe suffixe par .class).
3. de moule pour la creation de leurs instances.
Une methode se compose
Un fichier source Java comporte
de declarations de variables locales;
des directives dimportation comme
dinstructions.
import [Link].*;
Les types des param`etres et le type de retour constituent la signature de la methode.
des declarations de classes.
static int pgcd(int a, int b) {
return (b == 0) ? a : pgcd( b, a % b );
}
Point dentree : Une fonction speciale est appelee `a lexecution.
Elle sappelle toujours main et a toujours la meme signature.
public static void main(String[] args) {...}
Marie-Pierre Beal
17
Jean Berstel
Marie-Pierre Beal
Toute m
ethode, toute donn
ee fait partie dune classe
(pas de variables globales). Lappel se fait par dereferencement
dune classe ou dun objet dune classe, de la facon suivante :
Methodes ou donnees de classe : par le nom de la classe.
[Link]()
[Link]
18
Jean Berstel
Expressions, types, variables
Toute expression a une valeur et un type. Les valeurs sont
les valeurs primitives;
Methode ou donnee dun objet : par le nom de lobjet.
...
Stack s = new Stack();
[Link](x);
les references, qui sont des references `a des tableaux ou `a des
objets.
Il existe une reference speciale null. Elle peut etre la valeur
de nimporte quel type non primitif.
Lobjet courant est nomme this et peut etre sous-entendu.
public void setX(int x) {
this.x = x;
}
La classe courante peut etre sous-entendue pour des methodes
statiques.
Un objet ne peut
etre manipul
e, en Java, que par une
r
ef
erence.
Une variable est le nom dun emplacement memoire qui peut contenir une valeur. Le type de la variable decrit la nature des valeurs
de la variable.
Si le type est un type primitif, la valeur est de ce type.
Si le type est une classe, la valeur est une reference `a un objet de
cette classe, ou dune classe derivee. Une reference est differente
des pointeurs du C (pas darithmetique dessus).
Exemple :
[Link]()
Exemple :
out est un membre statique de la classe System.
Pixel p;
out est un objet de la classe PrintStream.
println est une methode dobjet de la classe PrintStream.
declare une variable de type Pixel, susceptible de contenir une
reference `a un objet de cette classe.
p = new Pixel(4, 6);
Levaluation de lexpression new Pixel(4, 6) retourne une
reference `a un objet de la classe Pixel. Cette reference est affectee `a p.
Marie-Pierre Beal
19
Jean Berstel
Marie-Pierre Beal
20
Jean Berstel
Passage de param`etres
int i, j = 5;
float re, im;
boolean termine;
static int numero;
static final int N = 12;
Toujours par valeur.
Exemple : Soit la methode
A noter :
static int plus(int a, int b) {
return a+b;
}
Une variable peut etre initialisee.
` lappel de la methode, par exemple int c = plus(a+1,7),
A
les param`etres sont evalues, des variables locales sont initialisees
avec les valeurs des param`etres, et les occurrences des param`etres
formels sont remplacees par les variables locales correspondantes.
Par exemple,
Une variable static est un membre de classe.
Une variable final est une constante.
Tout attribut de classe est initialise par defaut, `a 0 pour les
variables numeriques, `a false pour les booleennes, `a null
pour les references.
Dans une methode, une variable doit etre declaree avant utilisation. Elle nest pas initialisee par defaut.
int aLocal = a+1;
int bLocal = 7;
r
esultat = aLocal+bLocal;
Attention : Les objets sont manipul
es par des
r
ef
erences. Un passage par valeur dune r
ef
erence
est donc comme un passage par r
ef
erence !
Attention : Ce nest pas le passage par reference du C++.
Exemple :
Dans la definition dune classe, un attribut peut etre declare
apr`es son utilisation. (Elle se fait `a linterieur dune methode.)
static void increment(Pixel a) {
a.x++; a.y++;
}
Apr`es appel de increment(a), les coordonnees du point sont
incrementees !
Marie-Pierre Beal
21
Jean Berstel
22
Jean Berstel
Traitement par cas :
Instructions
Affectation, instructions conditionnelles, aiguillages, iterations
usuelles.
Affectation :
x = 1; y = x = x+1;
Instructions conditionnelles :
if (C) S
if (C) S else T
Iterations :
switch(c) {
case :
nEspaces++; break;
case 0: case 1: case 2: case 3: case 4:
case 5: case 6: case 7: case 8: case 9:
nChiffres++; break;
default:
nAutres++;
}
Blocs `a etiquettes :
while (C) S
do S while (C)
for (E; C; G) S
Une instruction break; fait sortir du bloc o`u elle se trouve.
La conditionnelle C doit etre de type booleen
Marie-Pierre Beal
Marie-Pierre Beal
23
Jean Berstel
un: while (...) {
...
deux : for (...) {
...
trois: while (...) {
...
if (...) continue un; // reprend while exterieur
if (...) break deux; // quitte boucle for
continue; // reprend while interieur
}
}
}
Marie-Pierre Beal
24
Jean Berstel
Types primitifs
Enveloppes des types primitifs
Nom
Taille Exemples
byte
8
1, -128, 127
short
16 2, 300
int
32 234569876
long
64 2L
float
32 3.14, 3.1E12, 2e12
double
64 0.5d
boolean
1
true ou false
char
16 a, \n, \u0000
boolean
char
byte
short
int
long
float
double
Une instance de la classe enveloppe encapsule une valeur du
type de base correspondant.
A noter :
Les caract`eres sont codes sur deux octets en Unicode.
Les types sont independants du compilateur et de la plateforme.
Tous les types numeriques sont signes sauf les caract`eres.
Un booleen nest pas un nombre.
Les operations sur les entiers se font modulo, et sans erreur :
byte b = 127;
b += 1; // b = -128
Marie-Pierre Beal
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
Chaque classe enveloppe poss`ede des methodes pour extraire
la valeur dun objet : primitifValue() appliquee sur lobjet
enveloppe renvoie une valeur de type primitif.
Une methode statique de chaque classe Enveloppe :
[Link](primitif p) renvoie un objet enveloppant le primitif correspondant.
Un objet enveloppant est immutable : la valeur contenue ne
peut etre modifiee.
On transforme souvent une valeur en objet pour utiliser une
methode manipulant ces objets.
25
Jean Berstel
Conversions automatiques (auto-boxing et auto-unboxing)
Depuis la version 1.5, la conversion est automatique.
Auto-boxing
Integer i = 3; // int -> Integer
Long l = 3L; // long -> Long
Long l = 3; // erreur, int -> Integer -X-> Long
Auto-unboxing
Integer i = new Integer(3);
int x = i; // Integer -> int
Long lo = null;
long l = lo; //erreur : [Link]
Marie-Pierre Beal
26
Jean Berstel
public static void main(String[] args){
Long a = 5L;
Long b = 5L;
Integer i = 6;
Integer j = 6;
Integer k = new Integer(6);
[Link](a == b); //true, a,b petits
[Link](i == j); //true, i,j petits
[Link](i == k); //false
i = i+1;//Integer -> int +1 -> int -> Integer
[Link](i); // 7
[Link](j); // 6
}
Ne pas tester legalite de references.
Auto-boxing et appels de methodes
class Test3{
static void myPrint(Integer i){
[Link](i);
}
public static void main(String[] args){
myPrint(5); //affiche 5
}
}
Auto-boxing et egalite
Sur des objets, == teste legalite des references. Les enveloppes
obtenues par auto-boxing ont la meme reference.
Marie-Pierre Beal
27
Jean Berstel
Marie-Pierre Beal
28
Jean Berstel
Sous-typage
Tableaux
Le sous-typage est la possibilite de referencer un objet dun certain
type avec un autre type.
Cest un objet particulier. Lacc`es se fait par reference et la creation
par new. Un tableau
En Java, le sous-typage concide avec la derivation.
se declare,
Il ny a pas de relation de sous-typage entre types primitifs et
types objets.
et sutilise.
Le conversions dauto-boxing et auto-unboxing sont faites avant
les transtypages sur les types objets.
Par exemple, Integer, Long, Float, Double derivent de la classe
abstraite (voir plus loin dans le cours) Number.
se construit,
Identificateur de type tableau se declare par
int[] tab; // vecteur dentiers
double[][] m; // matrice de doubles
La declaration des tableaux comme en C est acceptee
mais celle-ci est meilleure.
Number n = new Integer(3);
Number m = new Double(3.14);
Object o = new Integer(3);
Object obis = m;
Integer i = new Object();//erreur
La valeur de lidentificateur nest pas definie apr`es la declaration.
Construction dun tableau par new :
tab = new int[n] ;
m = new double[n][p] // n lignes, p colonnes
Utilisation traditionnelle
int i, j;
m[i][j] = x; // ligne i, colonne j
for (i = 0; i < [Link]; i++)
[Link](tab[i]);
//ou boucle for each
for (int x:tab) [Link](x);
Marie-Pierre Beal
29
Jean Berstel
Tout tableau a un attribut length qui donne sa taille `a la creation.
Distinguer:
la declaration, qui concerne la variable dont le contenu sera une
reference sur un tableau,
la construction, qui cree le tableau et retourne une reference
sur ce tableau.
On peut fusionner declaration et construction par initialisation
enumerative :
String[] jours = {"Lundi", "Mardi", "Mercredi",
"Jeudi", "Vendredi", "Samedi", "Dimanche" };
Les instructions suivantes provoquent toujours une exception (de
la classe ArrayIndexOutOfBoundsException) :
a[[Link]],
Marie-Pierre Beal
30
Jean Berstel
Un exemple :
/**
* Matrices of integers.
* @author Beal
* @author Berstel
* @version 1.0
*/
public class Matrix {
int[][] m;
/**
* Create a null matrix.
* @param dim dimension of the matrix
* @see Matrix#Matrix(int,int)
*/
public Matrix(int dim) {
this(dim,0);
}
/**
* Create a matrix whose coefficients are equal to a same number
* @param dim dimension of the matrix
* @param x integer value of each coefficient
* @see Matrix#Matrix(int)
*/
a[-1].
public Matrix(int dim, int n) {
m = new int [dim][dim];
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
m[i][j] = n;
}
/**
* Transpose this matrix
*/
public void transposer() {
Marie-Pierre Beal
31
Jean Berstel
Marie-Pierre Beal
32
Jean Berstel
for (int i = 0; i < dim; i++)
for (int j = i+1; j < dim; j++){
int t = m[i][j]; m[i][j] = m[j][i]; m[j][i]=t;
}
}
/**
* Returns a String object representing this Matrixs value.
*/
@Override
public String toString(){
StringBuilder sb = new StringBuilder();
for (int[] t : m){
for (int x : t){
[Link](x);
[Link](" ");
}
[Link]("\n");
}
return [Link]();
}
12 12 12
12 12 12
12 12 12
3 3 3
3 3 3
3 3 3
0 0 0
0 0 0
0 0 0
Creation de la documentation HTML
javadoc [Link]
Visualisation avec Netscape.
$ ls
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
/**
* Main
* @param args arguments of the line command
*/
[Link]
[Link]~
[Link]
[Link]
package-list
[Link]
[Link]
resources/
[Link]
public static void main(String[] args) {
Matrix a = new Matrix(3,12);
[Link](a);
Matrix b = new Matrix(3,3);
[Link](b);
Matrix c = new Matrix(3);
[Link](c);
}
}
Marie-Pierre Beal
33
Jean Berstel
Marie-Pierre Beal
34
Jean Berstel
M
ethodes
Creer une documentation HTML
Chaque classe contient une suite non embotee de methodes : on
ne peut pas definir des methodes `a linterieur de methodes.
Il sagit de creer une documentation et non detablir les
specifications des classes.
@author : il peut y avoir plusieurs auteurs;
@see : pour creer un lien sur une autre documentation Java;
@param : pour indiquer les param`etres dune methode;
@return : pour indiquer la valeur de retour dune methode;
@exception : pour indiquer quelle exception est levee;
static int next(int n) {
if (n % 2 == 1)
return 3 * n + 1;
return n / 2;
}
static int pgcd(int a, int b) {
return (b == 0) ? a : pgcd( b, a % b );
}
@version : pour donner le numero de version du code;
@since : pour donner le numero de la version initiale;
@deprecated : indique une methode ou membre qui ne devrait
plus etre utilise. Cree un warning lors de la compilation.
Une methode qui ne retourne pas de valeur a pour type de retour
le type void.
Exemple :
/**
* @deprecated Utiliser plutot afficher()
* @see #afficher()
*/
Marie-Pierre Beal
35
Jean Berstel
Marie-Pierre Beal
36
Jean Berstel
On distingue :
Les membres (attributs ou methodes) dune classe ont une visibilite
definie par defaut et ont des modificateurs de visibilite :
Profil : le nom plus la suite des types des arguments.
Signature : le type de retour plus le profil.
Signature compl`ete : signature plus la visibilite (private,
protected, public, ou rien).
Signature etendue : signature compl`ete plus les exceptions.
Un meme identificateur peut designer des methodes differentes
pourvu que leurs profils soient differents.
static int fact(int n, int p) {
if (n == 0) return p;
return fact( n-1, n*p);
}
public
protected
private
Par defaut, une classe a ses donnees ou methodes accessibles dans le
repertoire, plus precisement dans le paquetage dont il sera question
plus loin.
Un attribut (donnees ou methodes)
public est accessible dans tout code o`u la classe est accessible.
protected est accessible dans le code des classes du meme
paquetage et dans les classes derivees de la classe.
private nest accessible que dans le code de la classe.
static int fact(int n) {
return fact(n, 1);
}
La methode main() doit etre accessible de la machine virtuelle,
donc doit etre public.
Il ny a pas de valeurs par defaut (comme en C++). Il faut donc
autant de definitions quil y a de profils.
Marie-Pierre Beal
37
Jean Berstel
Constructeurs
execute le corps de la methode;
retourne la reference de lobjet cree.
Exemple avec seulement le constructeur par defaut :
class Pixel {
int x,y;
}
Utilisation :
public static void main(String[] args) {
Pixel p;
// p est ind
efini
p = new Pixel(); // p!= null, p.x = p.y = 0;
p.x = 4;
p.y = 5;
...
}
39
38
Jean Berstel
Exemple avec un constructeur particulier :
Les objets sont instancies au moyen de constructeurs. Toute classe
a un constructeur par defaut, sans argument. Lors de la construction dun objet, loperateur new reserve la place pour lobjet et
initialise les attributs `a leur valeur par defaut.
Le constructeur
Marie-Pierre Beal
Marie-Pierre Beal
Jean Berstel
class Pixel {
int x,y;
Pixel(int x, int y) {
this.x = x; this.y = y;
}
}
public static void main(String[] args) {
Pixel p, q;
// p, q ind
efinis
p = new Pixel(2,3); // p.x = 2, p.y = 3;
q = new Pixel();
// erreur !
...
}
La definition explicite dun constructeur fait disparatre le constructeur par defaut implicite. Si lon veut garder le constructeur
defini et le constructeur par defaut, il faut alors declarer explicitement celui-ci.
class Pixel {
int x,y;
Pixel() {}
Pixel(int x, int y) {
this.x = x; this.y = y;
}
}
public static void main(String[] args) {
Pixel p, q;
// p,q ind
efinis
p = new Pixel(2,3); // p.x = 2, p.y = 3;
q = new Pixel();
// OK !
...
}
Marie-Pierre Beal
40
Jean Berstel
dans le deuxi`eme constructeur, on affecte `a start et end les
references dobjets existants;
class Segment {
Pixel start ;
Pixel end;
}
dans le troisi`eme, on cree des objets `a partir de donnees de
base, et on affecte leurs references.
Utilisation :
public static void main(String[] args) {
Segment s;
// s ind
efini
s = new Segment() ; // [Link] = null, [Link] = null
}
Plusieurs constructeurs pour la meme classe :
class Segment {
Pixel start;
Pixel end;
Segment() {} // par defaut
Segment(Pixel start, Pixel end) {
[Link] = start;
[Link] = end;
}
Segment(int dx, int dy, int fx, int fy) {
start = new Pixel(dx, dy);
end = new Pixel(fx, fy);
}
}
Marie-Pierre Beal
41
Jean Berstel
Exemples demploi :
public static void main(String[] args) {
Segment s;
// s ind
efini
s = new Segment() ; // [Link] = null, [Link] = null
[Link] = new Pixel(2,3);
[Link] = new Pixel(5,8);
Pixel p = new Pixel(2,3);
Pixel q = new Pixel(5,8);
Segment t = new Segment(p,q);
Segment tt=
new Segment(new Pixel(2,3), new Pixel(5,8));
Segment r = new Segment(2,3,5,8);
}
Marie-Pierre Beal
Membres et m
ethodes statiques
des attributs de classe (static);
des attributs dobjet (ou dinstance).
Les attributs de classe static sont partages par tous les objets de
la classe. Il nen existe quun par classe au lieu de un pour chaque
instance ou objet dune classe lorsquil sagit de membre dobjets.
Exemple dattributs static:
un compteur du nombre dobjets;
un element particulier de la classe, par exemple une origine.
class Pixel {
int x, y;
static Pixel origin = new Pixel(0,0);
}
Les methodes peuvent aussi etre ou non static.
Les methodes statiques sont appelees en donnant le nom de la
classe ou le nom dune instance de la classe. Une methode statique
ne peut pas faire reference `a this.
Elles sont utiles pour fournir des services (helper). Methodes de la
classe Math.
43
Jean Berstel
Exemple 1
Les attributs peuvent etre
Marie-Pierre Beal
42
Jean Berstel
public class Chrono {
private static long start, stop;
public static void start() {
start = [Link]();
}
public static void stop() {
stop = [Link]();
}
public static long getElapsedTime() {
return stop - start;
}
}
On sen sert comme dans
class Test {
public static void main(String[] args) {
[Link]();
for (int i = 0; i < 10000; i++)
for (int j = 0; j < 10000; j++);
[Link]();
[Link]("Duree = "+ [Link]());
}
}
Sur cet exemple, on peut aussi creer un objet chronom`etre avec
des methodes dynamiques.
Marie-Pierre Beal
44
Jean Berstel
class User {
String nom;
static int nbUsers;
static User[] allUsers = new User[10];
User(String nom) {
[Link] = nom;
allUsers[nbUsers++] = this;
}
void send(String message, User destinataire) {
[Link]( message, this);
}
void handleMessage(String message, User expediteur) {
[Link](
[Link] + " dit \"" + message + "\" `
a " + nom);
}
void sendAll(String message) {
for (int i = 0; i < nbUsers; i++)
if (allUsers[i] != this) send( message, allUsers[i]);
}
Pierre dit "Bonjour" `
a Anne
Anne dit "Hello" `
a Pierre
Anne dit "Hello" `
a Alex
Anne dit "Hello" `
a Paul
Pierre dit "Encore moi" `
a Anne
Pierre dit "Encore moi" `
a Alex
Pierre dit "Encore moi" `
a Paul
public static void main(String[] args) {
User a = new User("Pierre"), b = new User("Anne"),
c = new User("Alex"), d = new User("Paul");
[Link]("Bonjour", b);
[Link]("Hello");
[Link]("Encore moi");
}
}
Marie-Pierre Beal
45
Jean Berstel
Methodes avec un nombre variable darguments : varargs
Depuis Java 1.5, il est possible de passer dans une methode un
nombre variable darguments de meme type.
Dans le code, les arguments sont traites comme un tableau.
Lors de lappel, on peut passer une suite ou un tableau.
class TestVarArgs{
static double polygonLength(Pixel... pixels){
float sum = 0;
int x = pixels[0].getX();
int y = pixels[0].getY();
double squareOfSide, lengthOfSide;
for (int i=1; i < [Link]; i++) {
squareOfSide =
(pixels[i].getX()-x)*(pixels[i].getX()-x)
+ (pixels[i].getY()-y)*(pixels[i].getY()-y);
lengthOfSide = [Link](squareOfSide);
x = pixels[i].getX();
y = pixels[i].getY();
sum += lengthOfSide;
}
return sum;
}
Marie-Pierre Beal
47
Jean Berstel
Marie-Pierre Beal
46
Jean Berstel
public static void main(String... args) {
Pixel p1= new Pixel(3,2);
Pixel p2 = new Pixel(3,4);
Pixel p3 = new Pixel(3,10);
[Link](polygonLength(p1,p2,p3));
Pixel[] tab = new Pixel[3];
tab[0] = p1; tab[1] = p2; tab[2] = p3;
[Link](polygonLength(tab));
}
}
Quelle est linteret de la syntaxe varargs ?
Marie-Pierre Beal
48
Jean Berstel
Heritage : generalites
Lheritage consiste `a faire profiter tacitement une classe derivee
D des attributs et des methodes dune classe de base B.
B
D
La classe derivee poss`ede les attributs de la classe de base (et
peut y acceder sauf sils sont prives).
La classe derivee poss`ede les methodes de la classe de base
(meme restriction).
La classe derivee peut declarer de nouveaux attributs et definir
de nouvelles methodes.
La classe derivee peut redefinir des methodes de la classe de
base. La methode redefinie masque la methode de la classe de
base.
Derivation par extends.
Toute classe derive, directement ou indirectement, de la classe
Object.
Larbre des derivations est visible dans les fichiers crees par
javadoc, sous eclipse,...
49
Jean Berstel
Usages
Le resultat est :
Marie-Pierre Beal
50
Jean Berstel
Points
epais : exemple de d
erivation
Il sagit dun point auquel on ajoute une information, lepaisseur.
On a donc un enrichissement.
Une classe derivee represente
une specialisation de la classe de base.
Mammif`ere derive de vertebre, matrice symetrique derive de
matrice. Compte sur livret A derive de Compte banquaire.
un enrichissement de la classe de base.
Un segment colore derive dun segment. Un article a un prix,
un vetement est un article qui a une taille. Un aliment est un
article qui a une date de peremption.
Une classe de base represente des proprietes communes `a plusieurs
classes. Souvent cest une classe abstraite, cest-`a-dire sans realite
propre.
Une figure est une abstraction dun rectangle et dune ellipse.
Un sommet est un nud interne ou une feuille.
Un vertebre est une abstraction des mammif`eres etc. Les
mammif`eres eux-memes sont une abstraction.
Un type abstrait de donnees est une abstraction dune structure de donnees.
La hauteur des derivations nest en general pas tr`es elevee. Il ne
faut pas se forcer `a creer des classes derivees.
Marie-Pierre Beal
}
class Der extends Base {
int z=7;
@Override public String toString(){
return "D "+x+" "+y+" "+z;
}
}
public class BaseTest{
public static void main(String[] args) {
Base b = new Base();
Der d = new Der();
[Link](b);
[Link]([Link]());
[Link](d);
[Link]([Link]());
}
}
B 2 3 5
8
D 3 5 7
8
La relation dheritage est transitive.
Marie-Pierre Beal
private int p = 2;
int x = 3, y = 5;
@Override public String toString(){
return "B "+p+" "+x+" "+y;
}
int sum(){return x+y;}
51
Jean Berstel
class Pixel {
int x, y;
Pixel (int x, int y) {
this.x = x; this.y = y;
}
void translate(int dx, int dy) {
this.x += dx; this.y += dy;
}
@Override
public String toString() {
return(this.x + ", " + this.y);
}
}
class ThickPixel extends Pixel {
int thickness;
ThickPixel(int x, int y, int t) {
super(x, y);
thickness = t;
}
@Override
public String toString() {
return [Link]() + ", " + thickness;
}
void thicken(int i) {
thickness += i;
}
public static void main(String[] args) {
ThickPixel a = new ThickPixel(3, 5, 1);
[Link](a); // 3, 5, 1
[Link](5,-2); [Link](a); // 8, 3, 1
[Link](5); [Link](a); // 8, 3, 6
}
}
Marie-Pierre Beal
52
Jean Berstel
base est execute en premier. Par defaut, cest le constructeur sans
argument de la classe de base. On remonte recursivement jusqu`a
la classe Object.
Dans un constructeur dune classe derivee, lappel dun autre constructeur de la classe de base se fait au moyen de super(...).
Cette instruction doit etre la premi`ere dans lecriture du constructeur de la classe derivee. En dautres termes, si cette instruction est
absente, cest linstruction super() qui est executee en premier.
This et super
La destruction des objets est effectuee :
automatiquement par le ramasse-miettes;
de facon asynchrone, avec un processus leger de basse priorite;
la methode finalize() permet de specifier des actions `a effecruer au moment de la destruction de lobjet (operations de
nettoyage, fermeture de fichiers ...).
Lappel au ramasse-miettes peut etre force par lappel
[Link]().
this et super sont des references sur lobjet courant.
super designe lobjet courant avec le type p`ere. Il indique que
la methode invoquee ou le membre dobjet designe doit etre
recherche dans la classe de base. Il y a des restrictions dusage
(f(super) est interdit).
Class Disque {
protected void finalize(){
[Link]("Disque detruit"); }
}
Lusage de this et super est special dans les constructeurs.
Marie-Pierre Beal
53
Jean Berstel
Marie-Pierre Beal
Points et disques : exemple de d
el
egation
Une methode redefinie est une methode dune classe derivee qui a
meme signature que la methode m`ere, cest-`a-dire meme :
class Pixel {
int x, y;
Pixel (int x, int y) {
this.x = x; this.y = y;
}
void translate(int dx, int dy) {
this.x += dx; this.y += dy;
}
@Override public String toString() {
return(this.x + ", " + this.y);
}
}
class Disk {
Pixel center;
int radius;
Disk(int x, int y, int radius) {
center = new Pixel(x,y);
[Link] = radius;
}
@Override
public String toString() {
return [Link]() + " ," + radius;
}
void translate(int dx, int dy) {
[Link](dx, dy); // d
el
egation
}
}
class DiskTest {
public static void main(String[] args) {
Disk d = new Disk(3, 5, 1);
[Link](d); // 3, 5 ,1
[Link](5,-2);
[Link](d); // 8, 3 ,1
}
}
55
Jean Berstel
Red
efinition
Il ne faut pas confondre derivation et delegation.
Marie-Pierre Beal
54
nom;
suite des types des param`etres;
type de retour (ou un sous-type de celui-ci (jdk 1.5)).
De plus :
les exceptions levees doivent aussi etre levees par la methode
de la classe m`ere, et etre au moins aussi precises.
la visibilite de la methode doit etre au moins aussi bonne que
celle de la methode de la classe m`ere (pas de restriction de
visibilite).
En cas de redefinition, la methode invoquee est determinee par le
mecanisme de liaison tardive (voir juste apr`es).
En cas de redefinition, la methode de la classe de base nest plus
accessible `a partir de lobjet appelant : la methode de la classe de
base est masquee.
Jean Berstel
Marie-Pierre Beal
56
Jean Berstel
Mecanisme de determination de la methode appelee I
public class Alpha{
void essai(Alpha a){
[Link]("alpha");
}
}
Pre-selection au niveau statique
Au niveau statique, le compilateur ne connat pas la nature de
lobjet, mais le type de sa reference.
public class Beta extends Alpha {
void essai(Beta b){
[Link]("beta");
}
public static void main(String[] args) {
Beta b = new Beta();
Alpha c = new Beta();
[Link](c);
}
}
public class Alpha{
void essai(Alpha a){
(1)
[Link]("alpha");
}}
public class Beta extends Alpha {
void essai(Beta b){ (2)
[Link]("beta");
}
public static void main(String[] args) {
Beta b = new ??();
Alpha c = new ??();
Beta essai( Alpha );
}}
public class Gamma extends Beta {
@Override
void essai(Alpha a){
[Link]("gamma");
}
public static void main(String[] args){
Beta d = new Gamma();
Alpha e = new Gamma();
[Link](e);
}
}
Il pre-selectionne une methode visible, de profil compatible
avec lappel. Les types des arguments doivent etre compatibles en tenant compte de lautoboxing et du sous-typage. Ici :
essai(Alpha).
Au niveau dynamique
Chaque objet a un pointeur sur une table de pointeurs de fonctions. Pour un objet Beta,
On obtient
essai(Alpha) (1),
essai(Beta) (2),
$ java Beta
alpha
$ java Gamma
gamma
Marie-Pierre Beal
La methode appelee est alors determinee par la nature de
lobjet appelant (liaison tardive) en fonction des methodes
pre-selectionnees et de cette table : ici (1).
57
Jean Berstel
Mecanisme de determination de la methode appelee II
Pre-selection au niveau statique
Au niveau statique, le compilateur voit
58
Jean Berstel
Mecanisme de determination de la methode appelee III
public class Alpha{
void essai(Alpha a){
(1)
[Link]("alpha");
}}
public class Beta extends Alpha {
void essai(Beta b){ (2)
[Link]("beta");
}
}}
public class Gamma extends Beta {
@Override void essai(Alpha a){ (3)
[Link]("gamma");
}
public static void main(String[] args){
Beta d;
if ([Link]()> O.5) d = new Gamma();
else d = new Beta();
Alpha e = new Gamma();
[Link](e);
}}
public class Alpha{
void essai(Alpha a){
(1)
[Link]("alpha");
}}
public class Beta extends Alpha {
void essai(Beta b){ (2)
[Link]("beta");
}
}}
public class Gamma extends Beta {
@Override void essai(Alpha a){ (3)
[Link]("gamma");
}
public static void main(String[] args){
Beta d = new ??();
Alpha e = new ??();
Beta essai(Alpha);
}}
Ici essai(Alpha) et essai(Beta) sont visibles (On voit statiquement au-dessus de Beta). Seule essai(Alpha) est compatible.
Au niveau dynamique
Au niveau statique, seule essai(Alpha) est compatible.
Si lobjet d est un Gamma. Sa table est
essai(Alpha) (3),
essai(Beta) (2).
Si lobjet d est un Beta. Sa table est
Lobjet d est un Gamma. Sa table est
essai(Alpha) (1),
essai(Beta) (2).
essai(Alpha) (3),
essai(Beta) (2),
La methode appelee est alors determinee par la nature de
lobjet appelant, ici (3).
Marie-Pierre Beal
Marie-Pierre Beal
59
Jean Berstel
La methode appelee est (1) ou (3). On ne peut le savoir (statiquement).
Marie-Pierre Beal
60
Jean Berstel
Mecanisme de determination de la methode appelee IV
Le transtypage
modifie le type de la reference `a un objet;
naffecte que le traitement des references : ne change jamais
le type de lobjet;
class A{
void f(A o) { [Link]("1 ");} (1)
}
class B extends A{
void f(A o) { [Link]("2 ");} (2)
void f(B o) { [Link]("3 ");} (3)
}
class Test{
public static void main(String[] args){
A a = new A();
A ab = new B();
B b = new B();
ab.f(b);
}
est implicite ou explicite.
On a vu que le sous-typage est automatique et quil concide avec
la derivation en Java : une variable de type B peut contenir implicitement une reference `a un objet de toute classe derivee D
de B.
Commentaires :
Cette r`egle sapplique aussi si B est une interface et D
implemente B;
La relation est transitive;
Pre-selection au niveau statique
Au niveau statique, le compilateur ne voit que f(A), qui est
compatible avec le sous-typage des arguments.
Cette r`egle sapplique aussi aux param`etres dune methode :
pour
C f(B b) {...}
Au niveau dynamique
on peut faire lappel f(d), avec d de classe D
Lobjet ab est un B. Sa table est
Cette r`egle sapplique aussi aux valeurs de retour dune
methode : pour la methode ci-dessus, on peut ecrire
f(A) (2),
f(B) (3),
r = f(b);
La methode appelee est (2).
si r est dune superclasse de C.
Marie-Pierre Beal
61
Jean Berstel
Le transtypage explicite dune reference nest valide que si lobjet
sousjacent est dune classe derivee.
// sous-typage automatique
Pixel p = new ThickPixel(5, 7, 1);
ThickPixel q;
q = p;
// erreur
// transtypage explicite ou cast
q = (ThickPixel) p; // ok
Marie-Pierre Beal
62
Jean Berstel
Ceci permet labstraction. Une methode generique peut etre
utilisee dans A. Cette methode est specialisee dans les classes
derivees.
En r
esum
e, types et classes ne sont pas la meme chose.
Variables have type, objects have class;
un objet ne change jamais de classe;
les references peuvent changer de type;
la verification des types est statique (`a la compilation);
la determination de la methodes `a invoquer est surtout dynamique (`a lexecution). Elle comporte une part statique.
Int
er
et du transtypage
permet de forcer lappel dune methode en changeant le type
dun argument.
permet le polymorphisme. Des objets de natures differentes
derivant dune meme classe A peuvent etre types par cette
classe. Par le mecanisme de liaison tardive, la methode appelee
en cas de redefinition dans les sous-classes, est la methode de
lobjet. Le fait quils soient types par A ne gene pas.
Ceci permet lencapsulation : on donne le nom de la methode
dans A (en general une interface), limplementation se fait dans
les sous-classes et peut etre cachee.
Marie-Pierre Beal
63
Jean Berstel
Marie-Pierre Beal
64
Jean Berstel
Heritage : interfaces
Program to Interfaces
Rectangles et ellipses
Une interface est une classe
Une classe Rectangle serait :
na que des methodes abstraites et tacitement publiques;
et na que des donnees static immuables (final).
Une interface sert `a specifier des methodes quune classe doit avoir,
sans indiquer comment les realiser.
Une classe abstraite est une classe
peut avoir des methodes concr`etes ou abstraites.
Une methode abstraite est declaree mais non definie.
Une classe abstraite sert en general `a commencer les
implementations (parties communes aux classes qui en deriveront).
On ne peut creer dinstance que dune classe concr`ete. Toutes les
methodes doivent etre definies dans la classe ou les classes m`eres.
Pas de new AbstractShape().
Linterface est le point ultime de labstraction. Cest un style de
programmation `a encourager.
class Rectangle {
double width, height;
Rectangle(double width, double height) {
[Link] = width; [Link] = height;
}
double getArea() {return width*height;}
String toStringArea() {
return "aire = "+getArea();
}
}
et une classe Ellipse serait
class Ellipse {
double width, height;
Ellipse(double width, double height) {
[Link] = width; [Link] = height;
}
double getArea(){
return width*height*[Link]/4;}
String toStringArea() {
return "aire = "+getArea();
}
}
Ces classes ont une abstraction commune, qui
definit les methodes de meme implementation;
declare les
differentes.
Marie-Pierre Beal
65
Jean Berstel
Linterface Shape
methodes
communes
Marie-Pierre Beal
et
dimplementation
66
Jean Berstel
On sen sert par exemple dans :
interface Shape {
double getArea();
String toStringArea();
}
La classe abstraite AbstractShape definit limplementation de
toStringArea
abstract class AbstractShape implements Shape {
double width, height;
AbstractShape(double width, double height) {
[Link] = width; [Link] = height;
}
public String toStringArea() {
return "aire = " + getArea();
}
}
Shape r = new Rectangle(6,10);
Shape e = new Ellipse(3,5);
[Link]([Link]());
[Link]([Link]());
ou dans :
Shape[] tab = new Shape[5];
tab[0] = new Rectangle(6,10);
tab[1] = new Ellipse(3,5);
...
for (Shape s:tab)
[Link]([Link]());
Les methodes abstraites sont implementees dans chaque classe
concr`ete.
class Rectangle extends AbstractShape{
Rectangle(double width, double height) {
super(width, height);
}
public double getArea() {return width*height;}
}
et
class Ellipse extends AbstractShape {
Ellipse(double width, double height) {
super(width, height);
}
public double getArea() {return [Link]*width*height/4;}
}
Marie-Pierre Beal
67
Jean Berstel
Marie-Pierre Beal
68
Jean Berstel
Exemples dinterface : les matrices suite
On peut tester le type dun objet `a laide de instanceof :
Shape s = new Rectangle(6,10);
if
if
if
if
(s
(s
(s
(s
instanceof
instanceof
instanceof
instanceof
interface Matrix {
Matrix add(Matrix a);
void setAt(int i, int j, int value);
void transpose();
}
Object) {...} // vrai
Shape) {...} // vrai
Rectangle) {...} // vrai
Ellipse) {...} // faux
Lusage de instanceof est restreint `a des cas bien particuliers. Il
ne doit pas se substituer au polymorphisme.
Marie-Pierre Beal
69
Jean Berstel
Deux implementations, `a savoir des matrices generales et des matrices symetriques, se partagent une classe abstraite commune.
//Abstract class for matrices of ints.
public abstract class AbstractMatrix implements Matrix{
int[][] m;
public AbstractMatrix(int dim) {
this(dim,0);
}
public AbstractMatrix(int dim, int n) {
m = new int [dim][dim];
for (int i = 0; i < dim; i++)
for (int j = 0; j < dim; j++)
m[i][j] = n;
}
@Override public String toString(){
StringBuilder sb = new StringBuilder();
for (int[] t : m){
for (int x : t){
[Link](x);
[Link](" ");
}
[Link]("\n");
}
return [Link]();
}
}
Marie-Pierre Beal
Les classes specifiques se contentent dimplementer les autres
methodes:
public class GeneralMatrix extends AbstractMatrix{
public GeneralMatrix(int dim){
super(dim);
}
public GeneralMatrix(int dim, int n){
super(dim,n);
}
public void transpose() {
int dim = [Link];
for (int i = 0; i < dim; i++)
for (int j = i+1; j < dim; j++){
int t = m[i][j];
m[i][j] = m[j][i];
m[j][i]=t;
}
}
public void setAt(int i, int j, int value) {
m[i][j] = value;
}
public Matrix add(Matrix a){
int n = [Link];
Matrice s = new GeneralMatrice(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
[Link](i, j, m[i][j] + ((AbstractMatrice)a).m[i][j]);
return s;
}
}
public class SymmetricMatrix extends AbstractMatrix{
public SymmetricMatrix(int dim) {
super(dim);
}
public SymmetricMatrix(int dim, int n){
super(dim,n);
}
Marie-Pierre Beal
71
Jean Berstel
70
Jean Berstel
public void transpose() {}
public void setAt(int i, int j, int value) {
m[i][j] = m[j][i] = value;
}
public Matrix add(Matrix a){
if (a instanceof SymmetricMatrix){
int n = [Link];
SymmetricMatrix sa = (SymmetricMatrix) a;
Matrix s = new SymmetricMatrix(n);
for (int i = 0; i < n; i++)
for (int j = 0; j < n; j++)
[Link](i, j, m[i][j] + sa.m[i][j]);
return s;
}
else return [Link](this);
}
public static void main(String[] args) {
Matrix a = new GeneralMatrix(3,12);
[Link](1,2,0);
[Link](a);
Matrix b = new SymmetricMatrix(3,14);
[Link](1,2,0);
[Link](b);
Matrix s = [Link](b); [Link](s);
Matrix t = [Link](b); [Link](t);
}
}
Resultat :
12 12 12
12 12 0
12 12 12
Marie-Pierre Beal
14 14 14
14 14 0
14 0 14
26 26 26
26 26 0
26 12 26
72
28 28 28
28 28 0
28 0 28
Jean Berstel
dun conteneur.
class Carre implements Function {
public int applyIt(int n) {
return n*n;
}
}
On encapsule une methode dans une interface :
interface Function {
int applyIt(int n);
}
On encapsule la fonction mapcar dans une autre interface :
interface Map {
void map(Function f);
}
Une classe qui peut realiser un map implemente cette interface :
class Tableau implements Map {
int[] a;
Tableau(int n) {
a = new int[n];
for (int i = 0; i < n; i++)
a[i] = i + 1;
}
public void map(Function f) {
for (int i = 0; i < [Link]; i++)
a[i] = [Link](a[i]);
}
public String toString() {...}
}
Marie-Pierre Beal
73
Un exemple dutilisation:
public class TestMap {
public static void main(String args[]) {
Tableau t = new Tableau(10);
Function square = new Carre();
[Link](t);
[Link](square);
[Link](t);
}
}
1 2 3 4 5 6 7 8 9 10
1 4 9 16 25 36 49 64 81 100
Jean Berstel
Marie-Pierre Beal
74
Jean Berstel
Il y a debordement lorsque lon fait
Exceptions
peek pour une pile vide;
pop pour une pile vide;
Voici une classe pile contenant des int, implementee par un tableau.
public class Stack{
static final int MAX=4;
int height = 0;
int[] table = new int[MAX];
Une pile ne peut pas proposer de solution en cas de debordement,
mais elle doit signaler (et interdire) le debordement. Cela peut se
faire par lusage dune exception.
public boolean isEmpty() {
return height == 0;
}
Une exception est un objet dune classe qui etend la classe
Exception.
[Link]
|_ [Link]
|_java.[Link]
|_java.[Link]
|_java.[Link]
|_ ...
|_java.[Link]
|_java.[Link]
|_java.[Link]
|_ ...
public boolean isFull() {
return height == MAX;
}
public void push(int item) {
table[height++] = item;
}
public int peek() {
return table[height-1];
}
public int pop() {
--height;
return table[height];
}
Pour les piles, on peut definir par exemple une nouvelle exception.
class StackException extends Exception {}
En cas de debordement, on l`eve une exception, par le mot throw.
On doit signaler la possible levee dans la declaration par le mot
throws.
Marie-Pierre Beal
push pour une pile pleine.
75
Jean Berstel
Marie-Pierre Beal
76
Jean Berstel
catch (Type1Exception e) { .... }
catch (Type2Exception e) { .... }
catch (Exception e) { .... }
// cas par defaut, capture les
// exceptions non traitees plus haut
finally {....} // toujours execute
void push(int item) throws StackException {
if (isFull())
throw new StackException("Pile pleine");
table[height++] = item;
}
Leffet de la levee est
la propagation dun objet dune classe dexceptions qui est en
general cree par new;
la sortie immediate de la methode;
la remontee dans larbre dappel `a la recherche dune methode
qui capture lexception.
La capture se fait par un bloc try / catch. Par exemple,
...
Stack s = new Stack();
try {
[Link]("top = "+[Link]());
} catch(StackException e) {
[Link]([Link]());
}
...
Exemple
try {
catch
catch
// le
... }
(Exception e) { .... }
(StackException e) { .... }
deuxi`
eme jamais ex
ecut
e
Une levee dexception se produit lors dun appel `a throw ou dune
methode ayant leve une exception. Ainsi lappel `a une methode
pouvant lever une exception doit etre :
ou bien etre contenu dans un bloc try / catch pour capturer
lexception;
ou bien etre dans une methode propageant cette classe
dexception (avec throws).
Les exceptions derivant de la classe RuntimeException nont pas
`a etre capturees.
Le bloc try lance une execution controlee.
En cas de levee dexception dans le bloc try, ce bloc est quitte
immediatement, et lexecution se poursuit par le bloc catch.
Le bloc catch recoit en argument lobjet cree lors de la levee
dexception.
Plusieurs catch sont possibles, et le premier dont largument
est du bon type est execute. Les instructions du bloc finally
sont executees dans tous les cas.
Marie-Pierre Beal
77
Jean Berstel
Marie-Pierre Beal
Voici une interface de pile dint, et deux implementations.
}
}
Implementation par listes chanees (classe interne Liste).
class StackException extends Exception {
StackException(String m) {super(m);}
}
Implementation par tableau
public class ArrayStack implements Stack {
static final int MAX=4;
private int height = 0;
private int[] table = new int[MAX];
public boolean isEmpty() {
return height == 0;
}
public boolean isFull() {
return height == MAX;
}
public void push(int item) throws StackException {
if (isFull())
throw new StackException("Pile pleine");
table[height++] = item;
}
public int peek() throws StackException{
if (isEmpty())
throw new StackException("Pile vide");
return table[height-1];
}
public int pop() throws StackException{
if (isEmpty())
79
Jean Berstel
throw new StackException("Pile vide");
--height;
return table[height];
interface Stack {
boolean isEmpty ();
boolean isFull();
void push(int item) throws StackException;
int peek() throws StackException;
int pop() throws StackException;
}
Marie-Pierre Beal
78
Jean Berstel
public class LinkedStack implements Stack{
private Liste head = null;
class Liste {
int item;
Liste next;
Liste(int item, Liste next) {
[Link] = item; [Link] = next;
}
}
public boolean isEmpty() {
return head == null;
}
public boolean isFull() {
return false;
}
public void push(int item) throws StackException{
head = new Liste(item, head);
}
public int peek() throws StackException{
if (isEmpty())
throw new StackException("Pile vide");
return [Link];
}
public int pop() throws StackException{
if (isEmpty())
throw new StackException("Pile vide");
int i = [Link];
head = [Link];
return i;
}}
Marie-Pierre Beal
80
Jean Berstel
interface Stack<E>{
boolean isEmpty ();
boolean isFull();
void push(E item) throws StackException;
E peek() throws StackException;
E pop() throws StackException;
}
public class LinkedStack<E> implements Stack<E>{
private Liste<E> head = null;
class Liste<E>{
E item;
Liste<E> next;
Liste(E item, Liste<E> next){
[Link] = item; [Link] = next;
}}
public boolean isEmpty() {
return head == null;
}
public boolean isFull() {
return false;
}
public void push(E item) throws StackException{
head = new Liste<E>(item, head);
}
public E peek() throws StackException{
if (isEmpty())
throw new StackException("Pile vide");
return [Link];
}
public E pop() throws StackException{
if (isEmpty())
throw new StackException("Pile vide");
E i = [Link];
head = [Link];
return i;
}}
public class Test{
public static void main(String[] args) {
Stack s = new ArrayStack(); //par table
try {
[Link](2); [Link]();
[Link](); // ca coince
[Link](); // jamais atteint
}
catch(StackException e) {
[Link]([Link]());
[Link]();
}
Stack t = new LinkedStack(); //par liste
try {
[Link](2); [Link](5);
[Link](); [Link]();
[Link]([Link]()); // ca coince
}
catch(StackException e) {
[Link]([Link]());
[Link]();
}
}
}
On obtient
Pile vide
StackException: Pile vide
at [Link]([Link])
at [Link]([Link])
Pile vide
StackException: Pile vide
at [Link]([Link])
at [Link]([Link])
Marie-Pierre Beal
81
Jean Berstel
Marie-Pierre Beal
Utilisation
82
Jean Berstel
Abrasure
public class Test{
public static void main(String[] args) {
Stack<Integer> s = new LinkedStack<Integer>();
try {
[Link](2); [Link]();
[Link](3L); //ne compile pas
[Link](); // ca coince
[Link](); // jamais atteint
}
catch(StackException e) {
[Link]([Link]());
[Link]();
}
Stack<Boolean> t = new LinkedStack<Boolean>();
try {
[Link](true); [Link](false); //test `
a la compilation
[Link](); [Link]();
[Link]([Link]()); // ca coince
} catch(StackException e) {
[Link]([Link]());
[Link]();
}
}
}
Les types parametres sont utilises pour permettre de verifier
`a la compilation des concordances de types tout en gardant la
genericite.
Le compilateur transforme ensuite les types parametres par le
mecanisme dabrasure.
Pour la machine virtuelle, les types parametres nexistent pas.
public class LinkedStack<E> implements Stack<E>{
private Liste<E> head = null;
class Liste<E>{
E item;
Liste next;
Liste(E item, Liste<E> next){
[Link] = item; [Link] = next;
}}
public void push(E item) throws StackException{
head = new Liste<E>(item, head);
}
est change en
public class LinkedStack implements Stack{
private Liste head = null;
class Liste{
Object item;
Liste next;
Liste(Object item, Liste next){
[Link] = item; [Link] = next;
}}
public void push(Object item) throws StackException{
head = new Liste(item, head);
}
et
Marie-Pierre Beal
83
Jean Berstel
Marie-Pierre Beal
84
Jean Berstel
Un pattern de creation : les fabriques
public static void main(String[] args) {
Stack<Integer> s = new LinkedStack<Integer>();
try {
[Link](2); [Link]();
[Link](3L); //ne compile pas
[Link](); // ca coince
[Link](); // jamais atteint
}
Une fabrique est une classe dont des methodes ont en charge la
construction dobjets dune autre classe.
Realisation : une methode
Box createBox() {return new Box();}
est change en
Exemple : On cherche une methode testVersion() qui permet
de remplacer le corps de la methode main de lexemple par deux
appels. Voici quelques variantes.
public class Test{
public static void main(String[] args) {
Stack s = new LinkedStack();
try {
[Link]((Integer)2); [Link]();
[Link]((Integer)3L);
// erreur de compilation ici
(Integer)[Link]();
(Integer)[Link]();
}
public static void testVersion1(Stack s) {
try {
[Link](2); [Link](5);
[Link](); [Link]();
[Link]([Link]());
}
catch(StackException e) {
[Link]([Link]());
}
}
utilise avec
testVersion1(new ArrayStack());
testVersion1(new LinkedStack());
Si lon veut creer `a linterieur de la methode de test:
public static void testVersion2(boolean version) {
Stack s;
if (version)
s = new ArrayStack();
else
s = new LinkedStack();
...
}
Marie-Pierre Beal
85
Jean Berstel
Marie-Pierre Beal
utilise avec
86
Jean Berstel
Paquetages
testVersion2(true);
testVersion2(false);
On peut delocaliser la creation en une methode de fabrique.
public static Stack createStack(boolean version) {
if (version) return new ArrayStack();
else return new LinkedStack();
}
Les classes dun paquetage sont dans un meme repertoire decrit
par le nom du paquetage.
Le nom est relatif aux repertoires
denvironnement CLASSPATH.
public static void testVersion3(boolean version) {
Stack s;
s = createStack(version);
...
}
la
variable
Par exemple, le paquetage [Link] est dans le repertoire
java/awt/event (mais les classes Java sont zippees dans les
archives).
testVersion3(true);
testVersion3(false);
On peut enfin transmettre un descripteur de classe:
public static <T> T factory(Class<T> clazz)
throws IllegalAccessException, InstantiationException{
return [Link]();
}
La methode T newInstance() de la classe Class<T> est une
methode de fabrique. On utilise cette methode avec
Stack s;
try {
s = factory([Link]);
s = factory([Link]);
}
catch(IllegalAccessException e) {}
catch(InstantiationException e) {}
87
de
Les noms de paquetage sont en minuscule.
utilise avec
Marie-Pierre Beal
Paquetage (package): un mecanisme de groupement de classes.
Importer [Link].* signifie que lon peut nommer les
classes dans ce repertoire par leur nom local, `a la place du nom absolu. Cela ne concerne que les fichiers .class et non les repertoires
contenus dans ce repertoire.
Exemple :
class MyApplet extends Applet non trouvee
class MyApplet extends [Link] ok
import [Link];
class MyApplet extends Applet ok
import [Link].*;
class MyApplet extends Applet ok
Jean Berstel
Marie-Pierre Beal
88
Jean Berstel
package repertoire;
en debut de chaque fichier .java qui en fait partie. Le
fichier .java doit se trouver dans un repertoire ayant pour nom
repertoire.
Par defaut, le paquetage est sans nom (unnamed), et correspond
au repertoire courant.
Si une meme classe apparat dans deux paquetages importes globalement, la classe utilisee doit etre importee explicitement.
Visibilite et paquetages
Visibilite des classes et interfaces
Une classe ou une interface qui est declaree public est accessible
en dehors du paquetage.
Si elle nest pas declaree public, elle est accessible `a linterieur du
meme paquetage, mais cachee en dehors.
Il faut declarer publiques les classes utilisees par les clients
utilisant le paquetage et cacher les classes donnant les details
dimplementation.
Ainsi, quand on change limplementation, les clients ne sont pas
concernes par les changements puisquils ny ont pas acc`es.
Marie-Pierre Beal
89
Jean Berstel
Marie-Pierre Beal
Differences entre Java et C++
90
Jean Berstel
Programmation des listes chanees
Java na pas
Une liste est une suite dobjets.
de fichier en-tete separes (.h et .c),
Comme sequence (a1, . . . , an), elle se programme iterativement.
de variable ou fonctions globales,
Comme structure imbriquee
de preprocesseur (#define ou #include),
(a1, (a2, ( (an, ()) )))
de valeurs par defaut dans les fonctions,
elle se definit recursivement.
de pointeurs (pas de pointeurs de fonction),
Une cellule est
de surcharge doperateurs,
de passage dargument par recopie,
soit une cellule vide
dallocation statique de memoire.
soit un cons dun objet et dune cellule
Java a
une methode finalize() appelee `a la destruction dobjets,
une classe universelle (Object) et des types parametres,
un heritage simple, mais la possibilite dimplementer un nombre
quelconque dinterfaces,
la possibilite de determiner le type dun objet `a lexecution
(instanceof),
des possibilites dintrospection : [Link],
une grande robustesse par verification : IndexOutOfBoundsException, ClassCastException, etc.
de nombreuses classes utilitaires predefinies.
Marie-Pierre Beal
91
Jean Berstel
Une liste contient une cellule initiale. Ceci conduit `a une classe
pour les listes, avec trois interfaces, pour les cellules, les cellules
cons et les cellules vides.
public class Liste {
Cell init ;
public Liste () {init = new ConcreteNil();}
public int length() {return [Link]();}
}
interface Cell {
int length();
}
interface Cons extends Cell {
Object getElem();
void setElem(Object o);
Cell getNext();
Marie-Pierre Beal
92
Jean Berstel
public class ListeTest{
public static void main(String[] args) {
Liste l = new Liste();
[Link] = new ConcreteCons(1,
new ConcreteCons(2,new ConcreteNil()));
[Link]("liste de longueur "+ [Link]());
}
}
interface Nil extends Cell {}
Limplementation se fait naturellement:
class ConcreteCons implements Cons{
private Object o;
private Cell next;
ConcreteCons(Object o, Cell next){
this.o = o;
[Link] = next;
}
public Object getElem(){
return o;
}
public void setElem(Object o){
this.o = o;
}
public Cell getNext(){
return next;
}
public void setNext(Cell next){
[Link] = next;
}
public int length(){
return [Link]()+1;
}
}
Plusieurs appels `a ConcreteNil() creent des cellules vides
differentes. Pour leviter, on change :
public class ConcreteNil implements Nil{
private static Cell nulle = new ConcreteNil();
private ConcreteNil() {}
public static Cell getNil() {return nulle;}
public int length(){return 0;}
}
avec bien sur
[Link] = new ConcreteCons(1,
new ConcreteCons(2, [Link]()));
class ConcreteNil implements Nil {
public int length(){
return 0;
}
}
Marie-Pierre Beal
93
Jean Berstel
Marie-Pierre Beal
Un pattern de creation : singleton
Realisation
un attribut prive statique instance designant linstance;
une methode publique de creation qui teste si linstance existe
dej`a;
un constructeur prive.
Exemple
public class ConcreteNil implements Nil {
private static ConcreteNil instance = null;
private ConcreteNil() {}
public static Cell getNil(){
if (instance == null)
instance = new ConcreteNil();
return instance;
}
public int length(){return 0;} // autres m
ethodes
}
95
Jean Berstel
Listes chanees generiques
Une classe singleton est une classe qui ne peut avoir quune seule
instance.
Marie-Pierre Beal
94
Jean Berstel
public class Liste<E> {
Cell<E> init ;
public Liste() { init = new ConcreteNil<E>();}
public int length() { return [Link]();}
public Iterator<E> iterator() { ... }
}
interface Cell<E> {
int length();
}
interface Cons<E> extends Cell<E> {
E getElem();
void setElem(E o);
Cell<E> getNext();
void setNext(Cell<E> next);
}
interface Nil<E> extends Cell<E> {}
Limplementation se fait naturellement:
class ConcreteCons<E> implements Cons<E> {
private E o;
private Cell<E> next;
ConcreteCons(E o, Cell<E> next){
this.o = o;
[Link] = next;
}
public E getElem(){
return o;
}
public void setElem(E o){
this.o = o;
Marie-Pierre Beal
96
Jean Berstel
public Cell<E> getNext(){
return next;
}
public void setNext(Cell<E> next){
[Link] = next;
}
public int length(){
return [Link]()+1;
}
Les classes fondamentales
}
class ConcreteNil<E> implements Nil<E> {
public int length(){
return 0;
}
}
1. Presentation des API
Usage:
public class ListeTest {
public static void main(String[] args) {
Liste<Integer> l = new Liste<Integer>();
[Link] = new ConcreteCons<Integer>
(1, new ConcreteCons<Integer>
(2,new ConcreteNil<Integer>()));
[Link]("liste de longueur "+ [Link]());
}
}
Marie-Pierre Beal
97
Jean Berstel
2. La classe [Link]
m`ere de toutes les classes
3. Les chanes de caract`eres
4. Outils mathematiques
5. Ensembles structures, iterateurs et comparateurs
6. Introspection
Marie-Pierre Beal
Les API
[Link]
classes de base du langage
[Link]
entrees / sorties
[Link]
ensemble doutils : les classes tr`es util
[Link]
classes reseaux
[Link] classes pour les appliquettes
[Link]
interfaces graphiques (Abstract Windowing Toolkit)
[Link] interfaces graphiques
...
et de nombreuses autres.
99
Jean Berstel
La classe [Link]
Les API (Application Programming Interface) forment linterface
de programmation, cest-`a-dire lensemble des classes livrees avec
Java.
Marie-Pierre Beal
98
Jean Berstel
protected Object
clone()
throws CloneNotSupportedException
public boolean
equals(Object obj)
protected void
finalize()
public final Class<?> getClass()
public int
hashCode()
public String
toString()
public final void
notify()
public final void
notifyAll()
public final void
wait()
public final void
wait(long timeout)
public final void
wait(long timeout, int nanos)
Marie-Pierre Beal
100
Jean Berstel
Le clonage
La methode toString() retourne la representation dun objet
sous forme de chane de caract`eres (par defaut le nom de la classe
suivi de son hashcode) :
[Link](new Integer(3).toString());
//affiche 3
[Link](new Object().toString());
//affiche [Link]@1f6a7b9
La valeur du hashCode peut etre obtenue par la methode
hashCode() de la classe Object.
Le clonage est la construction dune copie dun objet.
La classe Object contient une methode
Protected Object clone() throws CloneNotSupportedException.
Quand elle est appelee sur un objet dune classe qui implemente
linterface Cloneable, elle cree une copie de lobjet du meme
type. On a une copie superficielle de lobjet : les attributs de
lobjet sont alors recopies.
Quand elle est appelee sur un objet dune classe qui
nimplemente pas linterface Cloneable, elle l`eve lexception
CloneNotSupportedException.
La class Object nimplemente pas linterface Cloneable !
Exemple:
public class Pixel implements Cloneable {
private int x, y;
public Pixel (int x, int y) {
this.x = x; this.y = y;
}
public int getX(){
return this.x
}
public void setX(int x){
this.x=x;
}
@Override public String toString() {
return(this.x + ", " + this.y);
}
Marie-Pierre Beal
101
Jean Berstel
public static void main(String[] args)
throws CloneNotSupportedException
{
Pixel a = new Pixel(3,5);
Pixel b = (Pixel) [Link](); // m
ethode clone() de Object
[Link]([Link]() + 1);
[Link](a); // 3 5
[Link](b); // 4 5
}
}
Si on veut une classe clonable et une classe derivee non clonable, la
classe derivee implemente Cloneable mais on l`eve une exception
dans lecriture de clone().
Exemple de clonage
102
Jean Berstel
public Object clone() throws CloneNotSupportedException {
Stack instance = (Stack) [Link]();
[Link] = (Integer[]) [Link]();
return instance;
}
}
public class Test{
public static void main(String[] args) {
Stack s = new Stack(2);
[Link](5);
[Link](6);
try {
Stack t = (Stack) [Link]();
[Link]([Link]()); // 6
[Link]([Link]()); // 5
} catch (CloneNotSupportedException e) {}
}}
Remarquer lutilisation de [Link]() qui appelle clone()
de Object cree toujours un objet du bon type. Lappel `a clone()
sur un objet dune classe derivee de Stack serait incorrect si on
avait utilise new Stack().
Exemple
Le clonage par defaut est superficiel.
public class Stack implements Cloneable {
int height;
Integer[] table;
public Stack (int max) {
height = 0;
table = new Integer[max];
}
public class PriceStack extends Stack{
int price;
public PriceStack (int max) {
super(max);
price = 0;
}
public void push(Integer item) {
table[height++]=item;
}
public Object clone() throws CloneNotSupportedException
PriceStack instance = (PriceStack) [Link]();
// [Link] = price; (facultatif)
return instance;
}}
public Integer pop() {
return table[--height];
}
Marie-Pierre Beal
Marie-Pierre Beal
103
Jean Berstel
Marie-Pierre Beal
104
Jean Berstel
La methode equals() de la classe Object determine si deux objets sont egaux. Par defaut deux objets sont egaux sils sont accessibles par la meme reference.
Toute classe herite des deux methodes de Object
public boolean equals(Object o)
public int hashCode()
qui peuvent etre redefinies en respectant the Object Contract.
The Object Contract
equals doit definir une relation dequivalence;
equals doit etre consistente. (Plusieurs appels donnent le
meme resultat);
[Link](null) doit etre faux (si x est une reference);
hashCode doit donner la meme valeur sur des objets egaux par
equals.
Marie-Pierre Beal
105
Jean Berstel
Soit la classe Duration :
Remarquer que largument de equals est de type Object. Si
largument etait Rectangle, la methode serait surchargee. Elle
serait alors ignoree lors dun appel avec un argument de type Shape
qui reference un Rectangle. La comparaison entre les deux rectangles serait alors incorrecte.
Marie-Pierre Beal
106
Jean Berstel
Cette definition qui a lair correcte viole le contrat de symetrie :
public class Duration {
private final int hours;
private final int seconds;
public Duration(int hours, int seconds) {
[Link] = hours;
[Link] = seconds;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Duration))
return false;
Duration d = (Duration)o;
return ((hours == [Link]) && (seconds == [Link]));
}
@Override
public int hashCode() {
return new Integer(hours).hashCode() +new Integer(seconds).hashCode();
}
On consid`ere la classe derivee NanoDuration :
public class NanoDuration extends Duration {
private final int nanoSeconds;
public NanoDuration(int hours, int seconds, int nanoSeconds) {
super(hours,seconds);
[Link] = nanoSeconds;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof NanoDuration))
return false;
NanoDuration nd = (NanoDuration)o;
return [Link](nd) && (nanoSeconds == [Link]);
}
@Override
public int hashCode() {
return [Link]()+ new Integer(nanoSeconds).hashCode();
}
Marie-Pierre Beal
class Rectangle extends Shape{
final int width;
final int height;
Rectangle(int width, int height) {
[Link] = width;
[Link] = height;
}
@Override
public boolean equals(Object o) {
if (!(o instanceof Rectangle))
return false;
Rectangle rarg = (Rectangle)o;
return (width == [Link])
&& (height == [Link]);
}
@Override
public int hashCode() {
return new Integer(width).hashCode() + new Integer(height).hashCode()
}
107
Jean Berstel
public class Test{
public static void main(String[] args) {
Duration d = new Duration(2,80);
NanoDuration nd = new NanoDuration(2,80,100);
[Link]([Link](nd)); //true
[Link]([Link](d)); //false
}
En fait, il ny a pas de solution en redefinissant uniquement equals
dans la classe derivee. Une premi`ere methode consiste `a changer
equals dans la classe m`ere.
public class Duration {
...
@Override
public boolean equals(Object o) {
if (o == null) || (! [Link]().equals(getClass()))
return false;
Duration d = (Duration)o;
return hours == [Link] && seconds == [Link];
}
...
Quel est linconvenient de cette methode ?
Reponse : on perd la possibilite de comparaisons pour deventuelles
autres classes derivees.
Une deuxi`eme methode consiste `a utiliser la delegation (ou composition) au lieu la derivation.
public class NanoDuration {
final Duration d;
final int nanoSeconds;
...
}
Marie-Pierre Beal
108
Jean Berstel
Les chanes de caract`eres
equals() :
String s = "toto";
String t = "toto";
if ([Link](t)) ...
La classe [Link]
// true
La methode compareTo() est lequivalent du strcmp() du C.
La classe String est final (ne peut etre derivee).
Elle utilise un tableau de caract`eres (membre prive de la classe).
Le paquetage [Link]
Un objet de la classe String ne peut etre modifie. (On doit
creer un nouvel objet).
Ce paquetage permet de faire une analyse lexixale dun texte,
et de rechercher des motifs dans un texte.
La classe
[Link] utilise ce paquetage.
Un Pattern est construit `a partir dune chane de caract`eres
representant une expression reguli`ere (cest un automate fini).
Un Matcher est un objet pret `a parcourir une chane passee en
argument pour rechercher le motif. La recherche a lieu `a laide de
les methodes matches(), lookingAt() et find().
String nom = "toto" + "tata";
[Link]([Link]()); // 8
[Link]([Link](2)); // t
On peut construire un objet String `a partir dun tableau de caract`eres :
char table = {t,o,t,o};
String s = new String(table);
Exemple
et inversement :
char[] table= "toto".toCharArray();
Conversion dun entier en chane de caract`ere :
String one = [Link](1); // methode statique
qui appelle toString()
et inversement :
int i = [Link]("12"); // ou bien :
int i = [Link]("12");
Marie-Pierre Beal
109
Jean Berstel
Raccourci :
On peut faire afficher lindice de debut du motif dans la chane
ainsi que linstance du motif trouvee.
public static void main(String[] args){
Pattern p = [Link]("aa");
Matcher m = [Link]("baaaaaaaaaaba");
while ([Link]()){
[Link]("indice "+ [Link]()+ " "+[Link]());
}
}
1
3
5
7
9
aa
aa
aa
aa
aa
La sous-chane la plus longue verifiant le motif est choisie en cas
dambigute.
public static void main(String[] args){
Pattern p = [Link]("a*");
Matcher m = [Link]("baaaaaaaaaaba");
while([Link]()){
[Link]("indice "+[Link]()+" "+[Link]());
}
}
indice
indice
indice
indice
indice
Marie-Pierre Beal
110
Jean Berstel
On peut changer ce comportement par defaut `a laide de ?.
boolean b = [Link]("a*b", "aaaaab"); // true
indice
indice
indice
indice
indice
Pattern p = [Link]("a*b"); // Cr
eation dun Pattern
Matcher m = [Link]("aaaaab");
// scanne la cha^
ne enti`
ere `
a partir du d
ebut
boolean b = [Link](); // true
m = [Link]("aaaaabaaaaab");
// scanne la cha^
ne `
a partir du d
ebut
b = [Link](); // true
[Link]();
b = [Link](); // false
// recherche la prochaine occurrence du motif
[Link]();
b = [Link](); //true
b = [Link](); //true
b = [Link](); //false
public static void main(String[] args){
Pattern p = [Link]("a+?");
Matcher m = [Link]("baaaaaaaaaaba");
while ([Link]()){
[Link]("indice "+ [Link]()+ " "+[Link]());
}
}
On peut reperer des sous-expressions dans les expressions.
public static void main(String[] args){
// Groupe 1 Groupe2 Groupe3
Pattern p = [Link]("(aac(b*))|(aa)");
Matcher m = [Link]("baaaaaaaaaabaacbba");
while ([Link]()){
[Link]("indice "+[Link]()+" "+[Link]()+" ");
for (int i=1; i<= [Link]();i++)
[Link]("groupe "+ i+": "+[Link](i)+" ");
[Link]();
}
}
indice
indice
indice
indice
indice
indice
1 aa groupe 1: null groupe 2: null
3 aa groupe 1: null groupe 2: null
5 aa groupe 1: null groupe 2: null
7 aa groupe 1: null groupe 2: null
9 aa groupe 1: null groupe 2: null
12 aacbb groupe 1: aacbb groupe 2:
groupe 3:
groupe 3:
groupe 3:
groupe 3:
groupe 3:
bb groupe
aa
aa
aa
aa
aa
3: null
0
1 aaaaaaaaaa
11
12 a
13
Marie-Pierre Beal
111
Jean Berstel
Marie-Pierre Beal
112
Jean Berstel
Scanner sc = new Scanner(input).useDelimiter("\\s+");
while ([Link]())
[Link]([Link]());
[Link]();
String replaceAll().
public static void main(String[] args){
Pattern p = [Link]("(xxc(y*))");
Matcher m = [Link]("baaaxxcaaaaaaabxxcyya");
[Link]([Link]("toto$2"));
}
donne
donne
baaatotoaaaaaaabtotoyya
public static void main(String[] args){
Pattern p = [Link]("((David)(.*)((Marion))");
Matcher m = [Link]("David aime Marion");
[Link]([Link]("$4 $3 $2"));
}
aime
Le code ci-dessous a le meme effet que [Link]().
String input = "Vincent mit 500 ^
anes dans un pr
e";
Scanner sc = new Scanner(input);
[Link]("(.+?)(\\d+)(.+)");
MatchResult result = [Link]();
[Link]([Link](2)); //affiche 500
[Link]()
donne
Marion
Vincent
mit
500
^
anes
dans
un
pr
e
David
La class [Link]
La classe Scanner a plusieurs constructeurs dont
Scanner(File source)
Scanner(InputStream source)
Scanner(String source)
Scanner(Readable source)
Utilisation dej`a vue :
Scanner sc = new Scanner([Link]);
int i = [Link]();
Marie-Pierre Beal
113
Jean Berstel
Outils mathematiques
Marie-Pierre Beal
114
Jean Berstel
Ensembles structures, iterateurs et comparateurs
On peut trouver des outils mathematiques dans les deux classes et
le paquetage suivants :
[Link]
Collection
Queue
[Link]
List
Set
Deque
[Link] (pour le travail sur des entiers ou flottants longs)
Exemple : int maximum = [Link](3,4);
Exemple : Tirer au hasard un entier entre 100 et 1000 (les deux
compris).
int maximum = 100 + (int)([Link]()*901);
ArrayDeque
LinkedList ArrayList
PriorityQueue
Vector
Stack
Une instruction arithmetique sur les entiers peut lever
lexception ArithmeticException :
HashSet
SortedSet
LinkedHashSet TreeSet
Map
try { int i = 1/0;}
catch (ArithmeticException e) {...}
SortedMap
Une instruction arithmetique sur les flottants (double) ne l`eve
pas dexception. Une expression flottante peut prendre trois
valeurs particuli`eres :
POSITIVE INFINITY 1.0/0.0
NEGATIVE INFINITY 1.0/0.0
NaN
0.0/0.0 // Not a Number
Marie-Pierre Beal
115
Jean Berstel
Hashtable
HashMap
TreeMap
LinkedHashMap
Marie-Pierre Beal
116
Jean Berstel
Vue densemble
add pour ajouter un element.
remove pour enlever un element,
Deux paquetages
contains test dappartenance,
[Link] pour les ensembles, collections, iterateurs.
size pour obtenir le nombre delements,
[Link] structures supplementaires pour la
programmation concurrente.
isEmpty pour tester si lensemble est vide.
Deux interfaces
Collection<E> pour les ensembles dobjets, avec ou sans
repetition.
Map<K,V> pour les tables, cest-`a-dire des ensembles de couples
(cle, valeur), o`u la cle et la valeur sont de types parametres respectifs <K,V>. Chaque cle existe en un seul exemplaire mais
plusieurs cles distinctes peuvent etre associees `a une meme
valeur.
Des iterateurs sur les collections : ils permettent de parcourir une
collection.
Iterator<E> interface des iterateurs,
Le type des elements est un type parametre,<E>.
Sous-interfaces specialisees de Collection
List<E> specifie les sequences, avec les methodes
int indexOf(Object o) position de o.
E get(int index) retourne lobjet `a la position index.
E set(int index, E element) remplace lelement en
position index, et retourne lelement qui y etait
precedemment.
Set<E> specifie les ensembles sans duplication.
SortedSet<E> sous-interface de Set pour les ensembles ordonnes.
E first() retourne le premier objet.
ListIterator<E> iterateur sur les sequences.
E last() retourne le dernier objet.
Enumeration<E> ancienne forme des iterateurs.
SortedSet<E> subset(E fromElement, E toElement)
retourne une reference vers le sous-ensemble des objets
fromElementl et < toElement.
De plus, deux classes dutilitaires
Collections avec des algorithmes de tri etc,
Operations ensemblistes sur les collections
Arrays algorithmes specialises pour les tableaux.
boolean containsAll(Collection<?> c)
linclusion.
Marie-Pierre Beal
117
Jean Berstel
Marie-Pierre Beal
boolean addAll(Collection<? extends E> c) pour la
reunion.
pour
118
tester
Jean Berstel
Implementation dune collection
boolean removeAll(Collection<?> c) pour la difference.
boolean retainAll(Collection<?> c)
section.
pour
linter-
Les trois derni`eres methodes retournent true si elles ont modifie
la collection.
Pour les collections
ArrayList<E> (recommandee,
LinkedList<E>
(par
listes
implementent List<E>.
par tableaux),
et
doublement
chanees)
Vector<E> est une vieille classe (JDK 1.0) relookee qui
implemente aussi List<E>. Elle a des methodes personnelles.
HashSet<E> (recommandee) implemente Set<E>.
TreeSet<E> implemente SortedSet<E>.
Le choix de limplementation resulte de lefficacite recherchee :
par exemple, lacc`es indice est en temps constant pour les
ArrayList<E>, linsertion entre deux elements est en temps constant pour les LinkedList<E>.
Discipline dabstraction:
les attributs, param`etres, variables locales sont declares avec,
comme type, une interface (List<Integer>, Set<Double>),
les classes dimplementation ne sont utilisees que par leurs constructeurs.
Marie-Pierre Beal
119
Jean Berstel
Marie-Pierre Beal
120
Jean Berstel
Iterateurs
List<Integer> l = new Arraylist<Integer>();
Set<Integer> s = new HashSet<Integer>();
Exemple : Programme qui detecte une repetition dans les chanes
de caract`eres dune ligne.
import [Link];
import [Link];
class SetTest {
public static void main(String[] args) {
final Set<String> s = new HashSet<String>();
for (String w:args)
if ()
[Link]("D
ej`
a vu : " + w);
[Link]([Link]() + " distincts : " + s);
}
}
$ java SetTest a b c a b d
D
ej`
a vu : a
D
ej`
a vu : b
4 distincts : [d, a, c, b] //toString() de la collection
Marie-Pierre Beal
121
Jean Berstel
import [Link].*;
class HashSetTest {
public static <E> void printAll(Collection<E> c) {
for (Iterator<E> i = [Link](); [Link](); )
[Link]([Link]());
}
public static void main(String[] args){
final Set<Object> s = new HashSet<Object>();
[Link](new Person("Pierre", 23));
[Link](new Person("Anne", 20));
[Link]("Universit
e");
[Link]("Marne-la-Vall
ee");
printAll(s);
// copie des r
ef
erences, pas des objets,
// avec clone() de HashSet.
final Set<Object> t
= (Set<Object>) ((HashSet<Object>) s).clone();//unsafe cast
[Link]([Link]());
printAll(t);
Iterator<Object> i = [Link]();
while([Link]())
if ([Link]() instanceof Person) [Link]();
printAll(t);
}}
Avec les resultats
$ java HashSetTest
Marne-la-Vall
ee
Universit
e
Name: Anne, age: 20
Name: Pierre, age: 23
4
Marne-la-Vall
ee
Universit
e
Name: Anne, age: 20
Name: Pierre, age: 23
Marne-la-Vall
ee
Universit
e
Marie-Pierre Beal
Linterface Iterator<E> definit les iterateurs.
Un iterateur permet de parcourir lensemble des elements dune
collection.
Java 2 propose deux schemas, linterface Enumeration<E> et
linterface Iterator<E>.
Linterface [Link] a trois methodes
boolean hasNext() qui teste si le parcours contient encore
des elements;
E next() qui retourne lelement suivant, si un tel element existe (et l`eve une exception sinon).
void remove() qui supprime le dernier element retourne par
next.
Les
collections
implementent
linterface
Interface
Iterable<T>, ce qui permet de les parcourir aussi avec la
boucle foreach.
Marie-Pierre Beal
122
Jean Berstel
Observer le desordre.
Details sur les iterateurs.
la methode Iterator<E> iterator() de la collection positionne literateur au debut,
la methode boolean hasNext() teste si lon peut progresser,
la methode E next() avance dun pas dans la collection, et
retourne lelement traverse.
la methode void remove() supprime lelement reference par
next(), donc pas de remove() sans next().
|A B C
A|B C
A B|C
A B C|
iterator(),
next() = A,
next() = B,
next() = C,
hasNext()
hasNext()
hasNext()
hasNext()
=
=
=
=
true
true
true
false
Iterator<Character> i = [Link]();
[Link](); // NON
[Link]();
[Link]();
[Link](); // OK
[Link](); // NON
La classe [Link] implemente Iterator<String>.
123
Jean Berstel
Marie-Pierre Beal
124
Jean Berstel
Iterer sur les listes
On desire creer un tableau de references sur des objets de type
Shape qui peuvent etre Rectangle ou Ellipse (dej`a vus).
Les listes sont des sequences. Un iterateur de listes implemente
linterface ListIterator<E>. Il a des methodes supplementaires:
import [Link];
import [Link];
import [Link];
E previous() qui permet de reculer, joint `a
class ShapeTest{
public static void main(String[] args){
Shape r1 = new Rectangle(6,10);
Shape r2 = new Rectangle(5,10);
Shape e = new Ellipse(3,5);
final List<Shape> liste = new ArrayList<Shape>();
[Link](r1);
[Link](r2);
[Link](1,e); // on a r1, e, r2
for (Shape s:liste)
[Link]([Link]());
// ou bien
for (Iterator<Shape> it = [Link](); [Link]();)
[Link]([Link]().toStringArea());
}
}
$java -classpath ../shape:. ShapeTest
aire = 60.0
aire = 11.780972450961723
aire = 50.0
Marie-Pierre Beal
125
Jean Berstel
boolean hasPrevious() qui retourne vrai sil y a un element
qui prec`ede.
void add(E o) qui ajoute lelement juste avant literateur.
void set(E o) qui substitue o `a lobjet reference par next()
import [Link].*;
class LinkedListTest
public static <E> void printAll(Collection<E> c) ...
public static void main(String[] args)
final List<String> a = new LinkedList<String>();
[Link]("A");
[Link]("B");
[Link]("C");
printAll(a); // A B C
ListIterator<String> i = [Link]();
[Link]([Link]()); // A | B C -> A
[Link]([Link]()); // A B | C -> B
[Link]([Link]()); // true
[Link]([Link]()); // A | B C -> B
[Link]("X");
printAll(a); // A X | B C
Marie-Pierre Beal
negatif, si a < b.
nul, si a = b.
positif, si a > b.
Une classe Rectangle qui implemente cette interface doit definir
une methode int compareTo(Rectangle o). Il est recommande
davoir ([Link](b)==0) ssi ([Link](b)) est vraie.
Exemple : comparaisons de Person.
import [Link].*;
Jean Berstel
public int compareTo(Person anotherPerson){
int comp = [Link]([Link]);
return (comp !=0) ? comp : [Link]([Link]);
}
public String toString(){return name + " : " + age;}
Comparaison
Java exprime que les objets dune classe sont comparables, en demandant que la classe implemente linterface
[Link].
Linterface Comparable<T> declare une methode int
compareTo(T o) telle que [Link](b) est
126
}
class CompareTest{
public static void main(String[] args){
final SortedSet<Person> c = new TreeSet<Person>();
[Link](new Person("Paul", 21));
[Link](new Person("Paul", 25));
[Link](new Person("Anne", 25));
for (Person p:c)
[Link](p);
}
}
avec le resultat
$ java
Anne :
Paul :
Paul :
CompareTest
25
21
25
class Person implements Comparable<Person>{
protected final String name;
protected final Integer age;
public Person(String name, Integer age){
[Link] = name; [Link] = age;
}
public String getName(){
return name;
}
public Integer getAge(){
return age;
}
Marie-Pierre Beal
127
Jean Berstel
Marie-Pierre Beal
128
Jean Berstel
Comparateur
[Link]();
}
public static void main(String[] args){
final List<Person> c = new ArrayList<Person>();
[Link](new Person("Paul", 21));
[Link](new Person("Paul", 25));
[Link](new Person("Anne", 25));
printAll(c);
[Link](c, new NameComparator());
printAll(c);
[Link](c, new AgeComparator());
printAll(c);
}
Un comparateur est un objet qui permet la comparaison.
En Java, linterface [Link]<T> declare une
methode int compare(T o1, T o2).
On se sert dun comparateur
dans un constructeur dun ensemble ordonne.
dans les algorithmes de tri fournis par la classe Collections.
Exemple de deux comparateurs de noms :
class NameComparator implements Comparator<Person>{
public int compare(Person o1, Person o2){
int comp = [Link]().compareTo([Link]());
if (comp == 0)
comp = [Link]().compareTo([Link]());
return comp;
}
}
class AgeComparator implements Comparator<Person>{
public int compare(Person o1, Person o2){
int comp = [Link]().compareTo([Link]());
if (comp == 0)
comp = [Link]().compareTo([Link]());
return comp;
}
}
Et les resultats :
Paul : 21 Paul : 25 Anne : 25
Anne : 25 Paul : 21 Paul : 25
Paul : 21 Anne : 25 Paul : 25
// ordre dinsertion
// ordre sur noms
// ordre sur ages
Une liste de noms (pour pouvoir trier sans peine).
class ComparatorTest{
public static <E> void printAll(Collection<E> c){
for (E e = c)
Marie-Pierre Beal
129
Jean Berstel
Marie-Pierre Beal
130
Jean Berstel
Implementation dune table
Pour les tables
Les tables ou Map
HashMap<K,V> (recommandee), implemente Map<K,V>.
Linterface Map<K,V> specifie les tables, des ensembles de couples
(cle, valeur). Les cles ne peuvent etre dupliquees, au plus une
valeur est associee `a une cle.
V put(K key, V value) ins`ere lassociation (key, value)
dans la table et retourne la valeur precedemment associee `a la
cle ou bien null.
boolean containsKey(Object key) retourne vrai sil y a
une valeur associee `a cette cle.
V get(Object key) retourne la valeur associee `a la cle dans
la table, ou null si null etait associe ou si key nest pas une
cle de la table.
V remove(Object key) supprime lassociation de cle key.
Retourne la valeur precedemment associee. Retourne null si
null etait associe ou si key nest pas une cle de la table.
La sous-interface SortedMap<K,V> specifie les tables dont
lensemble des cles est ordonn
e.
Marie-Pierre Beal
131
Jean Berstel
Hashtable<K,V> est une vieille classe (JDK 1.0) relookee
qui implemente aussi Map<K,V>. Elle a des methodes personnelles.
TreeMap<K,V> implemente SortedMap<K,V>.
La classe TreeMap<K,V> implemente les operations avec des arbres
rouge-noir.
Un TreeMap<K,V> stocke ses cles de telle sorte que les operations
suivantes sexecutent en temps O(log(n)) :
boolean containsKey(Object key)
V get(Object key)
V put(K key, V value)
V remove(Object key)
pourvu que lon definisse un bon ordre.
Linterface
[Link] permet de specifier un comparateur des
cles.
Marie-Pierre Beal
132
Jean Berstel
On associe un nom `a chaque forme. Le nom est la cle, la forme est
la valeur associee .
Linterface Shape, et les classes Rectangle et Ellipse sont
comme dhabitude.
import [Link].*;
La classe [Link]<K,V> poss`ede un constructeur qui
permet de changer le comparateur :
TreeMap(Comparator<? super K> c)
Le programme devient :
public class ShapeMapTest{
public static void main(String[] args){
Shape r1 = new Rectangle(6,10);
Shape r2 = new Rectangle(5,10);
Shape e = new Ellipse(3,5);
final Map<String,Shape> tree = new TreeMap<String,Shape>();
[Link]("R2",r2);
[Link]("R1",r1);
[Link]("E",e);
[Link]([Link]("R1").toStringArea());
}
}
On obtient :
$ java ShapeMapTest
aire = 60.0
R2
133
import [Link].*;
//ordre inverse
public class OppositeComparator implements Comparator<String>{
public int compare(String o1, String o2){
if ([Link](o2) > 0) return -1;
if ([Link](o2) < 0) return 1;
return 0;
}
}
Cette methode l`eve une NullPointerException (qui est une
RunTimeException) si o1 est null. Le reste de la verification
est delegue `a compareTo.
class OppositeTest{
public static void main(String[] args){
Shape r1 = new Rectangle(6,10);
Shape r2 = new Rectangle(5,10);
Shape e = new Ellipse(3,5);
Comparator<String> c = new OppositeComparator();
final SortedMap<String,Shape> tree
= new TreeMap<String,Shape>(c);
[Link]("R2",r2);
[Link]("R1",r1);
[Link]("E",e);
[Link]([Link]() + " " + [Link]());
// affiche R2 E
}
R1
Marie-Pierre Beal
teur.
Jean Berstel
Marie-Pierre Beal
}
$javac -classpath ../shape:. [Link]
$java -classpath ../shape:. OppositeTest
R2 E
134
Jean Berstel
Iterer dans les tables
Les tables nont pas diterateurs.
Trois methodes permettent de voir une table comme un ensemble
Set<K> keySet() retourne lensemble (Set<K>) des cles;
Collection<V> values() retourne la collection des valeurs
associees aux cles;
Set<[Link]<K,V>> entrySet() retourne lensemble des
couples (cle, valeur). Ils sont de type [Link]<K,V> qui est
une interface statique interne `a Map<K,V>.
Map<String,Shape> m = ...;
Set<String> keys = [Link]();
Set<[Link]<String,Shape>> pairs = [Link]();
Collection<Shape> values= [Link]();
On peut ensuite iterer sur ces ensembles :
for (Iterator<String> i = [Link](); [Link](); )
[Link]([Link]());
for (Iterator<Shape> i = [Link](); [Link](); )
[Link]([Link]());
for (Iterator<[Link]<String,Shape>> i = [Link]();
[Link](); ){
[Link]<String,Shape> e = [Link]();
[Link]([Link]() + " -> " + [Link]());
}
ou utiliser les boucles foreach.
Marie-Pierre Beal
135
Jean Berstel
Marie-Pierre Beal
136
Jean Berstel
Exemple : construction dun index
class Index {
private final SortedMap<String,Set<Integer>> map;
On part dune suite dentrees formees dun mot et dun numero de
page, comme
22,
23,
25,
25,
25,
29,
"Java"
"It
erateur"
"Java"
"Map"
"Java"
"Java"
et on veut obtenir un index, comme
It
erateur [23]
Java [22, 25, 29]
Map [25]
Chaque mot apparat une fois, dans lordre alphabetique, et la
liste des numeros correspondants et donnee en ordre croisssant,
sans repetition.
Marie-Pierre Beal
137
Jean Berstel
Index() {
map = new TreeMap<String,Set<Integer>>();
}
public void myPut(int page, String word) {
Set<Integer> numbers = [Link](word);
if (numbers == null) {
numbers = new TreeSet<Integer>();
[Link](word, numbers); // la vraie m
ethode put
}
[Link](page);
}
public void print(){
Set<String> keys = [Link]();
for (String word: keys)
[Link](word + " " + [Link](word));
}
}
class IndexTest{
public static Index makeIndex(){
Index index = new Index();
[Link](22,"Java");
[Link](23,"It
erateur");
[Link](25,"Java");
[Link](25,"Map");
[Link](25,"Java");
[Link](29,"Java");
return index;
}
public static void main(String[] args){
Index index = makeIndex();
[Link]();
}
}
Marie-Pierre Beal
138
Jean Berstel
int[] a, b ...;
boolean [Link](a,b);
Algorithmes
sort pour trier un tableau (quicksort), par exemple
Les classes Collections et Arrays (attention au s final) fournissent des algorithmes dont la performance et le comportement
est garanti. Toutes les methodes sont statiques.
Collections:
int[] a;
...
[Link](a);
Exemple : tirage de loto.
import [Link].*;
min, max, dans une collection delements comparables;
sort pour trier des listes (tri par fusion);
List<Integer> l;
...
[Link](l);
La signature de cette methode sort est (!)
public static <T extends Comparable<? super T>> void sort(List<T> list)
binarySearch recherche dichotomique dans les listes ordonnees.
copy copie de listes, par exemple,
List<Integer> source = ...;
List<Integer> dest;
[Link](dest, source);
synchronizedCollection pour synchroniser une collection : elle ne peut etre modifiee durant lexecution dune
methode.
class Loto {
public static void main(String[] args) {
List<Integer> numbers = new ArrayList<Integer>(49);
for (int i=0; i < 49; i++)
[Link](i);
[Link](numbers); // m
elange
List<Integer> drawing = [Link](0,6);//les 6 premi`
eres
[Link](drawing); // tri
[Link](drawing); // et les voici
}
}
Resultat:
> java Loto
[6, 17, 24, 33, 41, 42]
> java Loto
[15, 24, 28, 41, 42, 44]
> java Loto
[27, 30, 35, 42, 44, 46]
Arrays:
binarySearch pour la recherche dichotomique, dans les
tableaux;
equals pour tester legalite des contenus de deux tableaux, par
exemple
Marie-Pierre Beal
139
Jean Berstel
Marie-Pierre Beal
140
Jean Berstel
Double ended queue Deque<E>
import [Link].*;
Depuis Java 1.6 on peut definir des files FIFO ou LIFO (piles) `a
laide de linterface [Link] qui permet de manipuler
une file par les deux bouts.
Les implementations des Deque
ArrayDeque<E>,
LinkedList<E>.
Les operations principales sur les Deque sont
addFirst, offerFirst pour ajouter un element en tete,
addLast, offerLast pour ajouter un element `a la fin,
removeFirst, pollFirst pour enlever un element en tete,
removeLast, pollLast pour enlever un element `a la fin,
gerFirst, peekFirst pour regarder un element en tete,
getLast, peekLast pour regarder un element `a la fin.
Chaque methode (sur chaque ligne ci-dessus) a deux formes : la
premi`ere renvoie une exception (Runtime) si loperation echoue.
La deuxi`eme renvoie null ou false.
Linterface donne un iterateur en sens inverse.
Iterator<E> descendingIterator()
Marie-Pierre Beal
141
Jean Berstel
public class Test {
public static void main(String[] args) {
final Deque<Integer> deque = new LinkedList<Integer>();
[Link](10);
[Link](20);
[Link](30);
for (Integer i:deque){
[Link](i+ " ");
}
[Link]();
for (Iterator<Integer> it = [Link]();
[Link]();){
[Link]([Link]()+ " ");
}
[Link]();
[Link]([Link]());
[Link](deque);
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
// Exception [Link]
[Link]([Link]());
}
}
donne
10 20 30
30 20 10
10
[20, 30]
20
30
null
Exception in thread "main" [Link]
Marie-Pierre Beal
142
Jean Berstel
Chaque type enumere a une methode static values() renvoyant un tableau contenant les valeurs enumerees.
Enum
erations
Exemple plus fourni :
Java 1.5 permet de definir des types enumeres. La classe de base
est [Link].
Exemple dusage simple :
import [Link].*;
public class CoinTest {
public enum Coin {
DOLLAR(1), EURO(10), PESOS(50);
class Test {
// Il sagit dune d
eclaration de classe
private enum Color { BLUE, RED, GREEN }
private final int value;
//le constructeur nest pas appel
e directement
Coin(int value) { [Link] = value; }
public int getValue() { return value; }
public static void main(String[] args) {
Color c = [Link];
[Link](c);
}
}
public static void main(String[] args) {
public static void main(String[] args) {
for (Coin c : [Link]()) {
+ [Link]());
[Link](c + ":
"
}
}
}
$ javac [Link]
$ ls
[Link] Test$[Link] [Link]
$ java Test
BLUE
Une classe interne, qui derive de la classe abstraite Enum, est creee.
Les valeurs enumerees sont des champs publics statiques de cette
classe.
Un type enumere peut implementer des interfaces. Les champs
peuvent etre utilises dans les collections, etre des cles des tables.
Marie-Pierre Beal
143
Jean Berstel
}
$ java CoinTest
DOLLAR:
1
EURO:
10
PESOS:
50
Marie-Pierre Beal
144
Jean Berstel
Programmation des listes chanees suite
return new ListeIterator();
}
}
On reprend lexemple dimplementation des listes simplement
chanees (t.90) contenant des elements de type Object (sans
utiliser les collections des API). On ecrit son propre iterateur pour
ces listes. Dans une premi`ere version, on utilise une classe interne
nommee. On ecrit ensuite une classe interne anonyme.
import [Link].*;
public class Liste<E> implements Iterable<E> {
Cell<E> init;
public Liste() { init = new ConcreteNil<E>();}
public int length() { return [Link]();}
// inner class
class ListeIterator<E> implements Iterator<E> {
Cell<E> c;
ListeIterator() {
c = init;
}
public boolean hasNext() {
return ([Link]() != 0);
}
public E next() {
if (! hasNext()) {
throw new NoSuchElementException();
}
E o = ((Cons<E>)c).getElem();
c = ((Cons<E>)c).getNext();
return o;
}
public void remove() {
throw new UnsupportedOperationException();
}
}
Marie-Pierre Beal
145
Jean Berstel
public class ListeTest {
public static void main(String[] args) {
Liste<Integer> l = new Liste<Integer>();
[Link] = new ConcreteCons<Integer>
(1, new ConcreteCons<Integer>
(2,new ConcreteNil<Integer>()));
[Link]("liste de longueur "+ [Link]());
for (Integer o : l)
[Link](o);
}
}
Lexecution donne :
liste de longueur 2
1
2
La compilation cree un fichier Liste$[Link]
pour la classe interne.
import [Link].*;
public class Liste implements Iterable<E> {
Cell<E> init;
public Liste() { init = new ConcreteNil<E>();}
public int length() { return [Link]();}
public Iterator<E> iterator() {
return new Iterator<E>() {
Cell<E> c = init;
public boolean hasNext() {
return ([Link]() != 0);
}
public E next() {
Marie-Pierre Beal
if (hasNext()) {
E o = ((Cons<E>)c).getElem();
c = ((Cons<E>)c).getNext();
return o;
146
Jean Berstel
Classes internes
}
else throw new NoSuchElementException();
}
public void remove() {
throw new UnsupportedOperationException();
}
};
}
}
La compilation cree un fichier Liste$[Link] pour la classe interne anonyme.
Exercice : ecrire le remove().
Une classe interne est une classe declaree `a linterieur dune
autre classe.
Une classe interne ne contient pas de membre statiques. Une
classe interne non statique (inner class comme ci-dessus) a
acc`es `a tous les membres de sa classe englobante. La classe
englobante a acces `a tous les membres de sa classe interne.
On peut obtenir une reference sur linstance de la classe englobante Toto par [Link].
Une classe interne (nommee ou anonyme) peut etre definie `a
linterieur dune methode (implementation 2 ci-dessus). Ceci
est utilise en interface graphique, ou pour ecrire des iterateurs.
La machine virtuelle java ne connat pas les classes internes
(comme elle ne connat pas les generics).
Marie-Pierre Beal
147
Jean Berstel
Marie-Pierre Beal
148
Jean Berstel
Generalites
Un flot (stream) est un canal de communication dans lequel on
peut lire ou ecrire. On acc`ede aux donnees sequentiellement.
Les flots prennent des donnees, les transforment eventuellement, et
sortent les donnees transformees.
Pipeline ou filtrage
Les donnees dun flot dentrees sont prises dans une source, comme
lentree standard ou un fichier, ou une chane ou un tableau de
caract`eres, ou dans la sortie dun autre flot dentree.
De meme, les donnees dun flot de sortie sont mises dans un puit,
comme la sortie standard ou un fichier, ou sont transmises comme
entrees dans un autre flot de sortie.
Les flots
1. Generalites
2. Flots doctets, flots de caract`eres
3. Les filtres
En Java, les flots manipulent soit des octets, soit des caract`eres.
Certains manipulent des donnees typees.
Les classes sont toutes dans le paquetage [Link] (voir aussi
[Link], par exemple la classe [Link]).
Les classes de base sont
4. Comment lire un entier
5. Manipulation de fichiers
6. Flots dobjets ou serialisation
File
RandomAccessFile
InputStream
OutputStream
Reader
Writer
StreamTokenizer
Les Stream, Reader et Writer sont abstraites.
Marie-Pierre Beal
149
Jean Berstel
Les Stream manipulent des octets, les Reader et Writer manipulent des caract`eres.
Il exite aussi des classes StringReader et StringWriter pour
manipuler les chanes comme des flots.
Hi
erarchie des classes
Fichiers
File
FileDescriptor
RandomAccessFile
Marie-Pierre Beal
Reader
150
Jean Berstel
Writer
Reader
BufferedReader
LineNumberReader
CharArrayReader
FilterReader
PushbackReader
InputStreamReader
FileReader
PipedReader
StringReader
Writer
BufferedWriter
CharArrayWriter
FilterWriter
OutputStreamWriter
FileWriter
PipedWriter
StringWriter
PrintWriter
Streams
InputStream
ByteArrayInputStream
FileInputStream
FilterInputStream
BufferedInputStream
DataInputStream
LineNumberInputStream
PushbackInputStream
ObjectInputStream
PipedInputStream
SequenceInputStream
OutputStream
ByteArrayOutputStream
FileOutputStream
FilterOutputStream
BufferedOutputStream
DataOutputStream
PrintStream
ObjectOutputStream
PipedOutputStream
Marie-Pierre Beal
151
Jean Berstel
Marie-Pierre Beal
152
Jean Berstel
Flots doctets et de caract`eres
flot len octets `a partir de off;
void close() : ferme le flot.
Les flots doctets en lecture
Objet dune classe derivant de InputStream.
[Link] est un flot doctets en lecture.
Methodes pour lire `a partir du flot :
int read() : lit un octet dans le flot, le renvoie comme octet
de poids faible dun int ou renvoie 1 si la fin du flot est
atteinte;
int read(byte[] b) : lit au plus [Link] octets dans le
flot et les met dans b;
int read(byte[] b, int off, int len) : lit au plus
len octets dans le flot et les met dans b `a partir de off;
int available() : retourne le nombre doctets dans le flot;
void close() : ferme le flot.
Les flots doctets en ecriture
Objet dune classe derivant de OutputStream.
[Link] est de la classe PrintStream, qui derive de
FilterOutputStream qui derive de OutputStream.
Methodes pour ecrire dans le flot:
void write(int b) : ecrit dans le flot loctet de poids faible
de b;
void write(byte[] b) : ecrit dans le flot tout le tableau;
Marie-Pierre Beal
153
Jean Berstel
Lire un octet
Marie-Pierre Beal
154
Jean Berstel
int read() : lit un caract`ere dans le flot, le renvoie comme
octets de poids faible dun int ou renvoie 1 si la fin du flot
est atteinte;
import [Link].*;
public class ReadTest {
public static void main(String[] args){
try {
int i = [Link]();
[Link](i);
} catch (IOException e) {};
}
}
int read(char[] b) : lit au plus [Link] caract`eres dans
le flot et les met dans b;
int read(char[] b, int off, int len) : lit au plus
len caract`eres dans le flot et les met dans b `a partir de off;
int available() : retourne le nombre doctets dans le flot;
void close() : ferme le flot.
On obtient :
Les flots doctets en ecriture
$ java ReadTest
a
97
Objet dune classe derivant de Writer.
Les methodes sont analogues `a celles des flots doctets.
Lire des octets
public class ReadTest {
static int EOF = (int) \n;
public static void main(String[] args) throws IOException {
int i;
while ((i = [Link]()) != EOF)
[Link](i + " ");
[Link]("\nFin");
}
}
On obtient :
$ java ReadTest
b
eal
98 233 97 108
Fin
Les flots de caract`eres en lecture
Objet dune classe derivant de Reader.
Methodes pour lire `a partir du flot :
Marie-Pierre Beal
155
Jean Berstel
Marie-Pierre Beal
156
Jean Berstel
Les filtres
Lire des entiers
Un filtre est un flot qui enveloppe un autre flot.
Les donnees sont en fait lues (ou ecrites) dans le flot enveloppe
apr`es un traitement (codage, bufferisation, etc). Le flot enveloppe
est passe en argument du constructeur du flot enveloppant.
Les filtres heritent des classes abstraites :
FilterInputStream (ou FilterReader);
FilterOutputStream (ou FilterWriter).
Filtres predefinis :
DataInputStream, DataOutputStream : les methodes
sont writeType(), readType(), o`u Type est Int, Char,
Double, ...;
BufferedInputStream : permet de bufferiser un flot;
PushBackInputStream: permet de replacer des donnees lues
dans le flot avec la methode unread();
PrintStream : [Link] est de la classe PrintStream.
Un entier avec BufferedReader
class Read{
public static int intRead() throws IOException{
InputStreamReader in = new InputStreamReader([Link]);
BufferedReader data = new BufferedReader(in);
String s = [Link]();
return [Link](s);
}
}
class ReadTest{
public static void main(String[] args) throws IOException{
int i = [Link]();
[Link](i);
}
}
La methode String readLine() de la classe BufferedReader
retourne la ligne suivante. La classe LineNumberReader derive de
la classe BufferedReader.
InputStreamReader : transforme un Stream en Reader;
BufferedReader : bufferise un flot de caract`eres;
LineNumberReader : pour une lecture de caract`eres ligne par
ligne;
Marie-Pierre Beal
157
Jean Berstel
Lire un texte sur lentr
ee standard
Marie-Pierre Beal
158
Jean Berstel
Lire une suite dentiers avec StreamTokenizer
class Test {
public static void main(String[] args) throws IOException {
BufferedReader in = null;
try {
in = new BufferedReader(
new InputStreamReader([Link]));
String s;
while ((s = [Link]()) != null) {
[Link]("> ");
s = [Link]();
[Link](s);
}
} catch (IOException e) {
} finally {
if (in != null) [Link]();
}
}
}
marie
> MARIE
pierre
> PIERRE
b
eal
> B
EAL
Un StreamTokenizer prend en argument un flot (reader) et le
fractionne en token (lex`emes). Les attributs sont
nval contient la valeur si le lex`eme courant est un nombre
(double)
sval contient la valeur si le lex`eme courant est un mot.
TT_EOF, TT_EOL, TT_NUMBER, TT_WORD
valeurs
de
lattribut ttype. Si un token nest ni un mot, ni un nombre,
contient lentier representant le caract`ere.
class MultiRead {
public static void read() throws IOException{
StreamTokenizer in;
InputStreamReader w = new InputStreamReader([Link]);
in = new StreamTokenizer(new BufferedReader(w));
[Link](/);
[Link](@,@);
do {
[Link]();
if ([Link] == (int) /)
[Link]([Link]);
if ([Link] == StreamTokenizer.TT_NUMBER)
[Link]((int) [Link]); // normalement double
if ([Link] == StreamTokenizer.TT_WORD)
[Link]([Link]);
} while ([Link] != StreamTokenizer.TT_EOF);
}
}
class MultiReadTest{
public static void main(String[] args) throws IOException{
[Link]();
}
}
Marie-Pierre Beal
159
Jean Berstel
Marie-Pierre Beal
160
Jean Berstel
Manipulation de fichiers
0 @I1@ INDI
1 NAME Paul /Le Guen/
0 TRLR
Les sources et puits des stream et reader sont
$ java MultiReadTest < Paul
0
@I1@
INDI
1
NAME
Paul
Le Guen
0
TRLR
les entrees et sorties standard (printf)
les String (sprintf)
les fichiers (fprintf)
Pour les String, il y a les StringReader et StringWriter. Pour
les fichiers, il y a les stream et reader correspondants.
La classe [Link] permet de manipuler le syst`eme de
fichiers;
Les classes FileInputStream (et FileOutputStream)
definissent des flots de lecture et decriture de fichiers doctets,
et les classes FileReader (et FileWriter) les flots de lecture
et decriture de fichiers de caract`eres.
Marie-Pierre Beal
161
Jean Berstel
Marie-Pierre Beal
162
Jean Berstel
Lecture dun fichier
La classe File decrit une representation dun fichier.
import [Link].*;
import [Link].*;
Un lecteur est le plus souvent defini par
FileReader f = new FileReader(nom);
public class FileInformation{
public static void main(String[] args) throws Exception{
info(args[0]);
}
FileInputStream in = new FileInputStream(nomIn);
FileOutputStream out = new FileInputStream(nomOut);
int readLength;
byte[] block = new byte[8192];
while ((readLength = [Link](block)) != -1)
[Link](block, 0, readLength);
public static void info(String nom)
throws FileNotFoundException {
File f = new File(nom);
if (![Link]())
throw new FileNotFoundException();
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
try {
[Link]([Link]());
[Link]([Link]());
} catch (IOException e) {
}
}
Lecture dun fichier de texte, ligne par ligne.
On obtient :
monge : > ls -l [Link]
-rw-r--r-- 1 beal beal 638 f
ev 13 16:08 [Link]
monge : > java FileInformation [Link]
[Link]
false
true
true
638
/home/beal/Java/Programmes5/file/[Link]
file:/home/beal/Java/Programmes5/file/[Link]
Marie-Pierre Beal
163
o`u nom est le nom du fichier. La lecture se fait par les methodes
de la classe InputStreamReader.
Lecture par blocs.
Jean Berstel
import [Link].*;
class ReadFile {
public static String read(String f) throws IOException {
FileReader fileIn = null;
StringBuilder s = new StringBuilder();
try {
fileIn = new FileReader(f);
BufferedReader in = new BufferedReader(fileIn);
String line;
while ((line = [Link]()) != null)
[Link](line + "\n");
} catch (IOException e) {
} finally {
if (fileIn != null) [Link]();
return [Link]();
}
}
public static void main(String[] args) throws IOException {
[Link]([Link]("toto"));
}
}
Marie-Pierre Beal
164
Jean Berstel
Les flots dobjets ou serialisation
import [Link].*;
Un flot dobjets permet decrire ou de lire des objets Java dans
un flot.
public class Pixel implements Serializable {
private int x, y;
public Pixel(int x,int y){ this.x = x; this.y = y; }
public String toString(){ return "(" + x + "," + y + ")"; }
On utilise pour cela les filtres ObjectInputStream et
ObjectOutputStream. Ce service est appele serialisation.
public void savePixel(String name) throws Exception {
File f = new File(name);
ObjectOutputStream out;
out = new ObjectOutputStream(new FileOutputStream(f));
[Link](this);
[Link]();
// fin de la partie sauvegarde
Les applications qui echangent des objets via le reseau utilisent
la serialisation.
Pour serialiser un objet, on utilise la methode dun
flot implementant linterface ObjectOutput :
void
writeObject(Object o).
ObjectInputStream in;
in = new ObjectInputStream(new FileInputStream(f));
Pixel oBis = (Pixel) [Link]();
[Link]();
[Link](this);
[Link](oBis);
[Link]([Link](oBis));
Pour deserialiser un objet, on utilise la methode dun
flot implementant linterface ObjectInput :
Object
readObject().
Pour quun objet puisse etre insere dans un flot, sa classe doit
implementer linterface Serializable. Cette interface ne contient pas de methode.
La premi`ere fois quun objet est sauve, tous les objets qui peuvent
etre atteints `a partir de cet objet sont aussi sauves. En plus de
lobjet, le flot sauvegarde un objet appele handle qui represente
une reference locale de lobjet dans le flot. Une nouvelle sauvegarde
entrane la sauvegarde du handle `a la place de lobjet.
}
public static void main(String[] args) throws Exception{
Pixel o = new Pixel(1,2);
[Link](args[0]);
}
}
On obtient :
monge :> java Pixel toto
(1,2)
(1,2)
false
Marie-Pierre Beal
165
Jean Berstel
Red
efinir lobjet de sauvegarde
Au moment de la sauvegarde, il est possible de remplacer un objet
par un autre.
On definit pour cela la methode Object writeReplace()
dans la classe de lobjet `a remplacer.
Au moment de la deserialisation, on utilise la methode Object
readResolve() de la classe de lobjet remplace pour retourner un objet compatible avec loriginal.
Dans lexemple suivant, une liste dentiers est remplacee, au moment de son ecriture dans un fichier, par un objet de la classe
ListeString qui contient la liste des entiers sous forme de chane
de caract`eres.
Marie-Pierre Beal
167
Jean Berstel
Marie-Pierre Beal
166
Jean Berstel
class Serial {
public static void main(String[] args) throws Exception{
Liste l = new Liste(1, new Liste(2,null));
[Link](args[0]);
[Link](args[0]);
}
}
class Liste implements Serializable{
int val;
Liste next;
public Liste(int val, Liste next){
[Link] = val ;
[Link] = next;
}
Object writeReplace() throws ObjectStreamException{
Liste tmp;
StringBuilder buffer = new StringBuilder();
for (tmp = this; tmp != null; tmp = [Link])
[Link](" " + [Link]);
return new ListeString([Link]());
}
public String toString(){
return "(" + val + "," + next + ")";
}
public void writeListe(String nom) throws Exception {
ObjectOutputStream out;
out = new ObjectOutputStream(new FileOutputStream(nom));
[Link](this);
[Link]();
}
public void readListe(String nom) throws Exception {
ObjectInputStream in;
in = new ObjectInputStream(new FileInputStream(nom));
Liste l = (Liste) [Link]();
[Link](l);
}
}
Marie-Pierre Beal
168
Jean Berstel
class ListeString implements Serializable {
String s;
ListeString(String s) { this.s = s; }
Object readResolve() throws ObjectStreamException {
StringTokenizer st = new StringTokenizer(s);
return resolve (st);
}
Liste resolve(StringTokenizer st) {
if ([Link]()) {
int val = [Link]([Link]());
return new Liste(val, resolve(st));
}
return null;
}
Introduction `a JDBC
1. Quest-ce que JDBC ?
On obtient :
2. Principe de fonctionnement
monge :> java Serial toto
(1,(2,null))
monge :> file toto
toto: Java serialization data, version 5
3. Connexion et interrogation
4. Traitement des resultats
5. Exemples
Marie-Pierre Beal
169
Jean Berstel
Marie-Pierre Beal
Quest-ce que JDBC ?
170
Jean Berstel
Principe de fonctionnement
Java DataBase Connectivity
est une API Java ([Link]) permettant de se connecter avec
des bases de donnees relationnelles (SGBDR),
Connexion
m
ethode)
avec
un
DriverManager
(ancienne
elle fournit un ensemble de classes et dinterfaces permettant
lutilisation dun ou plusieurs SGBDR `a partir dun programme
Java.
Chaque base de donnees utilise un pilote (driver) qui lui est
propre. Ce pilote permet de convertir les requetes JDBC dans
le langage natif du syst`eme de gestion de la base de donnees
relationnelles.
elle supporte le standard SQL-3, permet la connexion `a une ou
plusieurs bases, le lancement de requetes SQL et le traitement
des resultats.
Ces pilotes (dits drivers JDBC) sont un ensemble de classes et
interfaces. Ils sont fournis par les differents constructeurs ou
proprietaires (Oracle, PostgreSQL, MySQL, ...).
Avantages et inconv
enients
Java est un excellent candidat pour le developpement
dapplications de bases de donnees.
JDBC permet au programmeur decrire un code independant
de la base de donnees cible et du moyen de connectivite utilise.
Les bases de donnees relationnelles sont tr`es repandues mais
Java est oriente objet. Lideal serait de traiter des bases de
donnees elle-meme orientees objet.
On distingue 4 types de drivers (I,II,III,IV) suivant quils contiennent ou non des fonctions natives (non Java) de lAPI du
SGBDR et suivant le protocole reseau utilise.
Par exemple un driver de type IV est ecrit en pur Java et
communique avec la base avec le protocole reseau de la base.
Une applette peut etre executee si le serveur SGBDR est installe
au meme endroit que le serveur Web.
La compilation ne permet pas de verifier le code SQL avant
lexecution (voir SQLJ, SQL embarque dans Java). Il ny a pas
de verifications de types vis-`a-vis de la base de donnees.
Marie-Pierre Beal
171
Jean Berstel
Marie-Pierre Beal
172
Jean Berstel
Architecture
Architecture logicielle
Pour les drivers de type IV, on peut distinguer deux couches.
Application Java
JDBC API
JDBC DriverManager
JDBC Driver API
JDBC Driver
pour PostgreSQL
Il nest pas necessaire de coder en dur la classe driver;
JDBC Driver
pour Oracle
protocole proprietaire
protocole proprietaire
Base
Base
PostgreSQL
Oracle
Si des proprietes de la base changent, le code des applications
utilisateurs na pas `a etre change;
Des connexions distribuees et aussi des connexions stockees
(pooled connexions). Dans ce cas, une connexion refermee peut
etre recyclee, ce qui reduit les nombre de creations de connexions. Louverture dune connexion est effet couteuse. Ceci
sop`ere de facon transparente pour lutilisateur;
Un nom logique de la base a ete enregistre par ladministrateur
syst`eme via lAPI JNDI (Java Naming and Directory Interface). Lobjet DataSource est recherche via cette API. Si la
base source est mise sur autre serveur, ceci est transparent `a
lutilisateur.
Architecture r
eseau
Un mod`ele client-serveur simple :
Serveur
Client
Application
TCP/IP
JDBC
Marie-Pierre Beal
Les constructeurs de bases de donnees fournissent les drivers
et les implementations des DataSource. Un objet DataSource
represente une base de donnees physique et chaque connexion creee
est une connexion `a cette base. Linterface DataSource poss`ede
des methodes de creation de connexions. Un objet data source a
des properties (proprietes persistantes) contenant des informations comme la localisation du serveur de la base de donnees, le
nom de la base, le protocole reseau utilise pour communiquer avec
le serveur, etc .
Les avantages de ce mode de connexion par rapport `a celui via les
driver managers sont
SGBDR
Base
173
Jean Berstel
Marie-Pierre Beal
Utilisation de JDBC
174
Jean Berstel
Connexion (ancienne methode)
Importer
les
paquetages
[Link],
[Link],
[Link], (et [Link] Java version 1.5);
Se connecter `a la base de donnees;
Preparer une requete;
Enregistrement dun driver
On charge une classe Driver qui cree une instance delle meme
et senregistre aupr`es du DriverManager.
[Link]("[Link]");
Executer la requete;
Connexion a
` la base par un DriverManager
Recuperer les donnees retournees et les traiter;
Fermer un certain nombre dobjets ouverts au cours des
operations precedentes (dont la connexion `a la base).
Elle se fait via la methode getConnection() de la classe
DriverManager.
Cette methode demande une URL, un nom dutilisateur et
eventuellement un mot de passe (tous de type String).
LURL nest pas tr`es normalisee. Elle indique quon utilise
JDBC, le type du driver ou le type du SGBDR, lidentification
de la base distante.
Exemples dURLs :
String url = "jdbc:postgresql:beal_base";
String url = "jdbc:postgresql://localhost:5432/beal_base";
String url = "jdbc:postgresql://[Link]/beal_base";
Exemple de connexion. (Ladministrateur de la base de nom
beal base a enregistre lutilisateur beal en lautorisant `a consulter et modifier la base sans controle de mot de passe.
Lutilisateur beal poss`ede de plus le droit CREATEDB).
[Link]("[Link]");
String url = "jdbc:postgresql:beal_base";
Connection co = [Link]( url, "beal", "");
Marie-Pierre Beal
175
Jean Berstel
Marie-Pierre Beal
176
Jean Berstel
import [Link].*;
import [Link].*;
public class DataSourceConnexion {
public class Creation{
public Creation() throws Exception {
public DataSourceConnexion() {
[Link]("[Link]");
String url = "jdbc:postgresql:beal_base";
// Autre possibilite pour lURL
// String url = "jdbc:postgresql://localhost:5432/beal_base";
Connection co = [Link]( url, "beal", "");
if (co != null) [Link]();
[Link] source =
new [Link]();
[Link]("jdbc/beal_base");
[Link]("localhost:5432");
[Link]("beal_base");
[Link]("beal");
[Link]("");
[Link](10);
}
public static void main(String[] args) throws Exception{
new Creation();
}
}
Connection co = null;
try {
co = [Link]();
// use connection
} catch (SQLException e) {
// log error
} finally {
if (co != null) {
try { [Link](); } catch (SQLException e) {}
}
}
}
Connexion a
` la base par une DataSource
Context ctx = new InitialContext();
DataSource ds = (DataSource) [Link]("jdbc/beal_base");
Connection co = [Link]("beal","");
Une pooled connexion sera creee automatiquement si cette
implementation existe. Sinon une connexion standard est creee.
public static void main(String[] args) throws Exception{
new DataSourceConnexion();
}
}
Marie-Pierre Beal
177
Jean Berstel
Marie-Pierre Beal
Exemple de connexion-deconnexion avec une DataSource et
la JNDI.
import
import
import
import
import
Jean Berstel
}
catch (SQLException e){
[Link] ([Link]());
}
catch (Exception e){
[Link] ();
}
finally {
if (co != null) [Link]();
}
[Link].*;
[Link].*;
[Link].*;
[Link].*;
[Link].*; // contient PGPoolingDataSource
public class DataSourceAdmin {
public static void initialize() throws Exception {
// classe du vendeur
PGPoolingDataSource source = new PGPoolingDataSource();
[Link]("jdbc/beal_base");
[Link]("localhost:5432");
[Link]("beal_base");
[Link]("beal");
[Link]("");
[Link](10);
Context ctx = new InitialContext();
[Link]("jdbc/beal_base", source);
}
public static void main(String[] args) throws Exception{
[Link]();
}
}
178
}
public static void main(String[] args) throws Exception{
new DataSourceConnexion();
}
}
public class DataSourceConnexion {
public DataSourceConnexion() throws Exception {
// peut lever [Link]
Context ctx = new InitialContext();
// peut lever [Link]
DataSource ds = (DataSource) [Link]("jdbc/beal_base");
Connection co = null;
try {
co = [Link]("beal","");
SQLWarning w = [Link]();
if (w != null) [Link] ([Link]());;
Marie-Pierre Beal
179
Jean Berstel
Marie-Pierre Beal
180
Jean Berstel
comporte 18 interfaces dont les suivantes
comporte les interfaces suivantes
Driver,
DataSource,
Connection,
ConnectionPoolDataSource,
Statement, PreparedStatement, CallableStatement,
PooledConnection,
ResultSet,
RowSet, derive de ResultSet,
ResultSetMetaData, DataBaseMetaData,
JDBCRowSet, CachedRowSet, ..., derivent de RowSet.
Blob, Clob, Array (depuis SQL-3, Binary Large Object, Character Large Object). Ces interfaces sont destinees `a traiter
des bases de donnees o`u lon stocke par exemple des images.
Linterface Array est utilisee pour recuperer un attribut (une
seule colonne de la BDR) qui contient plusieurs informations
rangees dans un tableau (exemple : les notes dun etudiant).
RowSetMetaData, derive de ResultSetMetadata.
Marie-Pierre Beal
181
Jean Berstel
Marie-Pierre Beal
182
Jean Berstel
Statement st = [Link]();
String s = "SELECT * FROM Apprenti;";
ResultSet rs = [Link](s);
Manipulations de base
Le code SQL nest pas interprete par Java mais par le pilote
associe lors de la connexion.
Pr
eparer une requ
ete
` partir de lobjet de la classe Connection, on recup`ere un
A
objet de la classe Statement.
Statement st = [Link]();
Il existe trois types de Statement
Statement : requetes statiques simples
PreparedStatement : requetes dynamiques pre-compilees
avec param`etres.
CallableStatement : requetes stockees.
Lancer une requ
ete
Les methodes executeQuery et executeUpdate de la classe
Statement permettent dexecuter une requete SQL passee en
argument sous la forme dune String.
La methode executeQuery est utilisee pour les requetes de
type SELECT et renvoie un objet ResultSet qui represente
les t-uples resultats de la requete.
La methode executeUpdate est utilisee pour les requetes
modifiant une table (INSERT, UPDATE, CREATE TABLE,
DROP TABLE, DELETE). Elle retourne un entier indiquant
le nombre de t-uples traites.
La methode execute execute nimporte quelle requete.
Exemple : pour obtenir tous les t-uples de la table Apprenti.
Marie-Pierre Beal
183
Jean Berstel
Marie-Pierre Beal
184
Jean Berstel
Correspondances de types
Lobjet de la classe ResultSet represente les t-uples resultats.
On peut les parcourir avec next() et previous().
Les colonnes sont referencees par leur nom (lattribut de la
relation representee par la table) ou leur numero.
Lacc`es aux colonnes se fait par une methode getString(),
getInt(),..., (avec argument String ou int), suivant le type
de lattribut.
Les methodes Object getObject(String) ou Object
getObject(int) renvoient un objet correspondant au type
de lattribut (possibilite de recuperer un objet Java si la base
le permet (SQL type JAVA OBJECT)).
...
Statement st = [Link]();
String s = "SELECT * FROM Apprenti;";
ResultSet rs = [Link](s);
String n,p; int i;
while ([Link]()) {
n = [Link]("Nom");
p = [Link]("Prenom");
i = [Link]("NSS");
[Link](n+" "+p" "+i);
}
[Link]();
[Link]();
[Link]();
Type SQL
CHAR, VARCHAR
BIT
INTEGER
BIGINT
REAL
DOUBLE, FLOAT
DATE
BLOB
CLOB
ARRAY
DATE
REF
STRUCT
SQL types
...
classe ou interface Java
String
boolean
int
long
float
double
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
[Link]
...
On peut tester si la valeur dune colonne est la valeur NULL de
SQL avec la methode wasNull() de ResultSet qui renvoie
vraie si lon vient de lire une valeur nulle.
Les methodes getInt() ... convertissent une valeur NULL en
une valeur compatible avec le type renvoye (0 pour les valeurs
numeriques de base, null pour une reference, false pour un
booleen).
Marie-Pierre Beal
185
Jean Berstel
Exemple : du mod`ele objet au mod`ele relationnel
Marie-Pierre Beal
186
Jean Berstel
Exemple : creation de tables et interrogation
On consid`ere le schema relationnel forme des relations suivantes.
Apprenti (Nom, Prenom, NSS)
Prenom
Nom
Nom
Apprenti
Ingenieur (Nom, Prenom, CodeIngenieur, NomEntreprise,
CodeEntreprise)
Prenom
NSS
Ingenieur
CodeIngenieur
Enseignant (Nom, Prenom, statut, CodeEnseignant)
Cours (Intitule, CodeCours)
NomEntreprise
Inscription
CodeEntreprise
Tutorat
Inscription (NSS, CodeCours)
Tutorat (NSS, CodeEnseignant, CodeIngenieur)
Prenom
CodeCours
Cours
Affectation
Enseignant
Nom
CodeEnseignant
Intitule
Marie-Pierre Beal
Statut
187
Affectation (CodeEnseignant, CodeCours)
Jean Berstel
En rouge sont marques les attributs identifiants ou cles (specifies
UNIQUE en SQL). Tous les attributs seront non NULL sauf Statut
et Prenom.
Remarque : SQL ne distingue pas minuscule et majuscule (CodeIngenieur sera identique `a codeingenieur). Les noms des tables
et attributs ci-dessus commencent par une majuscule mais ceci
nindique pas quil font reference `a une quelconque classe Java.
Marie-Pierre Beal
188
Jean Berstel
Creation de la base
une ligne blanche.
import [Link].*;
import [Link].*;
public class Creation{
public static DataSource getSource() throws Exception {
Context ctx = new InitialContext();
DataSource source = (DataSource) [Link]("jdbc/beal_base");
return source;
}
public Creation() throws Exception{
DataSource source = [Link]();
Connection co = [Link]();
// lecture du fichier pour creer la base
Statement st = [Link]();
FileReader fichier = new FileReader("[Link]");
BufferedReader in = new BufferedReader(fichier);
StringBuilder sb = new StringBuilder();
String line;
while ( (line = [Link]()) != null) {
if ([Link]("")) {
[Link]([Link]());
//[Link]([Link]());
sb = new StringBuilder();
}
else { [Link](line+\n); }
}
[Link]();
[Link]();
[Link]();
}
public static void main(String[] args) throws Exception{
new Creation();
}
}
Marie-Pierre Beal
Dupont |
Dupond |
Tintin |
Milou |
(4 rows)
Jacques
Francois
David
Jerome
189
|
|
|
|
Jean Berstel
1450
1451
1452
1453
CREATE TABLE Enseignant
(Nom VARCHAR(25) NOT NULL,
Prenom VARCHAR(25),
Statut VARCHAR(25),
CodeEnseignant INTEGER NOT NULL UNIQUE);
...
INSERT INTO Apprenti
VALUES(Dupont,Jacques,1450);
...
Verification (ci-dessous par connexion directe `a la base sous Unix) :
beal_base=> SELECT * FROM Enseignant;
nom
|
prenom
| statut
| codeenseignant
---------+--------------+-----------+---------------Beal
| Marie-Pierre | titulaire |
8001
Roussel | Gilles
| titulaire |
8002
Berstel | Jean
| titulaire |
8003
Revuz
| Dominique
| titulaire |
8004
(4 rows)
beal_base=> SELECT * FROM Ingenieur;
nom
| prenom | codeingenieur |
nomentreprise
| codeentr
------------+---------+---------------+-------------------+---------Atome
| Michel |
9202 | CEA
|
100
Dechet
| Ludovic |
9203 | ANDRA
|
200
Monge
| Gaspard |
9204 | CEA
|
100
Banquetout | Felix
|
9205 | Credit-Avantageux |
300
(4 rows)
beal_base=> SELECT * FROM Apprenti;
nom
| prenom | nss
--------+----------+-----Marie-Pierre Beal
190
Jean Berstel
Exemple dinterrogation avec une requete statique
On demande les noms et prenoms de tous les apprentis dont le
tuteur enseignant a pour nom "Beal".
beal_base=> SELECT * FROM Cours;
intitule
| codecours
-----------------------+----------Java
| IR00
Interfaces graphiques | IR01
Systemes
| IR04
Reseaux
| IR12
(4 rows)
public class Interrogation{
public Interrogation(Connection co) throws Exception{
Statement st = [Link]();
// donne les apprentis dont le tuteur enseignant est Beal
String s ="SELECT [Link], [Link] "+
"FROM Tutorat, Apprenti, Enseignant "+
"WHERE [Link] "+
"= [Link] "+
"AND [Link] = [Link] "+
"AND [Link] = Beal ;";
ResultSet rs = [Link](s);
[Link]("Mes tutes :");
String n,p;
while ([Link]()){
n = [Link]("Nom");
p = [Link]("Prenom");
[Link](n+" "+p);
}
[Link](); [Link]();
}
public static void main(String[] args) throws Exception {
DataSource source = [Link]();
Connection co = [Link]();
Interrogation i = new Interrogation(co);
if (co != null) [Link]();
}}
beal_base=> SELECT * FROM Tutorat;
nss | codeenseignant | codeingenieur
------+----------------+--------------1450 |
8001 |
9202
1451 |
8001 |
9204
1452 |
8002 |
9205
1453 |
8003 |
9202
(3 rows)
beal_base=> SELECT * FROM Affectation;
codeenseignant | codecours
----------------+----------8001 | IR00
8003 | IR01
8004 | IR04
8004 | IR12
(4 rows)
Le resultat est
Mes tut
es :
Dupont Jacques
Dupond Francois
Marie-Pierre Beal
191
Jean Berstel
Marie-Pierre Beal
192
Jean Berstel
Creation dune requete pre-compilee
Conservation de lintegrite de la base
La plupart des SGBDR permettent des requetes pre-compilees. La
methode PrepareStatement() de la classe Connection renvoie
un objet PreparedStatement o`u
Afin de conserver lintegrite de la base, certaines requetes sont regroupees par paquets (appeles transactions) et ne sont validees que
si toutes se sont executees normalement. Par defaut une requete
constitue une transaction.
Les arguments qui seront passes de facon dynamique sont tous
notes ?.
Ils sont ensuite positionnes par les methodes
setInt(), setString(), ..., setNull() de la classe
PreparedStatement qui prennent en param`etres le numero
de largument (compte `a partir de 1) et largument lui-meme.
Les requetes sont ensuite lancees avec une des methodes
execute sans argument.
Validation des transactions
Par defaut une transaction est validee si lexecution des
requetes (par executeUpdate) sest bien passee. Par exemple, si une exception SQLException est levee, la transaction
nest pas validee.
On peut changer ce mode par defaut par
[Link](false);
public PreparedInterrogation(String arg, Connection co)
throws Exception{
...
String s =
"SELECT [Link], [Link] "+
"FROM Tutorat, Apprenti, Enseignant "+
"WHERE [Link] = [Link] "+
"AND [Link] = [Link] "+
"AND [Link] = ? ;";
PreparedStatement ps = [Link](s);
[Link](1,arg);
ResultSet rs = [Link]();
...
}
public static void main(String[] args) throws Exception{
...
new PreparedInterrogation("Beal",co);
}
Marie-Pierre Beal
193
Jean Berstel
Pour valider les changements il faut alors le signaler explicitement par
[Link]();
On peut annuler les commandes non encore validees par un
commit par :
[Link]();
Letat de la base juste apr`es le dernier commit est restaure.
Marie-Pierre Beal
Exemple
Linsertion dun nouvel apprenti peut se faire par :
195
Jean Berstel
Les meta-donnees
public Transaction(String nom, String prenom, int nss,
int codeTE, int codeTI, Connection co) throws Exception{
[Link](false);
String s = "INSERT INTO Apprenti "+
"VALUES(?,?,?) ;";
PreparedStatement ps = [Link](s);
[Link](1,nom); [Link](2,prenom); [Link](3,nss);
[Link]();
s = "INSERT INTO Inscription "+
"VALUES(?,IR00) ;";
ps = [Link](s);
[Link](1,nss);
[Link]();
s = "INSERT INTO Tutorat "+
"VALUES(?, ?, ?) ;";
ps = [Link](s);
[Link](1,nss); [Link](2,codeTE); [Link](3,codeTI);
[Link]();
// demande de transaction
[Link]();
[Link](true);
[Link]();
}
// arriv
ee du nouvel apprenti Edgar Jacobs
public static void main(String[] args) throws Exception {
DataSource source = [Link]();
Connection co = [Link]();
new Transaction("Jacobs","Edgar",1444, 8002, 9204);
[Link]();
}
beal_base=# SELECT * FROM apprenti WHERE [Link] = Jacobs;
nom
| prenom | nss
--------+--------+-----Jacobs | Edgar | 1444
(1 row)
Marie-Pierre Beal
194
Jean Berstel
M
eta-donn
ees sur les r
esultats
La methode ResultSetMetaData getMetaData() de la
classe ResultSet permet dobtenir des informations sur les
donnees renvoyees (et non ces donnees elles-memes).
On peut ensuite obtenir
le nombre de colonnes : getColumnCount(),
le nom dune colonne : getColumnName(int column),
si NULL SQL peut etre stocke dans une colonne : int
isNullable(int column).
M
eta-donn
ees sur la base
Pour recuperer des informations sur la base elle-meme dans son
ensemble, on utilise la methode getMetaData() de la classe
Connection.
Elle renvoie un objet de la classe DatabaseMetaData.
Cette derni`ere interface poss`ede des methodes pour obtenir des
informations sur la base.
Marie-Pierre Beal
196
Jean Berstel
Modifications de la base `a partir de resultats JDBC 2
public class MetaInterrogation{
public MetaInterrogation(Connection co) throws Exception{
Statement st = [Link]();
String s = "SELECT * from Ingenieur ;";
ResultSet rs = [Link](s);
ResultSetMetaData rsmd = [Link]();
int nbColonnes = [Link]();
for (int i = 1; i <= nbColonnes; i++) {
[Link]([Link](i)+" ");
}
[Link]();
for (int i = 1; i <= nbColonnes; i++) {
[Link]([Link](i)+" ");
} [Link]();
[Link]([Link]+" ");
[Link]([Link]+" ");
[Link]([Link]+" ");
DatabaseMetaData dbmd = [Link]();
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link]([Link]());
[Link](); [Link]();
}}
$ java MetaInterrogation
nom prenom codeingenieur nomentreprise codeentreprise
0 1 0 0 0
0 1 2
PostgreSQL
jdbc:postgresql://localhost:5432/beal_base?prepareThreshold=0
beal
PostgreSQL Native Driver
false
// Cette base nautorise pas les UPDATE positionn
es.
Marie-Pierre Beal
197
Jean Berstel
Modifications de la base `a partir de resultats JDBC 3
Il est possible (JDBC 2, vieux) de modifier la base `a partir des
objets ResultSet.
public class ResultSetUpdate{
public ResultSetUpdate(Connection co) throws Exception{
String s = "SELECT * FROM Apprenti ; ";
// r
esultats `
a modifier
Statement st = [Link](
ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
ResultSet rs = [Link](s);
[Link](5);
[Link]([Link](2)); // Edgar
[Link](2, "Edgar P."); //change la colonne 2
[Link]();
// mise `
a jour dans la base
[Link]();
[Link]();
}
public static void main(String[] args) throws Exception {
DataSource source = [Link]();
Connection co = null;
try {
co = [Link]();
new ResultSetUpdate(co);
} catch (Exception e) {
[Link]();
}
if (co != null) [Link]();
}
}
Marie-Pierre Beal
Jean Berstel
public class CachedRowSetUpdate {
public CachedRowSetUpdate throws Exception {
CachedRowSetImpl crs = null;
try {
crs = new CachedRowSetImpl(); // dans [Link]
[Link](ResultSet.TYPE_SCROLL_INSENSITIVE);
[Link](ResultSet.CONCUR_UPDATABLE);
String s = "SELECT * FROM Apprenti ; ";
[Link](s);
[Link](java/beal_base"); // g
er
e par JNDI;
[Link]("beal");
[Link]("");
[Link](5);
[Link](2, "Edgar P.");
[Link](); // mise `
a jour dans le RowSet
[Link](); // mise `
a jour dans la base
Un RowSet est un objet contenant un ensemble de lignes
provenant dun ResultSet.
Il existe deux types de RowSet, ceux qui sont en permanence connectes `a la base, comme JDBCRowSet, et ceux qui
ne se connectent `a la base que lorsque cest necessaire, comme
CachedRowSet.
Ainsi un CachedRowSet effectue les modifications dans un
tampon avant de les commuter sur la base via un driver ou
une DataSource. Il garde aussi une copie de la zone avant
les modifications pour tester sil ny a pas eu de modifications
concurrentes pendant quil etait deconnecte.
import
import
import
import
import
import
198
} catch (SQLException e) {
[Link]([Link]());
} catch (Exception e) {
[Link]();
} finally {
if (crs != null) [Link]();
}
[Link].*;
[Link].*;
[Link].*;
[Link].*;
[Link].*;
[Link].*;
public static void main(String[] args) throws Exception {
new CachedRowSetUpdate();
}
}
Marie-Pierre Beal
199
Jean Berstel
Marie-Pierre Beal
200
Jean Berstel
Introspection
class [Link]
interface [Link]
interface [Link]
class [Link]
interface [Link]
La classe [Link]<T> :
permet de manipuler les classes et interfaces comme des objets;
offre des possibilites dintrospection (exploration des methodes
et constructeurs dune classe).
On peut ensuite recuperer un objet methode. Les classes de ces
objets sont definies dans le paquetage [Link] :
class Test {
public static void main(String[] args) {
// La classe Class<T> repr
esente la classe dun objet
// de type T.
Class<Float> c1 = [Link]; [Link](c1);
Class<Float> c2 = [Link]; [Link](c2);
Class<List> c3 = [Link]; [Link](c3);
// [Link]<Integer>.class; erreur
Class<Cloneable> c4 = [Link]; [Link](c4);
Une instance de la classe Class<T> est associee `a toutes les classes,
interfaces, tableaux ou types primitifs.
On peut appliquer les methodes suivantes `a un objet c de la classe
Class<T>
getDeclaredMethods() retourne un tableau dobjets de la
classe [Link], les methodes declarees
dans c;
getMethods() retourne aussi les methodes heritees;
getMethods(String, Class... parameterTypes)
recherche une methode en fonction de son profil.
Une methode de la classe Method peut ensuite etre invoquee par
invoke().
// [Link]() renvoie un objet de type Class<? extends E>
// o`
u E est le type abrasion du type de o.
String s = "toto";
Class<? extends String> c5 = [Link]();
[Link](c5);
List<Integer> l = new ArrayList<Integer>();
Class<? extends List> c6 = [Link]();
try {
Class<?> c7 = [Link]("[Link]");
[Link](c7);
} catch (ClassNotFoundException e) {
}
}
}
Marie-Pierre Beal
201
Jean Berstel
Marie-Pierre Beal
import [Link].*;
import [Link];
public class MyDate{
public static void main(String[] args) throws Exception {
Class<?> classeDate = [Link]("[Link]"); // ou "Date"
Object myDate = [Link]();
//une instance de la classe Date est cr
e
ee
Method myOutput =
[Link]("toString", (Class[])null);
//retourne la methode toString() de la classe Date
[Link](
(String) [Link](myDate, (Object[])null));
//appel de toString() sur myDate
Date today = new Date();
[Link](today);
[Link](myDate);
}
}
On obtient :
> java Test
Wed Mar 30 10:09:32 GMT 2005
Wed Mar 30 10:09:32 GMT 2005
Wed Mar 30 10:09:32 GMT 2005
import [Link].*;
import [Link];
public static void main(String[] args) throws Exception{
Class<Date> classeDate = [Link];
Date myDate = [Link]();
// une instance de la classe Date est cr
ee
Method myOutput =
[Link]("toString", (Class[])null);
// on recupere la methode toString() de la classe Date
[Link](
Marie-Pierre Beal
203
Jean Berstel
202
Jean Berstel
(String) [Link](myDate,(Object[])null));
// appel de toString() sur myDate
Date today = new Date();
[Link](today);
[Link](myDate);
}
Soit la classe MyClasse
public class MyClasse {
public static void toto(int i){
[Link](i);
}
}
Et la classe Test
import [Link];
public class Test {
public static void main(String[] args) {
Class<MyClasse> c = [Link];
[Link](c);
Method[] t=[Link]();
for(int i=0; i< [Link]; i++){
[Link](t[i]);
}
try{
Method m = [Link]("toto", [Link]);
Integer i = 100;
MyClasse o = [Link]();
[Link](o,i);
[Link](i);
[Link](i);
}
catch(Exception e){//Nothing
[Link](e);
}
}
}
Marie-Pierre Beal
204
Jean Berstel
Le chargement de classes
public static void [Link](int)
100
100
100
Un chargeur de classes (classloader) est une instance dune sousclasse de la classe abstraite [Link]. Il charge
le bytecode dune classe `a partir dun fichier .class et la rend
accessible aux autres classes.
Principe du fonctionnement de la methode loadClass() de la
classe ClassLoader :
1. appel `a findLoadedClass() pour voir si la classe nest pas
dej`a chargee;
2. demande de chargement de la classe `a un chargeur parent
obtenu par getParent();
3. en cas dechec, appel de la methode findClass();
4. levee de lexception ClassNotFoundException en cas de nouvel echec.
Marie-Pierre Beal
205
Jean Berstel
public Class<?> loadClass(String name)
throws ClassNotFoundException {
try {
Class<?> c = findLoadedClass(name);
if (c != null) return c;
c = findClass(name);
if (c !=null) return c;
} catch (Exception e) {
throw new ClassNotFoundException(name);
}
}
La methode findClass() appelle une methode defineClass()
qui est la methode de base de tout chargeur de classes. Elle
cree une instance de la classe Class
stocke la classe dans le chargeur
La signature de defineClass() est :
Class<?> defineClass(String name,byte[] b,int off,int len)
throws ClassFormatError
207
206
Jean Berstel
import [Link].*;
ClassLoader parent = getParent();
try {
c = [Link](name);
if (c != null) return c;
} catch (ClassNotFoundException e) {}
Marie-Pierre Beal
Marie-Pierre Beal
Jean Berstel
public class VerboseClassLoader extends ClassLoader{
public VerboseClassLoader(){
super(getSystemClassLoader());//chargeur parent en param.
}
public Class<?> loadClass(String name)
throws ClassNotFoundException {
[Link]("Chargement de "+ name);
try {
byte[] b = loadClassData(new File(name+".class"));
return defineClass(name,b,0,[Link]);
} catch (Exception e) {
return getParent().loadClass(name);
}
}
private byte[] loadClassData(File f) throws IOException {
FileInputStream entree = new FileInputStream(f);
int length = (int)[Link]();
int offset = 0;
int nb;
byte[] tab = new byte[length];
while (length != 0) {
nb = [Link](tab,offset,length);
length -= nb;
offset += nb;
}
return tab;
}
}
Marie-Pierre Beal
208
Jean Berstel
VerboseClassLoader cl = new VerboseClassLoader();
Class<?> clazz = [Link]("A");
Object o = [Link]();
[Link]("Dans VerboseClassLoader : ");
if (o instanceof A)
[Link]("o instance de A");
else
[Link]("o nest pas instance de A");
[Link](([Link]()).getClassLoader());
A o2 = new A();
[Link](([Link]()).getClassLoader());
}
}
Etant
donnees trois classes vides B,C et D, la classe A est :
public class A extends B {
C c;
D d;
public A() {
[Link]("nouveau A()");
d = new D();
}
lappel `a newInstance() cree un objet et charge les classes
necessaires `a sa creation;
o et o2 nappartiennent pas `a la meme classe : deux classes de
meme nom (ici A) peuvent coexister dans la machine virtuelle si
elles nont pas le meme chargeur de classe. Ceci est important
pour la programmation reseau.
On obtient :
> java VerboseClassLoader
Chargement de A
Chargement de B
Chargement de [Link]
Chargement de [Link]
Chargement de [Link]
nouveau A()
Chargement de D
Dans VerboseClassLoader : o nest pas instance de A
VerboseClassLoader@7d772e
nouveau A()
[Link]$AppClassLoader@94af67
public void inutile(){
c = new C();
}
}
Marie-Pierre Beal
209
Jean Berstel
Marie-Pierre Beal
210
Jean Berstel
Programmation concurrente
La programmation concurrente est lensemble des mecanismes
permettant lexecution concurrente dactions specifiees de facon
sequentielle.
En Java, deux mecanismes permettent un ordonnancement automatique des traitements :
La programmation concurrente
la concurrence entre commandes du syst`eme (processus);
la concurrence entre processus legers de la machine virtuelle.
1. Programmation concurrente
2. Processus legers
3. Les Thread
4. Exclusion mutuelle
5. Synchronisation
Marie-Pierre Beal
211
Jean Berstel
Marie-Pierre Beal
212
Jean Berstel
Processus legers
La classe [Link]
Un processus leger (thread) correspond `a un fil dexecution (une
suite dinstruction en cours dexecution). Il sagit dun processus
cree et gere par la machine virtuelle Java.
Au lancement dun programme, la machine virtuelle poss`ede
un unique processus leger qui execute le main() de la classe
appelee.
Sil y a plusieurs processus legers :
ils sont associes `a un meme programme;
ils sexecutent dans le meme espace memoire.
Lorsque lon parle de processus leger, il y a trois notions bien distinctes :
un objet representant le code `a executer (la cible).
La classe de cet objet implemente linterface Runnable.
un objet qui controle du processus leger.
Il est dune classe derivant de Thread.
un fil dexecution, cest-`a-dire la sequence dinstructions en
cours dexecution.
Cest le code de la methode run() de la cible.
Ne pas confondre Thread (le controleur) et Runnable (le controle).
Cest dautant plus facile que Thread implemente Runnable et
peut donc sautocontroler !
Marie-Pierre Beal
213
Un objet de la classe Thread ne represente pas un processus
leger mais un objet de controle du processus leger.
Jean Berstel
D
emarrage et terminaison
public class MyThread{
public static void main(String[] args) throws Exception{
Thread threadInitiale = [Link]();
[Link]("Thread initiale");
[Link](threadInitiale);
[Link](1000);
[Link]([Link]());
Thread myThread = new Thread();
[Link]("Ma thread");
[Link](myThread);
[Link]([Link]());
}
}
On obtient `a lexecution :
Thread[Thread initiale,5,main]
true
Thread[Ma thread,5,main]
false
Chaque processus leger appartient `a un groupe de processus legers
(ici main) et a une priorite (ici 5).
Marie-Pierre Beal
214
Jean Berstel
Le lapin et la tortue (premi`
ere version)
D
emarrage dun processus leger par la methode start() du
thread.
Ex
ecution du processus leger par le thread qui appelle la
methode run() du runnable.
La methode run() peut etre specifiee de deux facons differentes :
en implementant la methode run() de linterface Runnable
(solution explicite).
en redefinissant la methode run() de la classe Thread (solution
directe).
Le processus leger se termine `a la fin du run().
Classe des lapins
public class Lapin implements Runnable{
public void run() {
long t = [Link](), x = t;
for (int i = 0; i<5; i++){
x = [Link]();
[Link]("Lapin "+i
+ " au temps "+ (x-t) + " ms.");
try {
[Link](300); // il se repose peu
} catch(InterruptedException e) {}
}
x = [Link]();
[Link]("Lapin est arriv
e au temps "
+ (x-t) + " ms.");
}
}
Classe des tortues
La classe Thread poss`ede sept constructeurs qui specifient :
le nom du processus leger (par defaut Thread-i);
le groupe du processus leger (un objet de la classe
ThreadGroup);
la cible (target) du processus leger : un objet implementant
linterface Runnable qui precise la methode run() `a executer
lors du demarrage du processus leger.
Marie-Pierre Beal
215
Jean Berstel
public class Tortue implements Runnable{
public void run() {
long t = [Link](), x = t;
for (int i = 0; i<5 ; i++){
x = [Link]();
[Link]("Tortue "+i
+ " au temps "+ (x-t) + " ms.");
try {
[Link](500);
// il se repose beaucoup
} catch(InterruptedException e) {}
}
x = [Link]();
[Link]("Tortue est arriv
ee au temps "
+ (x-t) + " ms.");
}
}
Marie-Pierre Beal
216
Jean Berstel
public class MesThread{
public static void main(String[] args){
Runnable tortue = new Tortue();
Runnable lapin = new Lapin();
La thread lente
Thread tortueThread = new Thread(tortue);
Thread lapinThread = new Thread(lapin);
La thread rapide
0
[Link]();
[Link]();
On obtient :
Tortue 0 au temps 0 ms.
Lapin 0 au temps 0 ms.
Lapin 1 au temps 302 ms.
Tortue 1 au temps 515 ms.
Lapin 2 au temps 612 ms.
Lapin 3 au temps 922 ms.
Tortue 2 au temps 1025 ms.
Lapin 4 au temps 1232 ms.
Tortue 3 au temps 1535 ms.
Lapin est arriv
e au temps 1542 ms.
Tortue 4 au temps 2045 ms.
Tortue est arriv
ee au temps 2555 ms.
4
3
217
fin
Attention : Ici, les deux thread ont meme priorite, donc meme
acc`es au processeur (equite). Lequite dacc`es au processeur nest
pas assuree sur toutes les implementations des machines virtuelles.
Marie-Pierre Beal
Jean Berstel
fin
Marie-Pierre Beal
218
Jean Berstel
Terminaison dun processus l
eger
Le lapin et la tortue (deuxi`
eme version)
Terminaison normale : `a la fin de la methode run().
Classe des lapins etend Thread :
public class Lapin extends Thread {
public void run() {
// inchang
e
}
}
On peut forcer la terminaison dun processus leger avant la fin
du run() en terminant lapplication. Lapplication se termine
lorsque :
[Link]() est appelee par lun des processus legers;
Classe des tortues etend Thread :
tous les processus legers qui nont pas ete marques daemon
sont termines.
public class Tortue extends Thread {
public void run() {
// inchang
e
}
}
Un processus leger peut etre user ou daemon. On peut creer des
processus legers daemon grace `a la methode setDaemon() de la
classe Thread. (Ex. [Link](true);).
Mise en place
Priorites dacc`es au processeur
public class MesThread{
public static void main(String[] args){
Thread tortueThread = new Tortue();
Thread lapinThread = new Lapin();
Les niveaux de priorite dacc`es au processeur varient de 1 `a 10.
Des constantes de la classe Thread les definissent :
[Link] PRIORITY 10
[Link] PRIORITY 5
[Link] PRIORITY 1
[Link]();
[Link]();
}
}
On peut definir et consulter un niveau de priorite en appliquant
une des methodes suivantes sur lobjet de controle du processus
leger :
setPriority()
getPriority()
setMaxPriority()
Marie-Pierre Beal
219
Jean Berstel
Marie-Pierre Beal
220
Jean Berstel
Exclusion mutuelle
public class Table{
private int[] tab;
Une operation atomique est une operation qui ne peut etre interrompue une fois quelle a commence.
public synchronized int somme(){
int s = 0;
for (int i = 0 ; i < [Link] ; i++)
s += tab[i];
return s;
}
Java garantit latomicite de lacc`es et de laffectation des variables de type primitif (sauf long et double).
Java poss`ede un mecanisme dexclusion mutuelle entre processus legers. Il garantit latomicite dexecution de morceaux
de code.
Un verrou peut etre associe `a une portion de code et permet
dexclure lacc`es de deux processus legers sur cette portion.
Pour cela, on synchronise une portion de code relativement `a un
objet en utilisant le mot cle synchronized :
public synchronized void setElem(int i, int j){
tab[i] = j;
}
}
Pendant lexecution dun [Link]() ou dun [Link]()
dans un processus P, tout autre processus Q qui essaie de faire
[Link]() ou [Link]() sur le meme x est suspendu.
synchronized comme modificateur dune methode :
sapplique au code dune methode relativement `a lobjet
courant.
synchronized(obj){...
portion de code ...};
Pendant lexecution par un processus leger A dune portion de code
synchronized, tout autre processus leger essayant dexecuter une
portion de code synchronized relative au meme objet est suspendu. Une fois A termine, un seul des processus legers en attente
est relance.
Marie-Pierre Beal
221
Jean Berstel
Marie-Pierre Beal
Exemple : variante
Jean Berstel
S
uret
e et vivacit
e
public class Table{
private int[] tab;
Quelques notions :
s
urete (safety) rien de faux peut se produire. Lexclusion
mutuelle r`egle le probl`eme de lacc`es concurrent en ecriture.
public synchronized int somme(){
int s = 0;
for (int i = 0; i < [Link] ; i++)
s += tab[i];
return s;
}
vivacite (liveness) tout processus peut sexecuter.
Les diverses facettes de la non vivacite :
famine (contention): un processus leger est empeche de
sexecuter parce que un processus plus prioritaire accapare le
processeur;
public void setElem(int i, int j){
if (i < 0 || i>= [Link])
throw new IndexOutOfBoundsException();
synchronized(this) {
tab[i] = j;
}
}
endormissement (dormancy) : un processus leger est suspendu
et jamais reveille;
terminaison prematuree;
Dans cette version, seule laffectation est verouillee : un processus
qui essaie decrire `a un index hors bornes nest pas suspendu.
Marie-Pierre Beal
222
223
Jean Berstel
interblocage (deadlock) : plusieurs processus legers sattendent
mutuellement avant de continuer.
Marie-Pierre Beal
224
Jean Berstel
Synchronisation entre processus legers
Cinq processus legers (les Turner) veulent faire tourner un compteur (le Counter) qui compte modulo 5.
Voici le compteur:
Java propose deux mecanismes :
attente/notification avec wait() et notify()
wait() appele sur un objet suspend le processus leger courant
qui attend une notification dun autre processus via le moniteur
de lobjet;
notify() appele sur un objet lib`ere un processus leger en attente par wait() sur le moniteur du meme objet.
attente de terminaison avec join()
join() est appele sur lobjet de controle dun processus leger
dont la terminaison est attendue; le processus courant est alors
interrompu jusqu`a la fin de celui-ci.
Les methodes wait(), join() et sleep() peuvent etre interrompues (et leur processus est alors debloque). La methode bloquante l`eve une exception InterruptedException qui peut etre
captee.
Marie-Pierre Beal
225
Jean Berstel
Voici la classe des tourneurs.
public class Turner extends Thread{
private Counter c; // le compteur
private int numero; // num
ero du tourneur
public Turner(int numero, Counter c){
[Link]("Tourneur "+ numero + " cr
e
e.");
[Link] = numero;
this.c = c;
if (numero + 1 < [Link]()) {
new Turner(numero + 1, c);
}
[Link]("Tourneur "+ numero + " d
emarre.");
start();
}
public void run(){}
public class Counter {
private int max; // 5 dans lexemple
private int count = 0; // initialisation, importante !
public Counter (int max) {
[Link] = max;
}
public int getMax(){
return max;
}
public int getValue(){
return count;
}
public synchronized void increment(){
count = (count +1) % max ; // ce quun tourneur veut faire
}
}
La r`egle du jeu : un Tourneur ne peut faire tourner le compteur
que lorsquil est egal `a son numero.
Marie-Pierre Beal
226
Jean Berstel
public void run()
try {
for (int etape = 0 ; ; etape++) {
[Link]("Tourneur "+ numero
+ " in
etape "+ etape);
synchronized(c){
while (numero != [Link]())
[Link](); // suspend this
[Link]("Tourneur "+ numero
+ " out
etape "+ etape);
[Link]();
[Link](); // lib`
ere les threads supendus
}
}
} catch (InterruptedException e) {}
}
Et le resultat:
public static void main(String[] args) {
Counter c = new Counter(5);
new Turner(0, c);
}
...
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
...
Debut dexecution
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Tourneur
Marie-Pierre Beal
0
1
2
3
4
4
3
2
1
0
cr
e
e.
cr
e
e.
cr
e
e.
cr
e
e.
cr
e
e.
d
emarre.
d
emarre.
d
emarre.
d
emarre.
d
emarre.
227
Jean Berstel
Marie-Pierre Beal
4
4
3
3
2
2
1
1
0
0
0
1
2
3
4
4
3
d
emarre.
in
etape 0
d
emarre.
in
etape 0
d
emarre.
in
etape 0
d
emarre.
in
etape 0
d
emarre.
in
etape 0
out
etape 0
out
etape 0
out
etape 0
out
etape 0
out
etape 0
in
etape 1
in
etape 1
228
Jean Berstel
Un esclave travaille
On peut simuler des variables locales `a chaque processus leger.
Pour cela :
public class Slave implements Runnable {
private int result;
public int getResult(){ return result; }
public int hardWork(){ return 0; }
public void run(){ result = hardWork(); }
}
on cree un objet de la classe ThreadLocal;
on y acc`ede par Object get();
on le modifie par void set(Object o).
Le matre fait travailler lesclave, et attend, par join, la fin du
processus esclave.
public class MyTarget implements Runnable {
public ThreadLocal v = new ThreadLocal();
public void run() {
[Link](new Double([Link]()));
[Link]([Link]());
}
public static void main(String[] args){
MyTarget c = new MyTarget();
Thread t1 = new Thread(c);
Thread t2 = new Thread(c);
[Link]();
[Link]();
}
}
public class Master implements Runnable{
public void run(){
Slave e = new Slave();
Thread slave = new Thread(e);
[Link]();
// fait autre chose
try {
[Link](); // attente de fin du run
} catch (InterruptedException ex){}
int result = [Link]();
[Link](result);
}
}
Mise en place:
On obtient :
public class MasterTest{
public static void main(String[] args) {
Master m = new Master();
Thread master = new Thread(m);
[Link]();
}
}
Marie-Pierre Beal
Exemple
229
0.8955847189505597
0.43636788900311063
Jean Berstel
Marie-Pierre Beal
230
Jean Berstel