POO
Chapitre 6: Interface, classe abstraite et
classe générique
Mme Mouna JARRAYA
Ingénieur en Génie Logiciel
Docteur en Informatique
E-mail:
jarrayamouna@gmail.com
mouna.jarraya@insat.ucar.tn
1
Problème du diamant
3
L’héritage est un paradigme important de la programmation Orientée Objet.
Avec l’héritage multiple, se pose le problème du diamant (problème du
losange).
La classe D hérite de deux classes B et C, elles-mêmes
filles d’une même classe A.
Un problème de conflit se pose lorsque des méthodes ou
des attributs des classes B et C portent le même nom.
Problème du diamant
4
L’héritage est un paradigme important de la programmation Orientée Objet.
Avec l’héritage multiple, se pose le problème du diamant (problème du
losange).
La classe D hérite de deux classes B et C, elles-mêmes
filles d’une même classe A.
Un problème de conflit se pose lorsque des méthodes ou
des attributs des classes B et C portent le même nom.
Pour cela ce mécanisme n'existe pas en Java!!
Comment faire pour bien concevoir en java des cas réels basés sur
l’héritage multiple?
Interface
5
Interface, C’est quoi?
Une interface définit un comportement d’une classe, sans implémenter ce
comportement.
C’est un ensemble de méthodes abstraites, et de constantes.
Une interface ne peut pas être instanciée, elle ne peut être que implémentée
par des classes.
Une classe qui implémente une interface doit fournir le code approprié des
méthodes abstraites.
Une classe peut implémenter plusieurs interfaces
Une interface peut hériter de plusieurs autres interfaces
Interface
6
Interface, C’est quoi?
On peut déclarer des variables dont le type est une interface.
Une classe qui hérite d’une autre classe et qui implémente une interface:
Doit mettre dans l'ordre l'héritage (extends) puis l'implémentation
(implements)
// une interface est soit publique soit accèspaquetage(default)
interface interface_exemple [extends noms d'interfaces]{
// déclaration des constantes(public static final facultatifs)
int MAX=100;
// entête d’une méthode F (public abstact facultatifs)
int F(int n);
// entête d’une méthode g (public abstact facultatifs)
void g();
}
Syntaxe
Le corps d’une interface est une énumération de constantes et de
méthodes sans la définition de leurs codes.
Interface
7
Interface, C’est quoi?
public interface I1 {
void f ( );
}
public interface I2 {
int g (int);
}
public interface I3 extends I2 {
float h (int);
}
class A implements I1, I3 {
/* A doit obligatoirement implémenter les méthodes f, g et h prévues dans I1 et
I3 qui hérite de I2*/
}
Syntaxe d’implémentation: utilisation d’une interface par une classe
Interface
8
Exemple
class Entier implements Affichable
{
private int val ;
public Entier (int n) {
val = n ;}
public void affiche() {
System.out.println («Je suis un
entier de valeur » + val) ;}
}
class Flottant implements Affichable {
private float val ;
public Flottant (float n){
val = n ;}
public void affiche() {
System.out.println (« Je suis un
flottant de valeur » + val) ; }
}
interface Affichable {
void affiche() ;
}
Interface
9
Héritage d’interfaces
De la même manière qu’une classe peut avoir des sous-classes, une
interface peut avoir des « sous-interfaces »
Une sous interface:
• Hérite de toutes les méthodes abstraites et des constantes de sa
« super-interface »
• Peut définir de nouvelles constantes et méthodes abstraites
Interface Set extends Collection
{
...
}
Interface
10
Héritage d’interfaces
À la différence des classes, une interface peut étendre plus d’une interface
à la fois.
package java.nio;
Interface ByteChannel extends ReadableByteChanel,
WriteableByteChanel{
}
Interface
11
Interfaces-Méthodes par défaut (JAVA 8)
Déclaration d’une méthode par défaut
• Fournir un corps à la méthode
• Qualifier la méthode avec le mot clé default
Les classes filles sont libérées de fournir une implémentation d’une
méthode default, en cas d'absence d’implémentation spécifique c’est la
méthode par défaut qui est invoquée.
Ceci est utile si on veut ajouter ultérieurement une méthode
Ce mécanisme n'existe qu'à partir de Java 8. Jusqu'en
Java 7 il n'est pas possible de créer des méthodes par
défaut dans les interfaces.
Interface
13
Interfaces-Méthodes par défaut (JAVA 8)
Pour résoudre le conflit, il existe une seule solution:
Implémenter la méthode au niveau de la classe elle même, car
l'implémentation de la classe est toujours prioritaire.
Interface
14
Interfaces-Méthodes par défaut (JAVA 8)
Une méthode statique est un élément que l’on peut rencontrer dans une
classe normale.
Un appel statique se fait au travers de la classe, il n’a besoin d'aucune
instance pour être exécuté.
Java 8 autorise des méthodes statiques dans les interfaces, qui obéissent
aux mêmes règles que celles que l’on trouve dans les classes abstraites ou
concrètes.
public interface Reproduction {
public static void description() {
System.out.println("Méthode statique dans une
interface");
}}
public class Main {
public static void main(String[] args) {
Reproduction.description();
}}
Interface
15
Interfaces, intérêts?
Les interfaces permettent de s’affranchir d’éventuelles contraintes d’héritage.
Lorsqu’on examine une classe implémentant une ou plusieurs interfaces, on
est sûr que le code d’implémentation est dans le corps de la classe
Permet une grande évolutivité du modèle objet
L’interface peut s’assimiler à la carte de visite d’une classe (et de tous les
objets auxquels elle donne naissance), qu’un développeur d’une autre classe
consulte et s’engage à respecter dans la conception de la sienne.
Interface
16
Exemple: public interface IO1 {
public void
jeTravaillePourO1();}
public interface IO2 {
public void
jeTravaillePourO2();}
public class O1 implements IO1
{
private IO2 unO2;
public O1() { }
public void setO2(IO2 unO2){
this.unO2 = unO2;
}
public void jUtiliseO2() {
System.out.println("j'utilise O2");
unO2.jeTravaillePourO2();}
public void jeTravaillePourO1(){
System.out.println("je travaille
pour O1");}}
public class O2 implements IO2 {
private IO1 unO1;
public O2 (IO1 unO1){
this.unO1 = unO1;
}
public void jeTravaillePourO2() {
System.out.println("je travaille pour
O2");
}
public void jUtiliseO1(){
System.out.println("j'utilise O1");
unO1.jeTravaillePourO1();}}
public class Principale {
public static void main(String[] args) {
O1 unO1 = new O1();O2 unO2 = new
O2(unO1);
unO1.setO2(unO2); unO1.jUtiliseO2();
unO2.jUtiliseO1();}}
j’utilise O2
je travaille pour O2
j’utilise O1
je travaille pour O1
Interface
17
Variables de type interface et polymorphisme
Bien que la vocation d’une interface soit d'être implémentée par une classe,
on peut définir des variables de type interface.
On ne pourra pas affecter à i une référence à quelque chose de type I puis
qu’on ne peut pas instancier une interface (pas plus qu’on ne pouvait
instancier une classe abstraite!).
En revanche, on pourra affecter à i n'importe quelle référence à un objet
d’une classe implémentant l'interface I (Surclassement)
public interface I {…}
void main (String[] args){
Ii;
…}
class A implements I{…}
void main (String [] args){
I i= new A(…);//OK
Interface
18
Exemple
class Entier implements Affichable
{
private int val ;
public Entier (int n) {
val = n ;}
public void affiche() {
System.out.println («Je suis un
entier de valeur » + val) ;}
}
class Flottant implements Affichable {
private float val ;
public Flottant (float n){
val = n ;}
public void affiche() {
System.out.println (« Je suis un
flottant de valeur » + val) ; }
}
interface Affichable {
void affiche() ;
}
public class TestInterface {
public static void main (String [] args)
{
Afficheable [] tab = {new Entier (25),
new Flottant (1.25)}
tab [0].affiche();
tab [1].affiche();
}
}
Résultat de l’exécution :
Je suis un entier de valeur 25
Je suis un flottant de valeur
1.25
Interface
19
Exercice:
Certain animaux peuvent crier. On représentera le fait de crier au moyen
d’une méthode affichant à l’écran le cri de l’animal.
– écrire une interface contenant la méthode permettant de crier.
– écrire les classes des chats, des chiens et des coqs.
– écrire un programme avec un tableau pour les animaux qui savent crier, le
remplir avec des chiens, des chats et des coqs, puis faire crier tous ces
animaux. Décrire ce qui s’affiche à l’écran à l’exécution de ce programme.
Interface
20
Exercice:
interface Criant{
void crier(); }
class Chat implements Criant{
public void crier(){
System.out.println("maou");
} }
class Chien implements Criant{
public void crier(){
System.out.println("wouf");
} }
class Coq implements Criant{
public void crier(){
System.out.println(" cocorico ");
} }
public class AnimauxCriant{
public static void main(String[]
a){ Criant[] tab = new Criant[4];
tab[0] = new Chat(); tab[1] =
new Chien(); tab[2] = new
Coq(); tab[3] = new Chien(); for
(int i=0; i<4;i++){
Tab[i].crier();}}}
Classe Abstraite
21
Dans la pratique courante de l’OO, les superclasses, bien qu’indispensables
à la factorisation des caractéristiques communes aux sous-classes, ne
donnent que très rarement naissance à des objets.
Exemple: Dans un système, les animaux ne peuvent être que des animaux
concrets (lion , girafe, otarie, etc.) sauf si on vous demande de rajouter un
animal dans votre logiciel sans préciser son espèce…
Le concept de classe abstraite se situe entre celui de classe et celui
d’interface.
Une classe abstraite peut implémenter (partiellement ou totalement) des
interfaces et peut hériter d’une classe ou d’une classe abstraite.
Toute classe contenant au moins une méthode abstraite devient d’office
abstraite
Classe Abstraite
22
Une classe abstraite est une classe qui ne peut pas être instanciée.
Une classe abstraite peut contenir des méthodes implémentées.
Une classe abstraite peut contenir des méthodes non implémentées (au
moins une seule méthode non implémentée).
Une classe abstraite est héritable.
Une méthode abstraite doit être obligatoirement déclarée « public »
Une classe dérivée d’une classe abstraite n’est pas obligée de redéfinir
toutes les méthodes abstraites, elle peut ne redéfinir aucune, mais elle reste
abstraite tant qu’il y a encore des méthodes abstraites non implémentées.
Classe Abstraite
23
Syntaxe:
public abstract class A
{
public void f() {......} //f est définie dans A
public abstract void g (int n) ; //g est une méthode
abstraite elle n’est pas définie dans A
}
Classe Abstraite
24
Syntaxe:
public abstract class A
{ public void f() {......} //f est définie dans A
public abstract void g (int n) ; //g est une méthode
abstraite elle n’est pas définie dans A}
A a ; //on peut déclarer une référence sur un objet de type
A ou dérivé
a = new A (....) ; //Erreur pas d’instanciation d’objets
d’une classe abstraite
//Si B hérite de A
a = new B(...) ; //Juste car B n’est pas une classe
abstraite
Classe Abstraite vs Interface
30
Une interface ne peut pas contenir des méthodes déjà implémentées.
Une classe, ou une classe abstraite peut implémenter plusieurs interfaces,
mais n’a qu’une superclasse, alors qu’une interface peut dériver de plusieurs
autres interfaces.
Des classes non liées hiérarchiquement peuvent implémenter la même
interface
Classe Générique
33
Pourquoi la programmation générique?
La programmation générique implique d'écrire du code qui puisse être
réutilisé pour des objets de types différents
Exemple: On ne programme plus des classes différentes pour collecter les
objets String et File, puisque dorénavant, la classe ArrayList collecte les
objets de n'importe quelle classe
Classe Générique
34
Avant le JDK 5.0
- La programmation équivalente à la programmation générique s'obtenait à
chaque fois par le mécanisme d'héritage
Ainsi, la classe ArrayList conservait simplement un tableau de références
Object (la classe Object est l'ancêtre de toutes les autres classes) :
public class ArrayList { // Avant le JDK 5.0
private Object[] tableauElémentsStockés;
public Object get(int indice) { ... }
public void add(Object élément) { ... }
...
}
Classe Générique
35
Avant le JDK 5.0
Cette approche présente deux problèmes:
D'une part, il faut avoir recours au transtypage (cast) lorsque vous récupérez
une valeur :
D'autre part, il n'existe aucune procédure de vérification des erreurs
Vous pouvez ajouter des valeurs de n'importe quelle classe :
Cet appel compile et s'exécute sans erreur
Par ailleurs, transtyper le résultat de get() sur une chaîne produira une
erreur, puisque normalement, nous devrions récolter un objet de type File
ArrayList fichier = new ArrayList() ; ... String
nomFichier = (String) fichier.get(0) ;
fichier.add(new
File("...")) ;
Classe Générique
36
A partir du JDK 5.0
Le JDK 5.0 propose une meilleure solution
• les paramètres de type
La classe ArrayList est désormais paramétrée et dispose d'un paramètre qui
doit être un type d'objet
Ainsi, à chaque fois qu’on utilise la classe ArrayList
• on doit systématiquement préciser le type d'élément qui doit être stocké
à l'intérieur de cette collection :
ArrayList<String> fichier = new ArrayList()<String>
;
Classe Générique
37
A partir du JDK 5.0
Le code est désormais plus facile à lire
ArrayList sera composée uniquement d'objets de type String
Le compilateur utilisera également ces informations
Aucun transtypage n'est nécessaire pour appeler la méthode get() :
• Grâce à notre déclaration, le compilateur sait que le type de retour est
String, et non Object :
String nomFichier =
fichier.get(0) ;
Classe Générique
38
A partir du JDK 5.0
Le compilateur sait également que la méthode d'un ArrayList possède un
paramètre de type String
• Cette technique est bien plus sûre que d'utiliser systématiquement un
paramètre de type Object
Ainsi, le compilateur peut vérifier que vous n'insérez aucun objet d'un type
erroné
Exemple, l'instruction suivante :
ne se compilera pas
• Une erreur de compilation vaut bien mieux qu'une exception de
transtypage de classe au moment de l'exécution
fichier.add(new File("...")) ; // ne peut ajouter que des objets String à un
ArrayList<String>
Classe Générique
39
Syntaxe
Une classe générique est une classe comprenant une ou plusieurs variables
de type = une classe paramétrée, dont le paramètre est un type d'objet
Seuls des objets peuvent être utilisés avec les génériques :
• si un type primitif est utilisé dans les génériques, une erreur de type «
unexpected type » est générée lors de la compilation.
Public class ClasseGénérique <T, E,..>{ //le ou les types des objets à
passer en
//paramètre
…
}
Classe Générique
41
Exemple:
La classe Paire introduit
une variable de type T,
incluse entre <> après le
nom de la classe
Une classe générique
(paramétrée) peut
posséder plusieurs
variables de type (utiliser
l'opérateur virgule pour les
séparer)
Les variables de type peuvent être utilisées tout au long de la définition de
la classe pour spécifier le type de retour des méthodes, le type des
attributs, ou même le type de certaines variables locales
Rien n'empêche également d'utiliser des attributs ou d'autres éléments
avec des types bien définis, c'est-à-dire non paramétrable, comme int,
String, etc.
Classe Générique
42
Exemple:
L'attribut premier utilise
une variable de type
Ainsi, comme son nom
l'indique premier pourra
être de n'importe quel type
C'est celui qui utilisera
cette classe qui spécifiera
le type qu'il désire utiliser
pour décrire l'objet de cette
classe Paire
Ainsi, vous instanciez une classe paramétrée en précisant le type que vous
désirez prendre
Classe Générique
43
Exemple:
Par exemple :
Ici, ordre est un objet de type Paire
Le paramètre de la classe Paire, ou exprimé autrement, la variable de type
est String
Ainsi, au moment de cette déclaration, à l'intérieur de la classe Paire, tout ce
qui fait référence à T est remplacé par le véritable type, c'est-à-dire String
Classe Générique
45
Exemple:
Le programme suivant met en oeuvre la classe Paire
La méthode minmax() statique parcourt un tableau de chaînes de caractères et
calcule en même temps la valeur minimale et la valeur maximale
Elle utilise un objet Paire pour renvoyer les deux
résultats
Exercices
46
Execice1:
Soit l'interface suivante :
interface LesMobiles {
public void avancer (float distance);
public void reculer (float distance);
public void accelerer(float vistesse) ;
public boolean enMarche ();
public int getKillometrage ();
public void afficher() ;
}
1. Implémenter la classe abstraite DeuxRoues qui a :
• Un attribut kilométrage (indiquant la distance parcourue totale) de type réel visible
uniquement au niveau package.
• Un attribut maVitesse de type réel égale à 0 si le Mobile est en état d'arrêt.
• Une méthode enMarche() qui renvoie true si l'attribut maVitesse est différent de zéro,
flase sinon.
• Une méthode int getKillometrage ()
• Une méthode afficher().
Exercices
47
Execice1 (Suite):
La classe Bicyclette hérite de la classe DeuxRoues et implémente l'interface LesMobiles,
définie comme suit :
• Un attribut vitesseMax de type réel et est constant. Une bicyclette ne peut avancer
qu'à une vitesse inférieure à vitesseMax
• Un constructeur pour initialiser tous les attributs
2. Implémentez la classe « Bicyclette».
La classe Moto hérite de la classe Bicyclette, définie comme suit :
• Un attribut energie de type chaine de caractère (visible uniquement au niveau de la
classe)
• Un attribut puissance de type entier
• Un constructeur pour initialiser tous les attributs
• Une redéfinition de la méthode afficher() pour adjoindre l'affichage de ses attributs
3. Implémentez la classe « Moto».
Exercices
48
Execice1 (Suite):
4. Soit la classe suivante :
class MonProg {
public static void main(String[] args) {
DeuxRoues dr= new DeuxRoues() ;
// b est une bicyclette dont le kilométrage est 0 sa vitesse initiale est nulle et la
// vitesseMax est de 20 k/hr
LesMobiles b=new Bicyclette(0,0,20) ;
Moto mt= new Moto(0,0,180, ''essence'',7) ;
Bicyclette bc= new Moto(0,0,200,''essence'',5) ;
b.vitesseMax=30.5 ;
mt.afficher() ;
a. Détecter les erreurs, et les corriger
b. Qu'affiche ce programme.
Exercices
49
Execice2 :
Définir une classe générique Triplet à l’aide du symbole T. On utilise ce symbole T dans la
suite de la définition de la classe, comme s’il s’agissait d’un type donné.
1. Définir les trois éléments de la classe Triplet.
2. Définir un constructeur permettant d’initialiser ces trois éléments.
3. Définir les méthodes getPremier, getSecond et getTroisième permettant de retourner
l’élément respectif.
4. Définir la méthode affiche permettant d’afficher les éléments d’un triplet.
5. Créer la classe TestTriplet qui vous permet de tester cette classe:
• Créer un triplet d’Integer, d’afficher ses éléments et d’obtenir le troisième
élément.
• Créer un triplet de camarades (chaines de caractères), d’afficher ses éléments et
d’obtenir son premier élément.