chap03suite.pps.svn-base

publicité
Exemple suite:
A a=new B();
a.f();
System.out.println("a.i="+a.i);
System.out.println("((B) a).i="+((B)a).i);
Donnera:




f() de B, i=3
g() de A, i=4
a.i=4
((B) a).i=3
POO-L3 H. Fauconnier
1
Remarques:




La variable i de A est occultée par la variable
i de B
La variable i de A est toujours présente dans
tout objet de B
Le méthode g de A a accès à toutes les
variables définies dans A (et uniquement à
celles-là)
La méthode f de B redéfinit f. f() redéfinie a
accès à toutes les variables définies dans B
POO-L3 H. Fauconnier
2
E) Divers

super

Le mot clé super permet d’accéder aux
méthodes de la super classe

En particulier super permet dans une méthode
redéfinie d’appeler la méthode d’origine
(exemple: super.finalize() appelé dans une
méthode qui redéfinit le finalize permet
d'appeler le finalize de la classe de base)
POO-L3 H. Fauconnier
3
Exemple
class Base{
protected String nom(){
return "Base";
}
}
class Derive extends Base{
protected String nom(){
return "Derive";
}
protected void print(){
Base maref = (Base) this;
System.out.println("this.name():"+this.nom());
System.out.println("maref.name():"+maref.nom());
System.out.println("super.name():"+super.nom());
}
------------this.name():Derive
maref.name():Derive
super.name():Base
POO-L3 H. Fauconnier
4
Contrôle d’accès




protected: accès dans les classes dérivées
Le contrôle d’accès ne concerne pas la
signature
Une méthode redéfinie peut changer le
contrôle d’accès mais uniquement pour élargir
l’accès (de protected à public)
Le contrôle d’accès se fait à la compilation
POO-L3 H. Fauconnier
5
Interdire la redéfinition



Le modificateur final interdit la
redéfinition pour une méthode
(Bien sûr une méthode de classe ne
peut être redéfinie! Elle peut être
surchargée)
Une variable avec modificateur final
peut être occultée
POO-L3 H. Fauconnier
6
E) Constructeurs et héritage

Le constructeurs ne sont pas des méthodes
comme les autres:


le redéfinition n’a pas de sens.
Appeler un constructeur dans un
constructeur



super() appelle le constructeur de la super classe
this() appelle le constructeur de la classe ellemême
Ces appels doivent se faire au début du code du
constructeur
POO-L3 H. Fauconnier
7
Constructeurs

Principe:


Quand une méthode d’instance est appelée
l’objet est déjà créé.
Création de l’objet (récursivement)
1.
2.
3.
Invocation du constructeur de la super classe
Initialisations des champs par les
initialisateurs et les blocs d’initialisation
Une fois toutes ces initialisations faites appel
du corps du constructeur (super() et this() ne
font pas partie du corps)
POO-L3 H. Fauconnier
8
Exemple
class X{
protected int xMask=0x00ff;
protected int fullMask;
public X(){
fullMask = xMask;
}
public int mask(int orig){
return (orig & fullMask);
}
}
class Y extends X{
protected int yMask = 0xff00;
public Y(){
fullMask |= yMask;
}
}
POO-L3 H. Fauconnier
9
Résultat
xMask
yMask
fullMask
Val. par défaut des champs
0
0
0
Appel Constructeur pour Y
0
0
0
Appel Constructeur pour X
0
0
0
Initialisation champ X
0x00ff
0
0
Constructeur X
0x00FF
0
0x00FF
Initialisation champs de Y
0x00FF
0xFF00
0x00FF
Constructeur Y
0x00FF
0xFF00
0xFFFF
POO-L3 H. Fauconnier
10
Remarques:


on ne peut pas (bien sûr) redéfinir une
méthode statique
le modificateur final permet
d'empêcher la redéfinition d'une classe
POO-L3 H. Fauconnier
11
La classe Objet


Toutes les classes héritent de la classe
Object
méthodes:







public final Class<? extends Object> getClass()
public int hashCode()
public boolean equals(Object obj)
protected Object clone() throws
CloneNotSupportedException
public String toString()
protected void finalize() throws Throwable
(wait, notify,notfyall)
POO-L3 H. Fauconnier
12
Exemple
class A{
int i;
int j;
A(int i,int j){
this.i=i;this.j=j;}
}
class D <T>{
T i;
D(T i){
this.i=i;
}
}
POO-L3 H. Fauconnier
13
Suite
public static void main(String[] args) {
A a=new A(1,2);
A b=new A(1,2);
A c=a;
if (a==b)
System.out.println("a==b");
else
System.out.println("a!=b");
if (a.equals(b))
System.out.println("a equals b");
else
System.out.println("a not equals b");
System.out.println("Objet a: "+a.toString()+" classe "+a.getClass());
System.out.println("a.hashCode()"+a.hashCode());
System.out.println("b.hashCode()"+b.hashCode());
System.out.println("c.hashCode()"+c.hashCode());
D <Integer> x=new D<Integer>(10);
System.out.println("Objet x: "+x.toString()+" classe "+x.getClass());
}
POO-L3 H. Fauconnier
14
Résultat:







a!=b
a not equals b
Objet a: A@18d107f classe class A
a.hashCode()26022015
b.hashCode()3541984
c.hashCode()26022015
Objet x: D@ad3ba4 classe class D
POO-L3 H. Fauconnier
15
En redéfinissant equals
class B{
int i;
int j;
B(int i,int j){
this.i=i;this.j=j;
}
public boolean equals(Object o){
if (o instanceof B)
return i==((B)o).i && j==((B)o).j;
else return false;
}
}
POO-L3 H. Fauconnier
16
Suite
B d=new B(1,2);
B e=new B(1,2);
B f=e;
if (d==e)
System.out.println("e==d");
else
System.out.println("d!=e");
if (d.equals(e))
System.out.println("d equals e");
else
System.out.println("a not equals b");
System.out.println("Objet d: "+d.toString());
System.out.println("Objet e: "+e.toString());
System.out.println("d.hashCode()"+d.hashCode());
System.out.println("e.hashCode()"+e.hashCode());

POO-L3 H. Fauconnier
17
Résultat:






d!=e
d equals e
Objet d: B@182f0db
Objet e: B@192d342
d.hashCode()25358555
e.hashCode()26399554
POO-L3 H. Fauconnier
18
Chapitre IV
Object, interfaces, classes imbriquées
Chapitre IV
1.
2.
3.
classe Object, clonage
interfaces
classes imbriquées
POO-L3 H. Fauconnier
20
Le clonage


les variables sont des références sur
des objets -> l'affectation ne modifie
pas l'objet
la méthode clone retourne un nouvel
objet dont la valeur initiale est une
copie de l'objet
POO-L3 H. Fauconnier
21
Points techniques




Par défaut la méthode clone duplique les
champs
la méthode clone de Object lance une
exception CloneNotSupportedException
l'interface Cloneable doit être
implémentée pour pouvoir utiliser la méthode
clone
la méthode clone est protected -> elle ne
peut être utilisée quand dans les méthodes
définies dans la classe ou ses descendantes.
POO-L3 H. Fauconnier
22
En conséquence




en implémentant Cloneable, le clonage est possible
pour la classe et les descendants directement
en implémentant Cloneable et en laissant passer
l'exception CloneNotSupportedException, le clonage
est possible
en n'implémentant pas Cloneable et en définissant
une méthode clone qui jette
CloneNotSupportedException, le clonage n'est plus
possible
si Cloneable n'est pas implémenté
CloneNotSupportedException est lancée à chaque
appel de clone
POO-L3 H. Fauconnier
23
Exemple
class A implements Cloneable{
int i,j;
A(int i,int j){
this.i=i; this.j=j;
}
public String toString(){
return "(i="+i+",j="+j+")";
}
protected Object clone() throws
CloneNotSupportedException{
return super.clone();
}
}
POO-L3 H. Fauconnier
24
Suite
A a1=new A(1,2);
A a2=null;
try {// nécessaire!
a2 =(A) a1.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
donnera:
a1=(i=1,j=2) a2=(i=1,j=2)
POO-L3 H. Fauconnier
25
Suite
class D extends A{
int k;
D(int i,int j){
super(i,j);
k=0;
}
public String toString(){
return ("(k="+k+")"+super.toString());
}
}
//…
D d1=new D(1,2);
D d2=null;
try { //nécessaire
d2=(D) d1.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
}
System.out.println("d1="+d1+" d2="+d2);
}
POO-L3 H. Fauconnier
26
Suite
class B implements Cloneable{
int i,j;
B(int i,int j){
this.i=i; this.j=j;
}
public String toString(){
return "(i="+i+",j="+j+")";
}
protected Object clone(){
try {
return super.clone();
} catch (CloneNotSupportedException ex) {
ex.printStackTrace();
return null;
}
}
}
POO-L3 H. Fauconnier
27
Suite
class C extends B{
int k;
C(int i,int j){
super(i,j);
k=0;
}
public String toString(){
return ("(k="+k+")"+super.toString());
}
}//...
B b1=new B(1,2);
B b2 =(B) b1.clone();
C c1=new C(1,2);
C c2 =(C) c1.clone();
POO-L3 H. Fauconnier
28
Pourquoi le clonage?


Partager ou copier?
Copie profonde ou superficielle?

par défaut la copie est superficielle:
POO-L3 H. Fauconnier
29
Exemple
class IntegerStack implements Cloneable{
private int[] buffer;
private int sommet;
public IntegerStack(int max){
buffer=new int[max];
sommet=-1;
}
public void empiler(int v){
buffer[++sommet]=v;
}
public int dépiler(){
return buffer[sommet--];
}
public IntegerStack clone(){
try{
return (IntegerStack)super.clone();
}catch(CloneNotSupportedException e){
throw new InternalError(e.toString());
}
}
}
POO-L3 H. Fauconnier
30
Problème:
IntegerStack un=new IntegerStack(10);
un.emplier(3);
un.empiler(9)
InetegerStack deux=un.clone();
Les deux piles partagent les mêmes données…
POO-L3 H. Fauconnier
31
Solution…
public IntegerStack clone(){
try{
IntegerStack nObj =
(IntegerStack)super.clone();
nObj.buffer=buffer.clone();
return nObj;
}catch(CloneNotSupportedException e){
//impossible
throw new InternalError(e.toString());
}
}
POO-L3 H. Fauconnier
32
Copie profonde
public class CopieProfonde implements Cloneable{
int val;
CopieProfonde n=null;
/** Creates a new instance of CopieProfonde */
public CopieProfonde(int i) {
val=i;
}
public CopieProfonde(int i, CopieProfonde n){
this.val=i;
this.n=n;
}
public Object clone(){
CopieProfonde tmp=null;
try{
tmp=(CopieProfonde)super.clone();
if(tmp.n!=null)
tmp.n=(CopieProfonde)(tmp.n).clone();
}catch(CloneNotSupportedException ex){}
return tmp;
}
}
POO-L3 H. Fauconnier
33
Suite
class essai{
static void affiche(CopieProfonde l){
while(l!=null){
System.out.println(l.val+" ");
l=l.n;
}
}
public static void main(String[] st){
CopieProfonde l=new CopieProfonde(0);
CopieProfonde tmp;
for(int i=0;i<10;i++){
tmp=new CopieProfonde(i,l);
l=tmp;
}
affiche(l);
CopieProfonde n=(CopieProfonde)l.clone();
affiche(n);
}
}
POO-L3 H. Fauconnier
34
Chapitre IV
1.
2.
3.
classe Object, clonage
interfaces
classes imbriquées
POO-L3 H. Fauconnier
35
classe abstraites
abstract class Benchmark{
abstract void benchmark();
public final long repeat(int c){
long start =System.nanoTime();
for(int i=0;i<c;i++)
benchmark();
return (System.nanoTime() -start);
}
}
class MonBenchmark extends Benchmark{
void benchmark(){
}
public static long mesurer(int i){
return new MonBenchmark().repeat(i);
}
}
POO-L3 H. Fauconnier
36
suite
public static void main(String[] st){
System.out.println("temps="+
MonBenchmark.mesurer(1000000));
}
Résultat:
temps=6981893
POO-L3 H. Fauconnier
37
Interfaces




Il n'y a pas d'héritage multiple en Java: une
classe ne peut être l'extension que d'une
seule classe
Par contre une classe peut implémenter
plusieurs interfaces (et être l'extension
d'une seule classe)
Une interface ne contient (essentiellement)
que des déclarations de méthodes
Une interface est un peu comme une classe
sans données membres et dont toutes les
méthodes seraient abstraites
POO-L3 H. Fauconnier
38
Héritage "multiple" en java
POO-L3 H. Fauconnier
39
Exemple:
interface Comparable<T>{
int compareTo(T obj);
}
class Couple implements Comparable<Couple>{
int x,y;
//
public int compareTo(Couple c){
if(x<c.x)return 1;
else if (c.x==x)
if (c.y==y)return 0;
return -1;
}
}
POO-L3 H. Fauconnier
40
Remarques…



Pourquoi, a priori, l'héritage multiple
est plus difficile à implémenter que
l'héritage simple?
Pourquoi, a priori, implémenter
plusieurs interfaces ne pose pas (trop)
de problèmes?
(Comment ferait-on dans un langage
comme le C?)
POO-L3 H. Fauconnier
41
Quelques interfaces




Cloneable: est une interface vide(!) un
objet qui l'implémente peut redéfinir la
méthode clone
Comparable: est une interface qui permet
de comparer les éléments (méthode
compareTo)
Runnable: permet de définir des "threads"
Serializable: un objet qui l'implémente
peut être "sérialiser" = converti en une suite
d'octets pour être sauvegarder.
POO-L3 H. Fauconnier
42
Déclarations

une interface peut déclarer:



des constantes (toutes les variables
déclarées sont static public et final)
des méthodes (elles sont implicitement
abstract)
des classes internes et des interfaces
POO-L3 H. Fauconnier
43
Extension


les interfaces peuvent être étendues avec
extends:
Exemple:
public interface SerializableRunnable
extends Serializable, Runnable;
(ainsi une interface peut étendre de plusieurs façons
une même interface, mais comme il n'y a pas
d'implémentation de méthodes et uniquement des
constantes ce n'est pas un problème)
POO-L3 H. Fauconnier
44
Exemple
interface X{
int val=0;
}
interface Y extends X{
int val=1;
int somme=val+X.val;
}
class Z implements Y{}
public class InterfaceHeritage {
public static void main(String[] st){
System.out.println("Z.val="+Z.val+" Z.somme="+Z.somme);
Z z=new Z();
System.out.println("z.val="+z.val+
" ((Y)z).val="+((Y)z).val+
" ((X)z).val="+((X)z).val);
}
}
---------------
Z.val=1 Z.somme=1
z.val=1 ((Y)z).val=1 ((X)z).val=0
POO-L3 H. Fauconnier
45
Redéfinition, surcharge
interface A{
void f();
void g();
}
interface B{
void f();
void f(int i);
void h();
}
interface C extends A,B{}
comment remplir le double contrat?
POO-L3 H. Fauconnier
46
Chapitre IV
1.
2.
3.
classe Object, clonage
interfaces
classes imbriquées
POO-L3 H. Fauconnier
47
Classes internes (nested classes)

Classes membres statiques


Classes membres


membres d'une classe englobante
Classes locales


membres statiques d'une autre classe
classe définie dans un bloc de code
Classes anonymes

classe locale sans nom
POO-L3 H. Fauconnier
48
Classe interne statique

membre statique d'une autre classe



classe ou interface
mot clé static
similaire aux champs ou méthodes
statiques: n'est pas associée à une
instance et accès uniquement aux champs
statiques
POO-L3 H. Fauconnier
49
Exemple
class PileChainee{
public static interface Chainable{
public Chainable getSuivant();
public void setSuivant(Chainable noeud);
}
Chainable tete;
public void empiler(Chainable n){
n.setSuivant(tete);
tete=n;
}
public Object depiler(){
Chainable tmp;
if (!estVide()){
tmp=tete;
tete=tete.getSuivant();
return tmp;
}
else return null;
}
public boolean estVide(){
return tete==null;
}
}
POO-L3 H. Fauconnier
50
exemple (suite)
class EntierChainable implements PileChainee.Chainable{
int i;
public EntierChainable(int i){this.i=i;}
PileChainee.Chainable next;
public PileChainee.Chainable getSuivant(){
return next;
}
public void setSuivant(PileChainee.Chainable n){
next=n;
}
public int val(){return i;}
}
POO-L3 H. Fauconnier
51
et le main
public static void main(String[] args) {
PileChainee p;
EntierChainable n;
p=new PileChainee();
for(int i=0; i<12;i++){
n=new EntierChainable(i);
p.empiler(n);
}
while (!p.estVide()){
System.out.println(
((EntierChainable)p.depiler()).val());
}
}
POO-L3 H. Fauconnier
52
Remarques


Noter l'usage du nom hiérarchique avec
'.'
On peut utiliser un import:


import PileChainee.Chainable;
import PileChainee;
(Exercice: réécrire le programme précédent
sans utiliser de classes membres
statiques)
POO-L3 H. Fauconnier
53
Classes membres




membre non statique d'une classe
englobante
peut accéder aux champs et méthodes
de l'instance
une classe interne ne peut avoir de
membres statiques
un objet d'une classe interne est une
partie de la classe englobante
POO-L3 H. Fauconnier
54
Exemple
class CompteBanquaire{
private long numero;
private long balance;
private Action der;
public class Action{
private String act;
private long montant;
Action(String act, long montant){
this.act=act;
this.montant= montant;
}
public String toString(){
return numero"+":"+act+" "+montant;
}
}
POO-L3 H. Fauconnier
55
Suite
//…
public void
balance
der=new
}
public void
balance
der=new
}
depot(long montant){
+= montant;
Action("depot",montant);
retrait(long montant){
-= montant;
Action("retrait",montant);
}
POO-L3 H. Fauconnier
56
Remarques


numero dans toString
this:


der=this.new Action(…);
CompteBancaire.this.number
POO-L3 H. Fauconnier
57
Classe interne et héritage
class Externe{
class Interne{}
}
class ExterneEtendue extends Externe{
class InterneEtendue extends Interne{}
Interne r=new InterneEtendue();
}
class Autre extends Externe.Interne{
Autre(Externe r){
r.super();
}
}
(un objet Interne (ou d'une de ses extensions) n'a de sens qu'à
l'intérieur d'un objet Externe)
POO-L3 H. Fauconnier
58
Quelques petits problèmes
class X{
int i;
class H extends Y{
void incremente(){i++;}
}
}
Si i est une donnée membre de Y… c'est ce i qui est
incrémenté
X.this.i et this.i lèvent cette ambiguïté.
POO-L3 H. Fauconnier
59
Suite
class H{
void print(){}
void print(int i){}
class I{
void print(){};
void show(){
print();
H.this.print();
// print(1); tous les print sont occultés
}
}
}
POO-L3 H. Fauconnier
60
Classes locales




classes définies à l'intérieur d'un bloc de
code,
analogue à des variables locales: une classe
interne locale n'est pas membre de la classe
et donc pas d'accès,
usage: créer des instances qui peuvent être
passées en paramètres
usage: créer des objets d'une extension
d'une classe qui n'a de sens que localement
(en particulier dans les interfaces
graphiques)
POO-L3 H. Fauconnier
61
Exemple

classes Collections (ou Containers):
classes correspondant à des structures
de données.


exemples: List, Set, Queue, Map.
L'interface Iterator permet de
parcourir tous les éléments composant
une structure de données.
POO-L3 H. Fauconnier
62
Iterator
public interface Iterator<E>{
boolean hasNext();
E next() throws NoSuchElementException;
void remove()throws
UnsupportedOperationException,
IllegalStateException;
}
POO-L3 H. Fauconnier
63
Exemple: MaCollection
class MaCollection implements Iterator<Object>{
Object[] data;
MaCollection(int i){
data=new Object[i];
}
MaCollection(Object ... l){
data=new Object[l.length];
for(int i=0;i<l.length;i++)
data[i]=l[i];
}
private int pos=0;
public boolean hasNext(){
return (pos <data.length);
}
public Object next() throws NoSuchElementException{
if (pos >= data.length)
throw new NoSuchElementException();
return data[pos++];
}
public void remove(){
throw new UnsupportedOperationException();
}
}
POO-L3 H. Fauconnier
64
Et une iteration:
public class Main {
public static void afficher(Iterator it){
while(it.hasNext()){
System.out.println(it.next());
}
}
public static void main(String[] args) {
MaCollection m=new
MaCollection(1,2,3,5,6,7);
afficher(m);
}
}
POO-L3 H. Fauconnier
65
Classe locale

Au lieu de créer d'implémenter
Iterator on pourrait aussi créer une
méthode qui retourne un iterateur.
POO-L3 H. Fauconnier
66
Exemple parcourir
public static Iterator<Object> parcourir(final Object[] data){
class Iter implements Iterator<Object>{
private int pos=0;
public boolean hasNext(){
return (pos <data.length);
}
public Object next() throws NoSuchElementException{
if (pos >= data.length)
throw new NoSuchElementException();
return data[pos++];
}
public void remove(){
throw new UnsupportedOperationException();
}
}
return new Iter();
}
POO-L3 H. Fauconnier
67
et l'appel
Integer[] tab=new Integer[12];
//…
afficher(parcourir(tab));
POO-L3 H. Fauconnier
68
Remarques


parcourir() retourne un itérateur pour le
tableau passé en paramètre.
l'itérateur implémente Iterator



mais dans une classe locale à la méthode
parcourir
la méthode parcourir retourne un objet de
cette classe.
data[] est déclaré final:

même si tous les objets locaux sont dans la portée
de la classe locale, la classe locale ne peut
accéder aux variables locales que si elles sont
déclarées final.
POO-L3 H. Fauconnier
69
Anonymat…

mais était-il utile de donner un nom à
cette classe qui ne sert qu'à créer un
objet Iter?
POO-L3 H. Fauconnier
70
Classe anonyme
public static Iterator<Object> parcourir1( final Object[] data){
return new Iterator<Object>(){
private int pos=0;
public boolean hasNext(){
return (pos <data.length);
}
public Object next() throws NoSuchElementException{
if (pos >= data.length)
throw new NoSuchElementException();
return data[pos++];
}
public void remove(){
throw new UnsupportedOperationException();
}
};
}
POO-L3 H. Fauconnier
71
Exemple interface graphique:
jButton1.addActionListener(new
ActionListener() {
public void
actionPerformed(ActionEvent evt){
jButton1ActionPerformed(evt);
}
});
POO-L3 H. Fauconnier
72
Principe…

ActionListener est une interface qui
contient une seule méthode



void actionPerformed(ActionEvent e)
cette méthode définit le comportement
voulu si on presse le bouton
Il faut que le Button jButton1 associe
l'événement correspondant au fait que
le bouton est pressé l'ActionListener
voulu: addActionListener
POO-L3 H. Fauconnier
73
Dans l'exemple
jButton1ActionPerformed est la méthode qui
doit être acivée
Création d'un objet de type ActionListener:
1.
2.
1.
2.
3.
3.
(Re)définition de ActionPerformed dans l'interface
ActionListener: appel de jButton1ActionPerformed
classe anonyme pour ActionListener
operateur new
ajout de cet ActionListener comme écouteur des
événements de ce bouton
jButton1.addActionListener
POO-L3 H. Fauconnier
74
Chapitre V
Exceptions
V) Exceptions
1.
2.
3.
4.
5.
Principes généraux
Déclarations de throws
try, catch et finally
Transfert d'information: chainage, pile
Assertions
POO-L3 H. Fauconnier
76
Exceptions et assertions

principe:

traitement des "erreurs"

quand une exception est lancée:




rupture de l'exécution séquentielle
"dépiler" les méthodes et les blocs
jusqu'à un traite exception adapté
erreur:

rupture du contrat:

précondition violée
POO-L3 H. Fauconnier
77
Exceptions

checked ou unchecked

checked: cas exceptionnel, mais dont l'occurrence
est prévue et peut être traitée (exemple: valeur
en dehors des conditions de la précondition,
indice hors d'un tableau…)


Une méthode qui peut lancer une checked exception
doit le déclarer
unchecked: il n'y a rien à faire, (exemple une
erreur interne de la JVM)

Une méthode qui peut lancer une unchecked exception
ne doit pas le déclarer
POO-L3 H. Fauconnier
78
Exceptions


Une exception est un objet d'une classe
dérivée de Thowable (en fait en général
de Exception)
Le mécanisme est le même que pour
tout objets:




on peut définir des sous-classes
des constructeurs
redéfinir des méthodes
ajouter des méthodes
POO-L3 H. Fauconnier
79
Exceptions et traite-exceptions


Un traite exception déclare dans son
entête un paramètre
Le type du paramètre détermine si le
traite-exception correspond à
l'exception

même mécanisme que pour les méthodes et
l'héritage
POO-L3 H. Fauconnier
80
Throw


Certaines exceptions et errors sont
lancé par la JVM
L'utilisateur peut définir ses propres
exceptions et les lancer lui-même:
throw expression;
l'expression doit s'évaluer comme une
valeur ou une variable qui peut être
affectée à Throwable
POO-L3 H. Fauconnier
81
Environnement

Par définition une exception va transférer le
contrôle vers un autre contexte



le contexte dans lequel l'exception est traitée est
différent du contexte dans lequel elle est lancée
l'exception elle-même peut permettre de passer
de l'information par son instanciation
l'état de la pile au moment de l'exception est
aussi transmis
public StackTraceElement[] getStackTrace() et
public void printStackTrace()
POO-L3 H. Fauconnier
82
Hiérarchie:

java.lang.Throwable (implements java.io.Serializable)

java.lang.Error




java.lang.AssertionError
java.lang.LinkageError
java.lang.ThreadDeath
java.lang.VirtualMachineError


exemple:java.lang.StackOverflowError
java.lang.Exception








java.lang.ClassNotFoundException
java.lang.CloneNotSupportedException
java.lang.IllegalAccessException
java.lang.InstantiationException
java.lang.InterruptedException
java.lang.NoSuchFieldException
java.lang.NoSuchMethodException
java.lang.RuntimeException

exemple: java.lang.IndexOutOfBoundsException
POO-L3 H. Fauconnier
83
Hiérarchie

Throwable:



la super classe des erreurs et des
exceptions
Error : unchecked
Exception :checked
POO-L3 H. Fauconnier
84
Exemple
public class MonException extends Exception{
public final String nom;
public MonException(String st) {
super("le nombre "+st+" ne figure pas");
nom=st;
}
}
POO-L3 H. Fauconnier
85
Exemple (suite)
class Essai{
static String[] tab={"zéro","un","deux","trois","quatre"};
static int chercher(String st ) throws MonException{
for(int i=0;i<tab.length;i++)
if (tab[i].equals(st))return i;
throw new MonException(st);
}
public static void main(String st[]){
try{
chercher("zwei");
}catch(Exception e){
System.out.println(e);
}
}
}
POO-L3 H. Fauconnier
86
Résultat

Donnera:
exceptions.MonException: le nombre zwei ne figure pas

e.printStackTrace(); dans le try bloc
donnera:
exceptions.MonException: le nombre zwei ne figure pas
at exceptions.Essai.chercher(MonException.java:29)
at exceptions.Essai.main(MonException.java:34)
POO-L3 H. Fauconnier
87
Throws

principe:

toute méthode qui peut générer
directement ou indirectement une
(checked) exception doit le déclarer par
une clause "throws" dans l'entête de la
méthode.


(les initialiseurs statiques ne peuvent donc pas
générer d'exceptions)
La vérification a lieu à la compilation
POO-L3 H. Fauconnier
88
Clause throws

Une méthode qui appelle une méthode
qui peut lancer une exception peut



attraper (catch) cette exception dans un
try bloc englobant la méthode qui peut
lancer cette exception
attraper cette exception et la
transformer en une exception déclarée
dans la clause throws de la méthode
déclarer cette exception dans la clause
throws de sa déclaration
POO-L3 H. Fauconnier
89
Clause throws et héritage

Si une classe dérivée redéfinit (ou
implémente) une méthode la clause
throws de la méthode redéfinie doit
être compatible avec celle d'origine


compatible = les exceptions de la clause
throws sont dérivées de celles de la
méthode d'origine
pourquoi?
POO-L3 H. Fauconnier
90
try, catch, finally
On attrape les exceptions dans des try-bloc:
try{
instructions
}catch(exception-type1 id1){
instructions
} catch(exception-type2 id2){
...
}finally{
instructions
}

POO-L3 H. Fauconnier
91
Principe:


le corps du try est exécuté jusqu'à ce qu'il
termine ou qu'une exception est lancée
Si une exception est lancée les clauses
"catch" sont examinées dans l'ordre



la première dont le type peut correspondre à
l'exception est choisie et son code exécuté
si aucun catch ne peut correspondre l'exception
est propagée
si une clause finally figure son code est ensuite
exécuté (toujours)
POO-L3 H. Fauconnier
92
Exemple
class A extends Exception{
}
class B extends A{
}
class essai{
public static void main(String[] st){
try{
throw new B();
}catch (A a){
System.out.println(a);
//
}catch (B b){
//
System.out.println(b);
}finally{
System.out.println("finally..");
}
}
}
POO-L3 H. Fauconnier
93
finally
public boolean rechercher(String fichier,
String mot) throws StreamException{
Stream input=null;
try{
input=new Stream(fichier);
while(!input.eof())
if(input.next().equals(mot))
return true;
return false;
}finally{
if (input != null)
input.close();
}
}
POO-L3 H. Fauconnier
94
Chaînage d'exceptions


Une exception peut être causée par une
autre.
il peut être utile dans ce cas de
transmettre la cause de l'exception
méthode:
public Throwable initCause(Throwable cause)

POO-L3 H. Fauconnier
95
Transmission d'information


en définissant une extension de la
classe et en définissant des
constructeurs
par défaut on a les constructeurs
public Throwable()
public Throwable(String message)
public Throwable(String message,
Throwable cause)
POO-L3 H. Fauconnier
96
Transmission d'information

On peut récupérer ces informations:
public String getMessage()
public Throwable getCause()

On peut obtenir l'état de la pile:
public void printStackTrace()
public StackTraceElement[]
getStackTrace()
POO-L3 H. Fauconnier
97
Exemple
class X extends Exception{
public X(){}
public X(String details){
super(details);
}
public X(Throwable e){
super(e);
}
public X(String details, Throwable e){
super(details,e);
}
}
POO-L3 H. Fauconnier
98
Suite
try{
}
-----
throw new A();
}catch (A a){
try {
throw new X(a);
} catch (X ex) {
ex.printStackTrace();
}
}
X: A
at essai.main(Finally.java:61)
Caused by: A
at essai.main(Finally.java:58)
POO-L3 H. Fauconnier
99
Remarque

à la place de:
throw new X(a);

on pourrait mettre
throw (X) new X().initCause(a);
(pourquoi le cast (X) est nécessaire?)
POO-L3 H. Fauconnier
100
Assertions



Une autre façon de garantir le contrat
est de définir des assertions qui
vérifient les invariants (ou les
préconditions)
Si l'assertion n'est pas vérifiée une
AssertionError est lancée
(une option de compilation permet de
vérifier ou non les assertions)
POO-L3 H. Fauconnier
101
Assertions

Syntaxe:
assert expr [: detail];
 expr est une expression boolean
 detail est optionnel et sera passé au
constructeur de AssertionError
(une string ou un Throwable)

Exemple:
assert i!=0 : "i ="+i+" i devrait être non nul";
POO-L3 H. Fauconnier
102
Assertions


par défaut les assertions ne sont pas
évaluées
pour les évaluer:
-enableassertions:nom_du_package
 -disableassertions:nom_du_package
avec en argument le ou les paquetages
concernés.

POO-L3 H. Fauconnier
103
Chapitre VI
Enumeration, tableaux, conversion de types,
noms
Types énumérés

Exemple:




enum Couleur {PIQUE, CŒUR, CARREAU, TREFLE,}
définit des constantes énumérées (champs static de la
classe)
on peut définir des méthodes dans un enum
des méthodes



public static E[] values() retourne les constantes dans l'ordre
de leur énumeration
public static E valueOf(String nom) la constante associé au
nom
un type enum étend implicitement java.lang.Enum (aucune
classe ne peut étendre cette classe)
POO-L3 H. Fauconnier
105
Tableaux



collection ordonnée d'éléments,
les tableaux sont des Object
les composants peuvent être de types
primitifs, des références à des objets
(y compris des références à des
tableaux),
POO-L3 H. Fauconnier
106
Tableaux

int [] tab= new int t[3];




indices commencent à 0
contrôle de dépassement


déclaration d'un tableau d'int
initialisé à un tableau de 3 int
ArrayIndexOutOfBoundException
length donne la taille du tableau
POO-L3 H. Fauconnier
107
Tableaux



un tableau final: la référence ne peut être changée
(mais le tableau référencé peut l'être)
tableaux de tableaux:
exemple:
public static int[][] duplique(int[][] mat){
int[][] res= new int[mat.length][];
for(int i=0;i<mat.length;i++){
res[i]=new int[mat[i].length];
for (int j=0;j<mat[i].length;j++)
res[i][j]=mat[i][j];
}
return res;
}
POO-L3 H. Fauconnier
108
Tableaux

exemple:
public static void affiche(int [][] tab){
for(int[] d:tab){
System.out.println();
for(int v:d)
System.out.print(v+" ");
}
}
POO-L3 H. Fauconnier
109
Initialisations
static int[][] pascal={
{1},
{1,1},
{1,2,1},
{1,3,3,1},
};
String[] nombre= {"un", "deux", "trois", "quatre"};
POO-L3 H. Fauconnier
110
Exemple
for(int i=1;i<p.length;i++){
p[i]=new int[i+1];
p[i][0]=1;
for(int j=1; j<i;j++){
p[i][j]=p[i-1][j-1]+p[i-1][j];
}
p[i][i]=1;
}
POO-L3 H. Fauconnier
111
Tableau et héritage

Object


X
X[]
int[]


Y
Z
Y[]
Y[] yA=new Y[3];
X[] xA=yA; //ok
xA[0]=new Y();
xA[1]=new X(); //non
xA[1]=new Z(); //non
Z[]
POO-L3 H. Fauconnier
112
Noms

il ya 6 espaces de noms





package
type
champ
variables locale
etiquettes
POO-L3 H. Fauconnier
113
Noms!?
package divers;
class divers{
divers divers(divers divers){
divers:
for(;;){
if (divers.divers(divers)==divers)
break divers;
}
return divers;
}
}
POO-L3 H. Fauconnier
114
Trouver la bonne méthode


Il faut pouvoir déterminer une seule
méthode à partir d'une invocation avec
des paramètres
problèmes: héritage et surcharge


(en plus des problèmes liés à la généricité)
principe trouver la méthode "la plus
spécifique"
POO-L3 H. Fauconnier
115
Règles
déterminer dans quelle classe chercher la méthode
(uniquement par le nom)
trouver les méthodes dans la classe qui peuvent
s'appliquer
1.
2.
1.
2.
3.
3.
4.
sans "boxing" sans nombre variable d'arguments
avec boxing
avec un nombre variable d'arguments
si une méthode a des types de paramètres qui
peuvent être affectés à une autre des méthodes de
l'ensemble -> la supprimer
s'il ne reste qu'une méthode c'est elle (sinon
ambiguïté sauf s'il s'agit de méthodes abstraites
POO-L3 H. Fauconnier
116
Exemple
void
void
void
void
A
AD1
ADD1
AD2
f(A a,AD2 ad2)//un
f(AD1 ad1,A a)//deux
f(ADD1 add1, AD2 s)//trois
f(A … a)//quatre
f(Aref, AD2ref);//a
f(ADD1ref, Aref);//b
f(AD1ref, ADD2ref);//c
f(AD1ref, AD2ref);//d
f(AD2ref, AD1ref);//e
ADD2
POO-L3 H. Fauconnier
117
Exemple (suite)





(a) correspond exactement à (un)
(b) correspond à (deux)
(c) peut correspondre aux trois
premiers mais (un) est moins spécifique
que (trois) idem entre (un) et (trois)
d'où résultat (trois)
(d) (un) et (deux) ne peuvent s'éliminer
(e) uniquement (quatre)
POO-L3 H. Fauconnier
118
Chapitre VII
Généricité
Chapitre VII
1.
2.
3.
4.
Principes généraux
Types génériques imbriqués
Types paramètres bornés
Méthodes génériques
POO-L3 H. Fauconnier
120
Principes




Paramétrer une classe ou une méthode par un
type:

une pile de X

une pile d'Object
En java toute classe étant dérivée de Object,
cela permet d'obtenir une forme de
généricité sans contrôle des types
La généricité est un mécanisme "statique"
assez complexe
la généricité existe dans d'autres langages
(exemple C++ et Ada)
POO-L3 H. Fauconnier
121
Exemple: File
public class Cellule<E>{
private Cellule<E> suivant;
private E element;
public Cellule(E val) {
this.element=val;
}
public Cellule(E val, Cellule suivant){
this.element=val; this.suivant=suivant;
}
public E getElement(){ return element;}
public void setElement(E v){
element=v;
}
public Cellule<E> getSuivant(){ return suivant;}
public void setSuivant(Cellule<E> s){
this.suivant=s;
}
}
POO-L3 H. Fauconnier
122
Suite
class File<E>{
protected Cellule<E> tete;
protected Cellule<E> queue;
private int taille=0;
public boolean estVide(){
return taille==0;
}
public void enfiler(E item){
Cellule<E> c=new Cellule<E>(item);
if (estVide())
tete=queue=c;
else{
queue.setSuivant(c);
queue=c;
}
taille++;
} //..
POO-L3 H. Fauconnier
123
suite
public E defiler(){
if (estVide())
return null;
Cellule<E> tmp=tete;
tete=tete.getSuivant();
taille--;
return tmp.getElement();
}
public int getTaille(){
return taille;
}
}
POO-L3 H. Fauconnier
124
Usage
Cellule<Integer> cel=new Cellule<Integer>(23);
File<Integer> fi=new File<Integer>();
File<String> fs=new File<String>();
File<Object> fobj=new File<Object>();
String[] st={"zéro","un","deux",
"trois","quatre","cinq"};
for(int i=0;i<st.length;i++){
fs.enfiler(st[i]);
fi.enfiler(i);
}
POO-L3 H. Fauconnier
125
Remarques

Une déclaration de type générique peut
avoir plusieurs paramètres:


Map<K,V>
Contrôle de type:

fs.enfiler(4) est refusé à la compilation
POO-L3 H. Fauconnier
126
Typage

Mais, une invocation ne crée pas un nouveau
type:




(fs.getClass()==fi.getClass()) est vrai
la classe est ici File
il s'agit surtout d'un contrôle (effectué à la
compilation)
à l'exécution fi n'a plus aucune information sur
quelle invocation a permis sa construction
POO-L3 H. Fauconnier
127
Conséquences

Aucune instanciation n'est possible
pour un type argument


Dans l'exemple: E v=new E();
est impossible
Pas de tableau de E
POO-L3 H. Fauconnier
128
Exemple
public E[] toArray(File<E> f){
E[] tab=new E[f.getTaille()]; //non
for(int i=0;i<f.getTaille();i++)
tab[i]=f.defiler();
}



Comment construire un tableau sans connaître le
type de base?
La classe Array et la méthode
Array.newInstance() permettraient de résoudre
ce problème (mais sans contrôle de type)
On peut aussi utiliser la classe Object.
POO-L3 H. Fauconnier
129
Object
public static <E> Object[]
toArray(File<E> f){
Object[] tab=new Object[f.getTaille()];
for(int i=0;i<f.getTaille();i++)
tab[i]=f.defiler();
return tab;
}
mais on perd l'avantage du contrôle de type.
POO-L3 H. Fauconnier
130
Contrôle du type


Pourtant, on peut passer un objet d'un
type paramètre à une méthode.
Comment se fait le passage des
paramètres?
 le compilateur passe le type le plus
général (Object) et utilise le cast
pour assurer le contrôle du typage.
POO-L3 H. Fauconnier
131
Chapitre VII
1.
2.
3.
4.
Principes généraux
Types génériques imbriqués
Types paramètres bornés
Méthodes génériques
POO-L3 H. Fauconnier
132
Types génériques imbriqués
public class FileSimpleChainageb <E>{
public class Cellule{
private Cellule suivant;
private E element;
public Cellule(E val) {
this.element=val;
}
public Cellule(E val, Cellule suivant){
this.element=val;
this.suivant=suivant;
}
public E getElement(){
return element;
}
public void setElement(E v){
element=v;
}//...
POO-L3 H. Fauconnier
133
Suite
public Cellule getSuivant(){
return suivant;
}
public void setSuivant(Cellule s){
this.suivant=s;
}
}
protected Cellule tete;
protected Cellule queue;
private int taille=0;
public boolean estVide(){
return taille==0;
}
public int getTaille(){
return taille;
}
POO-L3 H. Fauconnier
134
Fin…
public void enfiler(E item){
Cellule c=new Cellule(item);
if (estVide())
tete=queue=c;
else{
queue.setSuivant(c);
queue=c;
}
taille++;
}
public E defiler(){
if (estVide())
return null;
Cellule tmp=tete;
tete=tete.getSuivant();
taille--;
return tmp.getElement();
}
}
POO-L3 H. Fauconnier
135
Chapitre VII
1.
2.
3.
4.
Principes généraux
Types génériques imbriqués
Types paramètres bornés
Méthodes génériques
POO-L3 H. Fauconnier
136
Type paramètre borné

On peut borner le type paramètre:
class valeur implements Comparable<Valeur>{..}
…
interface SortedCollection<E extends Comparable<E>{}


E doit implémenter Comparable
(Comparable est une interface
générique)
(on peut avoir plusieurs contraintes
séparées par '&')
POO-L3 H. Fauconnier
137
Quelques petites difficultés



Si P est un type paramétré par un autre
type, et si A est une extension de B
alors P<A> n'est pas une extension de
P<B>.
Par exemple List<Integer> n'est pas un
sous-type de List<Number>
(notons que par contre Integer[] est un
sous-type de Number[])
POO-L3 H. Fauconnier
138
Exemple
static double somme(List<Number> l){
double res=0.0;
for(Number n:l)
res+=n.doubleValue();
return res;
}
public static void main(String[] st){
List<Integer> l= new ArrayList<Integer>();
for(int i=0;i<10;i++)l.add(i);
double s=somme(l); //incorrect
}
POO-L3 H. Fauconnier
139
Joker


Pour cela on peut introduire un joker
'?' pour représenter le type et mettre
des contraintes sur l'héritage
'?' représente n'importe quel type
static double somme2(List<? extends Number> l){
double res=0.0;
for(Number n:l)
res+=n.doubleValue();
return res;
}
POO-L3 H. Fauconnier
140
Types bornés

List<? extends Number>



indique que le type doit au moins être un Number
(tout type qui dérive de Number)
borné supérieurement (upper bounded): au moins
un Number ( Number ou type dérivé de)
On peut aussi imposer que le type soit une
superclasse d'un autre type


List<? super Integer>
borné inférieurement: au plus un Integer
(Integer ou super-classe de Integer)
POO-L3 H. Fauconnier
141
Sous-typage



List<?> est une super classe de
List<Object>
Et:
List<?>

List<? extends Number>


List<Number>
List<? extends Integer>
 List<Integer>
POO-L3 H. Fauconnier
142
Types paramètres bornés

Exemple:

SortedCollection est composée d'éléments du
type E et ces éléments peuvent être comparés.
Mais <E extends comparable<E>> est trop fort:
il suffit que E extends Comparable<T> pour T égal à E
ou T superclasse de E
(si E extends Comparable<Object> a fortiori on peut
comparer les éléments de E)
<E extends Comparable<? super E>>
POO-L3 H. Fauconnier
143
Mais attention
File<?> str=new File<String>();
str.enfiler("un");
provoque une erreur à la compilation:
enfiler(capture of ?) in generique.File<capture of ?>
cannot be applied to (java.lang.String)
de même:
File<? extends Number> num=new File<Number>();
num.enfiler(Integer.valueOf(12));
en effet File<? extends Number> peut être par exemple une File
d'un type dérivé de Number.
Par contre:
File<? super Number> num=new File<Number>();
num.enfiler(Integer.valueOf(12));
est correct
POO-L3 H. Fauconnier
144
Joker '?'
enfiler(capture of ?) in generique.File<capture of
?> cannot be applied to (java.lang.String)

signifie que le type de str est
File<capture of ?> qui n'est pas
compatible avec String
POO-L3 H. Fauconnier
145
Quelques explications



? peut correspondre à n'importe quel type
enfiler(a) où a est de type A ne peut
fonctionner si le type correspondant à ? est
dérivé de A
de même ? dans <? extends X> ne peut
fonctionner car si ? est Y dérivé de X il faut
un paramètre d'une classe dérivée de Y
par contre ? dans <? super X> ne pouvant
correspondre qu'à une classe "avant" X, tout
Z dérivé de X fonctionne
POO-L3 H. Fauconnier
146
Mais

inversement pour la valeur retournée
(avec la méthode défiler par exemple)



pour <?> quelque soit le type X
correspondant on peut l'affecter à Object
et à X
idem pour <? extends X>
mais pour <? super Y> si Z correspond à ?
pour T un type quelconque on ne peut
savoir si T peut être affecté par un Z
POO-L3 H. Fauconnier
147
Chapitre VII
1.
2.
3.
4.
Principes généraux
Types génériques imbriqués
Types paramètres bornés
Méthodes génériques
POO-L3 H. Fauconnier
148
Méthodes génériques

Supposons que l'on veuille convertir en
tableau une File de E


on a vu précédemment que l'on ne pouvait
ni instancier un objet E ni créer un tableau
de E
on peut cependant passer un tableau de la
taille appropriée à une méthode qui
retourne ce tableau:
POO-L3 H. Fauconnier
149
enTableau1
public E[] enTableau1(E[] tab){
int i=0;
for(Cellule<E> c= tete; c != null && i<
tab.length;
c=c.getSuivant())
tab[i++] = c.getElement();
return tab;
}

enTableau1 est une nouvelle méthode de File:
File<String> fs=new File<String>();
String[] u;
u=fs.enTableau1(new String[fs.getTaille()]);
POO-L3 H. Fauconnier
150
enTableau

Mais,


il faut que le tableau passé en paramètre
soit un tableau de E, alors qu'un tableau
d'une super-classe de E devrait
fonctionner (si F est une superclasse de E
un tableau de F peut contenir des objets
E).
avec une méthode générique:
POO-L3 H. Fauconnier
151
enTableau
public <T> T[] enTableau(T[] tab){
Object[] tmp = tab;
int i=0;
for(Cellule<E> c= tete; c != null && i< tab.length;
c=c.getSuivant())
tmp[i++] = c.getElement();
return tab;
}




la déclaration impose que le type du tableau retourné soit du
type du tableau de l'argument
Notons que tmp est un tableau d'Object ce qui est nécessaire
pour le getSuivant
Notons que normalement il faudrait que T soit une superclasse
de E (à l'exécution il peut y avoir une erreur).
Notons enfin que 'T' ne sert pas dans le corps de la méthode.
POO-L3 H. Fauconnier
152
Remarque
public <T> T[] enTableaubis(T[] tab){
int i=0;
for(Cellule<E> c= tete;
c != null && i< tab.length;
c=c.getSuivant())
tab[i++] = (T)c.getElement();
return tab;
}


provoque un warning "Cellule.java uses unchecked
or unsafe operations".
(l'"effacement" ne permet pas de vérifier le
type)
POO-L3 H. Fauconnier
153
Avec Reflection…

Une autre solution peut être si on veut
créer un vrai tableau est d'utiliser
Array.newInstance de la classe:
java.lang.reflect
POO-L3 H. Fauconnier
154
Exemple avec Reflection
public E[] enTableau2(Class<E> type){
int taille = getTaille();
E[] arr=(E[])Array.newInstance(type,taille);
int i=0;
for(Cellule<E> c= tete; c != null && i< taille;
c=c.getSuivant())
arr[i++] = c.getElement();
return arr;
}



on crée ainsi un tableau de "E"
"unchecked warning": le cast (E[]) n'a pas le sens usuel
pour fs déclaré comme précédemment on aura:
String[] u=fs.enTableau2(String.class); //ok
Object[] v=fs.enTableau2(Object.class); //non

(car fs est un File<String> et que la type doit être exact)
POO-L3 H. Fauconnier
155
Avec une méthode générique
public <T> T[] enTableau3(Class<T> type){
int taille = getTaille();
T[] arr=(T[])Array.newInstance(type,taille);
int i=0;
Object[] tmp=arr;
for(Cellule<E> c= tete; c != null && i< taille;
c=c.getSuivant())
tmp[i++] = c.getElement();
return arr;
}
POO-L3 H. Fauconnier
157
Inférence de type


Comment invoquer une méthode
générique?
Exemple:
static <T> T identite(T obj){
return obj;
}
POO-L3 H. Fauconnier
158
Invocations

On peut explicitement préciser le type:
String s1="Bonjour";
String s2= Main.<String>identite(s1);

Mais le compilateur peut trouver le type le
plus spécifique:
String s1=identite("Bonjour");

On aura:
Object o1=identite(s1);
//ok
Object o2=identite((Object)s1); //ok
s2=identite((Object s1);
//non!!!
s2=(String)identite((Object) s1);//ok
POO-L3 H. Fauconnier
159
Comment ça marche?



Mécanisme de l'effacement ("erasure")
Pour chaque type générique il n'y a qu'une classe:
Cellule<String> et Cellule<Integer> ont la même classe
Effacement:

Cellule<String> -> Cellule


Pour une variable type:



Cellule est un type brut
<E> -> Object
<E extends Number> -> Number
Le compilateur remplace chaque variable type par son
effacement
POO-L3 H. Fauconnier
160
Comment ça marche?

Si le résultat de l'effacement du
générique ne correspond pas à la
variable type, le compilateur génère un
cast:


par effacement le type variable de File<E>
est Object
pour un "defiler" sur un objet File<String>
le compilateur insère un cast sur String
POO-L3 H. Fauconnier
161
Comment ça marche?

A cause de l'effacement, rien de ce qui
nécessite de connaître la valeur d'un
argument type n'est autorisé. Par exemple:



on ne peut pas instancier un paramètre type: pas
de new T() ou de new T[]
on ne peut pas utiliser instanceof pour une
instance de type paramétrée
on ne peut pas créer de tableau sur un type
paramétré sauf s'il est non borné new
List<String>[10] est interdit mais new
List<?>[10] est possible.
POO-L3 H. Fauconnier
162
Comment ça marche?

les cast sont possibles mais n'ont pas la
même signification que pour les types non
paramétrés:


le cast est remplacé par un cast vers le type
obtenu par effacement et génère un "unchecked
warning" à la compilation.
Exemple:


on peut caster paramètre File<?> vers un File<String>
pour un enfiler (ce qui génère le warning)
A l'exécution si le type effectif est File<Number> cela
passe… mais le defiler provoquera un
ClassCastException.
POO-L3 H. Fauconnier
163
Comment ça marche?

Exemple:
List<String> l=new ArrayList<String>();
Object o=identite(l);
List<String> l1=(List<String>)o;// warning
List<String> l2=(List)o;//warning
List<?> l3=(List) o; //ok
List<?> l4=(List<?>)o; //ok
POO-L3 H. Fauconnier
164
Application: surcharge



avoir la même signature s'étend aux
méthodes avec variables types
même signature pour des variables
types = même type et même borne
(modulo bien sûr renommage!)
signatures équivalentes par annulation:
mêmes signatures où l'effacement des
signatures sont identiques
POO-L3 H. Fauconnier
165
Surcharge
class Base<T>{
void m(int x){};
void m(T t){};
void m(String s){};
<N extends Number> void m(N n){};
void m(File<?> q){};
}
----m(int)
m(Object)
m(String)
m(Number)
m(File)
POO-L3 H. Fauconnier
166
Et héritage…

exemple:
class D<T> extends Base<T>{
void m(Integer i){} //nouveau
void m(Object t){} // redéfinit m(T t)
void m(Number n){}
// redéfinit m(N n)
}
POO-L3 H. Fauconnier
167
Chapitre VIII
Strings,
Plan




A) String
B) Expressions régulières
C) Chaînes et tableaux (char et byte)
D) Chaînes modifiables
POO-L3 H. Fauconnier
169
String

Une String est une chaîne de caractères
non modifiable



(attention les caractères en java sont en Unicode)
StringBuilder et StringBuffer sont des
classes de chaînes qui peuvent être
modifiées.
String StringBuilder et StringBuffer
implémentent l'interface CharSequence
POO-L3 H. Fauconnier
170
CharSequence

Interface:




char charAt(int index)
Retourne le char the char en position
index.
int length()
Retourne la longueur de la séquence.
CharSequence subSequence(int start, int end)
Retourne une sous CharSequence
String toString()
Retourne la string correspondant à la
séquence
POO-L3 H. Fauconnier
171
String

De nombreuses méthodes pour manipuler les
chaines (attention un objet String n'est pas
modifiable)






constructeurs
indexOf, lastIndexOf retourne la première
(dernière) position
conversion valueOf( valeur d'un type primitif)
replace, trim, split
toLowerCase, toupperCase()
…
POO-L3 H. Fauconnier
172
Comparaison

'==' ne compare les contenus, MAIS
deux littéraux ayant le même contenu
sont identiques:
String st1="bonjour";
String st2="bonjour"
if(st1==st2)System.out.println("égal");
else System.out.println("différent");
donnera égal
La méthode intern permet de retourner un
String de même référence
POO-L3 H. Fauconnier
173
Manipulations sur les chaînes











char charAt(int index)
int compareTo(String anotherString) comparaison
lexicographique
boolean contains(CharSequence s)
boolean equals(Object anObject)
int length()
boolean matches(String regex)
boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len)
boolean regionMatches(boolean ignoreCase, int toffset,
String other, int ooffset, int len)
String replace(CharSequence target,
CharSequence replacement)
String[] split(String regex)
String trim()
POO-L3 H. Fauconnier
174
Exemples
String string = "Madam, I am Adam";
boolean b = string.startsWith("Mad");
b = string.endsWith("dam");
b = string.indexOf("I am") > 0;
b = string.matches("(?i)mad.*");
b = string.matches("(?i).*adam");
b = string.matches("(?i).*i am.*");
POO-L3 H. Fauconnier
// true
// true
// true
175
Exemple: remplacement
static String replace(String str, String pattern,
String replace) {
int s = 0;
int e = 0;
StringBuffer result = new StringBuffer();
while ((e = str.indexOf(pattern, s)) >= 0) {
result.append(str.substring(s, e));
result.append(replace);
s = e+pattern.length();
}
result.append(str.substring(s));
return result.toString();
}
POO-L3 H. Fauconnier
176
Exemple
Strinf st1="bonjour";
String st3=new String("bonjour");
if(st1==st3)System.out.println("égal");
else System.out.println("différent");
String st4=st3.intern();
if(st1==st4)System.out.println("égal");
else System.out.println("différent");
(la comparaison des références est bien sûr moins
coûteuse que la comparaison des contenus)
(de plus dans tous les cas des chaînes de même contenus
ont le même hashcode)
POO-L3 H. Fauconnier
177
Expressions régulières


Les expressions régulières permettent
de définir un motif (pattern) objet de
la classe Pattern.
Un motif est créé par la méthode
compile

Pattern pat = Pattern.compile("[a-z]*")
POO-L3 H. Fauconnier
178
Expressions régulières

la syntaxe des expressions régulières (rationnelles) est assez
large:







caractères

exemples \t , a ,\xhh ,

exemples [a-z], [^a-z], [a-z&&0-9]

exemples . , \d, \D, \w, \W, \s, \S

exemples \p{Blank}, \p{javaLowerCase}

exemples ^, $,\b (bord d'un mot)

exemples [a-z]?, [1-9][0-9]+, \W*,
classes de caractères
classes de caractères prédéfinis
classes prédéfinies ASCII, Character
bords
itérations
capture et restitution


(X) définit la capture de X
\n correspond à la n-ième capture
POO-L3 H. Fauconnier
179
Recherche de motif

Principe:
Pattern pat=Pattern.compile(regex);
Matcher matcher=pat.match(entrée);
boolean trouve = matcher.find();
la classe Matcher contient les méthodes pour
chercher (find()), retourner la sousséquence trouvée (group())
POO-L3 H. Fauconnier
180
Exemple: rechercher
String patternStr = "b";
Pattern pattern = Pattern.compile(patternStr);
CharSequence inputStr = "a b c b";
Matcher matcher = pattern.matcher(inputStr);
boolean matchFound = matcher.find();
// true
String match = matcher.group();
// b
int start = matcher.start();
// 2
int end = matcher.end();
// 3
matchFound = matcher.find();
// true
POO-L3 H. Fauconnier
181
Remplacer
CharSequence inputStr = "ab12 cd efg34";
String patternStr = "([a-zA-Z]+[0-9]+)";
Pattern pattern = Pattern.compile(patternStr);
Matcher matcher = pattern.matcher(inputStr);
// Remplacer toutes les occurrences
StringBuffer buf = new StringBuffer();
boolean found = false;
while ((found = matcher.find())) {
String replaceStr = matcher.group();
replaceStr = replaceStr.toUpperCase();
matcher.appendReplacement(buf, replaceStr);
}
matcher.appendTail(buf);
String result = buf.toString();
// AB12 cd EFG34
POO-L3 H. Fauconnier
182
Chaines et tableaux de char


Une string n'est pas un tableau de char
mais on peut passer de l'un à l'autre
constructeurs
String(char[] value)
String(char[] value, int offset, int count)

méthode:
void getChars(int srcBegin, int srcEnd,
char[] dst, int dstBegin)
POO-L3 H. Fauconnier
183
Chaînes et tableaux de byte




les chaines contiennent des caractères
codés en UTF-16.
On peut convertir ces caractères en
byte suivant un codage
De même on peut coder des bytes en
caractères unicode.
(par exemple un byte Latin-1 se code en
Unicode en ajoutant un octet de 0)
POO-L3 H. Fauconnier
184
Charset

la classe Charset permet de faire
correspondre des séquences d'unicode
et des bytes. En standard:






US-ASCII
ISO-8859-1
UTF-8
UTF-16BE
UTF-16LE
UTF-16
POO-L3 H. Fauconnier
185
tableau de byte

constructeurs:





String(byte[] bytes) (conversion suivant le jeu de
caractère par défaut)
String(byte[] bytes, int offset, int length)
String(byte[] bytes, String charsetName)
(suivant le charset)
String(byte[] bytes, int offset, int length,
String charsetName) (suivant le charset)
méthodes


byte[]getBytes()
byte[]getBytes(String charsetName)
POO-L3 H. Fauconnier
186
Exemple:
try {
// Conversion Unicode en x-MacRoman
String string = "abcéçùà\u563b";
System.out.println(string);
byte[] mac = string.getBytes("x-MacRoman");
System.out.println(new String(mac));
// Conversion x-MacRoman vers Unicode
string = new String(utf8, "x-MacRoman");
System.out.println(string);
} catch (UnsupportedEncodingException e) {
}

abcéçùà?

abcŽ??ˆ?

abcéçùà?
POO-L3 H. Fauconnier
187
Exemples:
for(String nom: Charset.availableCharsets().keySet())
System.out.println(nom);
affichera la liste des jeux de caractères:

















EUC-JP
EUC-KR
GB18030
GB2312
GBK
IBM-Thai
IBM00858
IBM01140
IBM01141
IBM01142
IBM01143
IBM01144
IBM01145
IBM01146
IBM01147
IBM01148
…
POO-L3 H. Fauconnier
188
Exemple
Charset charset = Charset.forName("ISO-8859-1");
CharsetDecoder decoder = charset.newDecoder();
CharsetEncoder encoder = charset.newEncoder();
try {
// Convertit une string vers ISO-LATIN-1
ByteBuffer bbuf =
encoder.encode(CharBuffer.wrap("une chaîne"));
// Convertit ISO-LATIN-1 bytes en string.
CharBuffer cbuf = decoder.decode(bbuf);
String s = cbuf.toString();
} catch (CharacterCodingException e) {
}
POO-L3 H. Fauconnier
189
Exemple:
try {
// Conversion vers ISO-LATIN-1 de bytes
ByteBuffer bbuf =
encoder.encode(CharBuffer.wrap("une chaîne"));
// Conversion de ISO-LATIN-1 vers bytes
CharBuffer cbuf = decoder.decode(bbuf);
String s = cbuf.toString();
System.out.println(s);
} catch (CharacterCodingException e) {
}
POO-L3 H. Fauconnier
190
StringBuilder





La classe StringBuilder peut contenir des
chaînes qui peuvent être modifiées.
Il s'agit d'une structure de données
dynamique: la taille de la chaîne est
augmentée automatiquement
La taille initiale peut être précisée dans le
constructeur (16 par défaut).
(Il existe aussi une classe StringBuffer qui
est "thread-safe")
méthodes insert, append, delete
POO-L3 H. Fauconnier
191
Chapitre IX
Entrées-sorties
Principes généraux

entrées sorties




streams dans java.io
channels dans java.nio ("n" pour non-blocking)
streams: séquences de données ordonnées
avec une source (stream d'entrée) ou un
destination (stream de sortie)
channels et buffer. Buffer contient les
données et le channel correspond à des
connections
POO-L3 H. Fauconnier
193
Streams

Deux grandes sortes de Stream



character Streams contiennet des
caractères UTF-16
byte Streams contiennent des octets
Character versus byte



imput ou output stream pour les byte
reader, writer pour les character
deux hiérarchies qui se correspondent
POO-L3 H. Fauconnier
194
Hiérarchie

java.io.InputStream (implements java.io.Closeable)



java.io.ByteArrayInputStream
java.io.FileInputStream
java.io.FilterInputStream








java.io.BufferedInputStream
java.io.DataInputStream (implements java.io.DataInput)
java.io.LineNumberInputStream
java.io.PushbackInputStream
java.io.ObjectInputStream (implements
java.io.ObjectInput, java.io.ObjectStreamConstants)
java.io.PipedInputStream
java.io.SequenceInputStream
java.io.StringBufferInputStream
POO-L3 H. Fauconnier
195
Hiérarchie

java.io.OutputStream (implements java.io.Closeable,
java.io.Flushable)



java.io.ByteArrayOutputStream
java.io.FileOutputStream
java.io.FilterOutputStream





java.io.BufferedOutputStream
java.io.DataOutputStream (implements java.io.DataOutput)
java.io.PrintStream (implements java.lang.Appendable,
java.io.Closeable)
java.io.ObjectOutputStream (implements
java.io.ObjectOutput, java.io.ObjectStreamConstants)
java.io.PipedOutputStream
POO-L3 H. Fauconnier
196
Hiérachie…

java.io.Reader (implements java.io.Closeable,
java.lang.Readable)

java.io.BufferedReader



java.io.CharArrayReader
java.io.FilterReader



java.io.PushbackReader
java.io.InputStreamReader


java.io.LineNumberReader
java.io.FileReader
java.io.PipedReader
java.io.StringReader
POO-L3 H. Fauconnier
197
Hiérarchie

java.io.Writer (implements java.lang.Appendable,
java.io.Closeable, java.io.Flushable)




java.io.BufferedWriter
java.io.CharArrayWriter
java.io.FilterWriter
java.io.OutputStreamWriter




java.io.FileWriter
java.io.PipedWriter
java.io.PrintWriter
java.io.StringWriter
POO-L3 H. Fauconnier
198
Streams d'octets

Class InputStream
(toutes ces méthodes peuvent lancer IOEXception)
 abstract int read() lit un octet
 int read (byte[] b) lit et écrit dans b, (le nombre
d'octets lus dépend de b et est retourné

int read(byte[] b, int off, int len)

long skip(long n)
 int available() n d'octets pouvant être lus

void mark(int readlimit) et void reset() pose
d'une marque et retour à la marque
 voidclose()
POO-L3 H. Fauconnier
199
Stream d'octets

OutputStream
(toutes ces méthodes peuvent lancer
IOEXception)





abstract void write(int b) écrit un octet
void write(byte[] b)
void write(byte[] b, int off, int len)
voidclose()
voidflush()
POO-L3 H. Fauconnier
200
Exemples
public static int compteIS(String st)
throws IOException{
InputStream in;
int n=0;
if (st==null)in=System.in;
else
in= new FileInputStream(st);
for(; in.read() != -1;n++);
return n;
}
POO-L3 H. Fauconnier
201
Exemples
public static void trOS(String f, char from, char to){
int b;
OutputStream out=null;
if(f==null) out=System.out;
else
try{
out=new FileOutputStream(f);
while((b= System.in.read())!=-1)
out.write(b==from? to:b);
out.flush();
out.close();
}catch(IOException ex){
ex.printStackTrace();
}
}
POO-L3 H. Fauconnier
202
Reader-Writer

Reader et Writer sont els deux classes
abstraites pour les streams de
carctères:

le read de InputStream retourne un byte
comme octet de poids faible d'un int alors
que le read deReader retourne un char à
partir de 2 octetes de poids faible d'un int
POO-L3 H. Fauconnier
203
Reader

essentiellement les mêmes méthodes que pour
InputStream:









int read()
int read(char[] cbuf)
abstract int read(char[] cbuf, int off, int len)
int read(CharBuffer target)
boolean ready() si prêt à lire
voidreset()
voidmark(int readAheadLimit)
booleanmarkSupported()
longskip(long n)
POO-L3 H. Fauconnier
204
Writer

similaire à OutputStream mais avec des caractères
au lieu d'octets.











void write(char[] cbuf)
abstract void write(char[] cbuf, int off, int len)
void write(int c)
void write(int c)
void write(String str)
void write(String str, int off, int len)
Writer append(char c)
Writer append(CharSequence csq)
Writer append(CharSequence csq, int start, int end)
abstract void close()
abstract void flush()
POO-L3 H. Fauconnier
205
Exemples
public static int compteR(String st)
throws IOException{
Reader in;
int n=0;
if (st==null)
in=new InputStreamReader(System.in);
else
in= new FileReader(st);
for(; in.read() != -1;n++);
return n;
}
POO-L3 H. Fauconnier
206
Exemples
public static void trWr(String f, char from, char to){
int b;
Writer out=null;
if(f==null)
out= new OutputStreamWriter(System.out);
else
try {
out=new FileWriter(f);
while((b= System.in.read())!=-1)
out.write(b==from? to:b);
out.flush();
out.close();
}catch(IOException e){System.out.println(e);}
}
POO-L3 H. Fauconnier
207
Remarques



les streams standard System.in et
System.out sont des streams d'octets
InputStreamReader permet de passer
de InoutStream à Reader
System.in et System.out sont des
PrintStream (obsolète à remplacer par
la version caractère PrintWriter)
POO-L3 H. Fauconnier
208
InputStreamReader et
OutputStreamWriter


conversion entre caractères et octets, la conversion
est donnée par un charset
Constructeurs:







InputStreamReader(InputStream in)
InputStreamReader(InputStream in, Charset cs)
InputStreamReader(InputStream in, String charsetName)
OutputStreamWriter(OutputStream out)
OutputStreamWriter(OutputStream out, Charset cs)
OutputStreamWriter(OutputStream out,
CharsetEncoder enc)
OutputStreamWriter(OutputStream out,
String charsetName)
POO-L3 H. Fauconnier
209
Autres classes





FileInputStream
FileOutputStream
FileReader
FileWriter
Ces classes permettent d'associer une
stream à un fichier donné par son nom
(String) par un objet File ou un objet
FileDescriptor (un mode append peut être
défini pour les ecritures)
POO-L3 H. Fauconnier
210
Quelques autres classes

Les filtres





Buffered





FilterInputStream
FilterOutputStream
FilterReader
FilterWriter
BufferedInputStream
BufferedOutputStream
BufferedReader
BufferedWriter
Tubes




PipedInputStream
PipedOutputStream
PipedReader
PipedWriter
POO-L3 H. Fauconnier
211
Exemple d'un filtre
class conversionMaj extends FilterReader{
public conversionMaj(Reader in){
super(in);
}
public int read() throws IOException{
int c=super.read();
return(c==-1?c:Character.toUpperCase((char)c));
}
public int read(char[] buf, int offset, int count)throws
IOException{
int nread=super.read(buf,offset,count);
int last=offset+nread;
for(int i=offset; i<last;i++)
buf[i] = Character.toUpperCase(buf[i]);
return nread;
}
}
POO-L3 H. Fauconnier
212
Exemple suite:
StringReader source=new StringReader("ma chaîne");
FilterReader filtre=new conversionMaj(source);
int c;
try{
while((c=filtre.read())!= -1)
System.out.print((char)c);
}catch(IOException e){
e.printStackTrace(System.err);
}
POO-L3 H. Fauconnier
213
Pipe (tube)

Un tube associe une entrée et un
sortie: on lit à une extrémité et on
écrit à l'autre.
POO-L3 H. Fauconnier
214
Exemple pipe
class PipeExemple extends Thread{
private Writer out;
private Reader in;
public PipeExemple(Writer out,Reader in){
this.out=out;
this.in=in;
}
public void run(){
int c;
try{
try{
while ((c=in.read())!=-1){
out.write(Character.toUpperCase((char)c));
}
}finally{out.close();}
}catch(IOException e){e.printStackTrace(System.err);}
}
}
POO-L3 H. Fauconnier
215
Suite
PipedWriter out1=new PipedWriter();
PipedReader in1=new PipedReader(out1);
PipedWriter out2=new PipedWriter();
PipedReader in2=new PipedReader(out2);
PipeExemple pipe=new PipeExemple(out1, in2);
pipe.start();
try{
for(char c='a';c<='z';c++) {
out2.write(c);
System.out.print((char)(in1.read()));
}
}finally {
out2.close();
}
POO-L3 H. Fauconnier
216
ByteArray, String…

java.io.InputStream (implements java.io.Closeable)

java.io.ByteArrayInputStream
java.io.StringBufferInputStream

java.io.ByteArrayOutputStream



java.io.OutputStream (implements java.io.Closeable,
java.io.Flushable)
java.io.Reader (implements java.io.Closeable, java.lang.Readable)



java.io.CharArrayReader
java.io.StringReader
java.io.Writer (implements java.lang.Appendable,
java.io.Closeable, java.io.Flushable)


java.io.CharArrayWriter
java.io.StringWriter
POO-L3 H. Fauconnier
217
Print Streams


java.io.PrintStream (implements
java.lang.Appendable, java.io.Closeable)
java.io.PrintWriter

méthode println()
POO-L3 H. Fauconnier
218
Streams pour les données


DataInput: interface pour lire des
bytes d'une stream binaire et les
transformer en données java de type
primitif
DataOutput: interface pour convertir
des valeurs de type primitif en stream
binaire.
POO-L3 H. Fauconnier
219
Sérialisation

sauvegarder des objets java en flot d'octets:

objet vers byte: sérialisation
 byte vers objet: désérialisation
java.io.ObjectInputStream (implements
java.io.ObjectInput, java.io.ObjectStreamConstants)
java.io.ObjectInputStream (implements
java.io.ObjectInput, java.io.ObjectStreamConstants)


POO-L3 H. Fauconnier
220
Sauver des objets




la serialisation-désérialisation doit
permettre de sauvegarder et restituer
des objets.
sauver et restituer des objets n'est
pas si simple. Pourquoi?
interface serializable
(alternative XML)
POO-L3 H. Fauconnier
221
Manipuler des fichiers…

java.io.File (implements
java.lang.Comparable<T>,
java.io.Serializable)
POO-L3 H. Fauconnier
222
nio

entrée sorties de haute performance
avec contrôle sur les buffers.
POO-L3 H. Fauconnier
223
Collections
Collections

types de données




interfaces
implémentations
algorithmes
Interfaces:
POO-L3 H. Fauconnier
225
Collections: les interfaces








Collection<E>: add remove size toArray…
Set<E>: sans duplication
List<E>: des listes éléments non ordonnés et avec
duplication
Queue<E>: avec tête: peek, poll (défiler), offer
(enfiler)
Map<K,V>:association clés valeurs
SortedMap<K,V> avec clés triées
Iterator<E>: interface qui retourne successivement
les éléments next(), hasNext(), remove()
ListIterator<E>: itérateur pour des List, set(E)
previous, add(E)
POO-L3 H. Fauconnier
226
Des implémentations








HashSet<E>: implémentation deSet comme table de hachage.
Recherche ajout suppression en temps constant
TreeSet<E>: SortedSet comme arbre binaire équilibré O(log(n))
ArrayList<E>: liste implémentée par des tableaux à taille
variable accès en O(1) ajout et suppression enO(n-i) (i position
considérée)
LinkedList<E>: liste doublement chaînée implémente List et
Queue accès en O(i)
HashMap<K,V>: implémentation de Map pas table de hachage
ajout suppression et recherche en O(1)
TreeMap<K,V>: implémentation de SortedMap à partir d'arbres
équilibrésajout, suppression et recherche en O(log(n))
WeakHashMap<K,V>: implémentation de Map par table de
hachage
PriorityQueue<E>: tas à priorité.
POO-L3 H. Fauconnier
227
Comparaisons

Interface Comparable<T> contient la
méthode



public int compareTo(T e)
"ordre naturel"
Interface Comparator<T> contient la
méthode

public int compare(T o1, T o2)
POO-L3 H. Fauconnier
228
Quelques autres packages

System méthodes static pour le
système:



entrée-sorties standard
manipulation des propriétés systèmes
utilitaires "Runtime" exit(), gc() …
POO-L3 H. Fauconnier
229
Runtime, Process


Runtime permet de créer des processus
pour exécuter des commande: exec
Process retourné par un exec méthodes





destroy()
exitValue()
getInputStream()
getOutputStream()
getErrorStream()
POO-L3 H. Fauconnier
230
Exemple

exécuter une commande (du système
local)


associer l'entrée de la commande sur
System.in
associer la sortie sur System.out.
POO-L3 H. Fauconnier
231
Exemple
class plugTogether extends Thread {
InputStream from;
OutputStream to;
plugTogether(OutputStream to, InputStream from ) {
this.from = from; this.to = to;
}
public void run() {
byte b;
try {
while ((b= (byte) from.read()) != -1) to.write(b);
} catch (IOException e) {
System.out.println(e);
} finally {
try {
to.close();
from.close();
} catch (IOException e) {
System.out.println(e);
}
}
}
POO-L3 H. Fauconnier
}
232
Exemple suite
public class Main {
public static Process userProg(String cmd)
throws IOException {
Process proc = Runtime.getRuntime().exec(cmd);
Thread thread1 = new plugTogether(proc.getOutputStream(),
System.in);
Thread thread2 = new plugTogether(System.out,
proc.getInputStream());
Thread thread3 = new plugTogether(System.err,
proc.getErrorStream());
thread1.start(); thread2.start(); thread3.start();
try {proc.waitFor();} catch (InterruptedException e) {}
return proc;
}
public static void main(String args[])
throws IOException {
String cmd = args[0];
System.out.println("Execution de: "+cmd);
Process proc = userProg(cmd);
}
}
POO-L3 H. Fauconnier
233
Chapitre X
threads
Threads

threads: plusieurs activités qui coexistent et
partagent des données

exemples:




pendant un chargement long faire autre chose
coopérer
processus versus threads
problème de l'accès aux ressources partagées



verrous
moniteur
synchronisation
POO-L3 H. Fauconnier
235
Principes de base

extension de la classe Thread





méthode run est le code qui sera exécuté.
la création d'un objet dont la superclasse est
Thread crée la thread (mais ne la démarre pas)
la méthode start démarre la thread (et retourne
immédiatement)
la méthode join permet d'attendre la fin de la
thread
les exécutions des threads sont asynchrones et
concurrentes
POO-L3 H. Fauconnier
236
Exemple
class ThreadAffiche extends Thread{
private String mot;
private int delay;
public ThreadAffiche(String w,int duree){
mot=w;
delay=duree;
}
public void run(){
try{
for(;;){
System.out.println(mot);
Thread.sleep(delay);
}
}catch(InterruptedException e){
}
}
}
POO-L3 H. Fauconnier
237
Suite
public static void main(String[] args) {
new ThreadAffiche("PING", 10).start();
new ThreadAffiche("PONG", 30).start();
new ThreadAffiche("Splash!",60).start();
}
POO-L3 H. Fauconnier
238
Alternative: Runnable

Une autre solution:


créer une classe qui implémente
l'interface Runnable (cette interface
contient la méthode run)
créer une Thread à partir du constructeur
Thread avec un Runnable comme
argument.
POO-L3 H. Fauconnier
239
Exemple
class RunnableAffiche implements Runnable{
private String mot;
private int delay;
public RunnableAffiche(String w,int duree){
mot=w;
delay=duree;
}
public void run(){
try{
for(;;){
System.out.println(mot);
Thread.sleep(delay);
}
}catch(InterruptedException e){
}
}
}
POO-L3 H. Fauconnier
240
Suite
public static void main(String[] args) {
Runnable ping=new RunnableAffiche("PING", 10);
Runnable pong=new RunnableAffiche("PONG", 50);
new Thread(ping).start();
new Thread(pong).start();
}
POO-L3 H. Fauconnier
241
Synchronisation

les threads s'exécutent
concurremment et peuvent accéder
concurremment à des objets:

il faut contrôler l'accès:




thread un lit une variable (R1) puis modifie cette
variable (W1)
thread deux lit la même variable (R2) puis la modifie
(W2)
R1-R2-W2-W1
R1-W1-R2-W2 résultat différent!
POO-L3 H. Fauconnier
242
Exemple
class X{
int val;
}
class Concur extends Thread{
X x;
int i;
String nom;
public Concur(String st, X x){
nom=st;
this.x=x;
}
public void run(){
i=x.val;
System.out.println("thread:"+nom+" valeur x="+i);
try{
Thread.sleep(10);
}catch(Exception e){}
x.val=i+1;
System.out.println("thread:"+nom+" valeur x="+x.val);
}
}
POO-L3 H. Fauconnier
243
Suite
public static void main(String[] args) {
X x=new X();
Thread un=new Concur("un",x);
Thread deux=new Concur("deux",x);
un.start(); deux.start();
try{
un.join();
deux.join();
}catch (InterruptedException e){}
System.out.println("X="+x.val);
}
donnera (par exemple)

thread:un valeur x=0

thread:deux valeur x=0

thread:un valeur x=1

thread:deux valeur x=1

X=1
POO-L3 H. Fauconnier
244
Deuxième exemple
class Y{
int val=0;
public int increment(){
int tmp=val;
tmp++;
try{
Thread.currentThread().sleep(100);
}catch(Exception e){}
val=tmp;
return(tmp);
}
int getVal(){return val;}
}
class Concur1 extends Thread{
Y y;
String nom;
public Concur1(String st, Y y){
nom=st;
this.y=y;
}
public void run(){
System.out.println("thread:"+nom+" valeur="+y.increment());
}
}
POO-L3 H. Fauconnier
245
Suite
public static void main(String[] args) {
Y y=new Y();
Thread un=new Concur1("un",y);
Thread deux=new Concur1("deux",y);
un.start(); deux.start();
try{
un.join();
deux.join();
}catch (InterruptedException e){}
System.out.println("Y="+y.getVal());
}
----------


thread:un valeur=1
thread:deux valeur=1
Y=1
POO-L3 H. Fauconnier
246
Verrous

à chaque objet est associé un verrou

synchronized(expr) {instructions}



expr doit s'évaluer comme une référence à un
objet
verrou sur cet objet pour la durée de
l'exécution de instructions
déclarer les méthodes comme
synchronized: la thread obtient le verrou
et le relâche quand la méthode se termine
POO-L3 H. Fauconnier
247
synchronised(x)
class Concur extends Thread{
X x;
int i;
String nom;
public Concur(String st, X x){
nom=st;
this.x=x;
}
public void run(){
synchronized(x){
i=x.val;
System.out.println("thread:"+nom+" valeur x="+i);
try{
Thread.sleep(10);
}catch(Exception e){}
x.val=i+1;
System.out.println("thread:"+nom+" valeur x="+x.val);
}
}
}
POO-L3 H. Fauconnier
248
Méthode synchronisée
class Y{
int val=0;
public synchronized int increment(){
int tmp=val;
tmp++;
try{
Thread.currentThread().sleep(100);
}catch(Exception e){}
val=tmp;
return(tmp);
}
int getVal(){return val;}
}
-----------


thread:un valeur=1
thread:deux valeur=2
Y=2
POO-L3 H. Fauconnier
249
Mais…

la synchronisation par des verrous peut
entraîner un blocage:




la thread un (XA) pose un verrou sur l'objet A et
(YB) demande un verrou sur l'objet B
la thread deux (XB) pose un verrou sur l'objet B
et (YA) demande un verrou sur l'objet A
si XA –XB : ni YA ni YB ne peuvent êter
satisfaites -> blocage
(pour une méthode synchronisée, le verrou
concerne l'objet globalement et pas
seulement la méthode)
POO-L3 H. Fauconnier
250
Exemple
class Dead{
Dead partenaire;
String nom;
public Dead(String st){
nom=st;
}
public synchronized void f(){
try{
Thread.currentThread().sleep(100);
}catch(Exception e){}
System.out.println(Thread.currentThread().getName()+
" de "+ nom+".f() invoque "+ partenaire.nom+".g()");
partenaire.g();
}
public synchronized void g(){
System.out.println(Thread.currentThread().getName()+
" de "+ nom+".g()");
}
public void setPartenaire(Dead d){
partenaire=d;
}
}
POO-L3 H. Fauconnier
251
Exemple (suite)
final Dead un=new Dead("un");
final Dead deux= new Dead("deux");
un.setPartenaire(deux);
deux.setPartenaire(un);
new Thread(new Runnable(){public void run(){un.f();}
},"T1").start();
new Thread(new Runnable(){public void run(){deux.f();}
},"T2").start();
------------


T1 de un.f() invoque deux.g()
T2 de deux.f() invoque un.g()
POO-L3 H. Fauconnier
252
Synchronisation…

wait, notifyAll notify

attendre une condition / notifier le
changement de condition:
synchronized void fairesurcondition(){
while(!condition)
wait();
faire ce qu'il faut qaund la condition est vraie
}
----------------synchronized void changercondition(){
… changer quelque chose concernant la condition
notifyAll(); // ou notify()
}
POO-L3 H. Fauconnier
253
Exemple (file: rappel Cellule)
public class Cellule<E>{
private Cellule<E> suivant;
private E element;
public Cellule(E val) {
this.element=val;
}
public Cellule(E val, Cellule suivant){
this.element=val;
this.suivant=suivant;
}
public E getElement(){
return element;
}
public void setElement(E v){
element=v;
}
public Cellule<E> getSuivant(){
return suivant;
}
public void setSuivant(Cellule<E> s){
this.suivant=s;
}
POO-L3 H. Fauconnier
254
File synchronisées
class File<E>{
protected Cellule<E> tete, queue;
private int taille=0;
public synchronized void enfiler(E item){
Cellule<E> c=new Cellule<E>(item);
if (queue==null)
tete=c;
else{
queue.setSuivant(c);
}
c.setSuivant(null);
queue = c;
notifyAll();
}
POO-L3 H. Fauconnier
255
File (suite)
public synchronized E defiler() throws InterruptedException{
while (tete == null)
wait();
Cellule<E> tmp=tete;
tete=tete.getSuivant();
if (tete == null) queue=null;
return tmp.getElement();
}
POO-L3 H. Fauconnier
256
Téléchargement