précédent | suivant | table des matières | s'évaluer |
|
1 Définition.
Une interface définit un comportement (d’une classe) qui doit être implémenté par une classe, sans implémenter ce comportement. C’est un ensemble de méthodes abstraites, et de constantes. Certaines interfaces ( Cloneable, Serializable, …) sont dites interfaces de «balisage» : elle n’imposent pas la définition d’une méthode, mais indiquent que les objets qui les implémentent ont certaines propriétés.
Les différences entre les interfaces et les classes abstraites :
2 L'interface Comparable
L’interface Comparable, nécessite l’implémentation de la méthode compareTo :
interface Comparable int compareTo(Object o); }
Exemple : ordonner les employés d’une entreprise par ordre croissant des salaires :
On peut créer une classe entreprise de la façon suivante :
public class Entreprise { Employe [] lEntreprise; public Entreprise(Employe [] e) { lEntreprise = new Employe[e.length]; for (int i = 0; i<e.length; ++i) lEntreprise[i] = e[i]; } public void lister(){ for (int i = 0; i<lEntreprise.length; ++i) System.out.println(lEntreprise[i]); } }
Pour lister les employés de l’entreprise par ordre alphabétique, on peut utiliser le tri de tableaux de la classe Arrays, mais il nécessite que les élément à trier implémentent l’interface Comparable :
public void listerOrdre(){ Arrays.sort(lEntreprise); for (int i = 0; i<lEntreprise.length; ++i) System.out.println(lEntreprise[i]); }
Donc la classe Employe s’écrit :
class Employe implements Comparable{ . . . public int compareTo( Object o ){ Employe e = (Employe)o; // lève une exception // ClassCastException si o // n’est pas de la classe Employe return nom.compareTo(e.nom);// par ordre alphabétique return (int)(salaire-e.salaire);// par salaire croissant } }
Si on veut pouvoir trier par salaire croissant ou par ordre alphabétique, on définira un attribut de classe booléen triSalaire :
class Employe implements Comparable{ static boolean triSalaire = true; . . . public int compareTo( Object o ){ Employe e = (Employe)o; // lève une exception //ClassCastException si o // n’est pas de la classe Employe if(triSalaire) return (int)(salaire-e.salaire);//par salaire croissant else return nom.compareTo(e.nom); //par ordre alphabétique } }
La méthode listerOrdre de la classe Entreprise devient alors :
public void listerOrdre(boolean triSalaire){ Employe.triSalaire = trisalaire ; Arrays.sort(lEntreprise); for (int i = 0; i<lEntreprise.length; ++i) System.out.println(lEntreprise[i]); }
3 L'interface Cloneable.
C’est une interface de balisage : une classe qui implémente l’interface Cloneable, indique à Object.clone() qu’il est légal pour cet objet de faire une copie superficielle attribut par attribut pour les instance de cette classe. Une tentative de clonage pour des classes qui n’implémentent pas Cloneable se traduit par la levée d’une exception : CloneNotSupportedException. La définition de clone() pour la classe Object est :
protected native Object clone() throws CloneNotSupportedException{
if ( !(this instanceof Cloneable)) throw new CloneNotSupportedException();
else {
// copie superficielle des attributs
}
}
class XSurface implements Cloneable{ . . . public Object clone() throws CloneNotSupportedException { return super.clone(); } }
class XProfondeur implements Cloneable{ X x; . . . public Object clone() throws CloneNotSupportedException { XProfondeur xp = (XProfondeur)super.clone() ; xp.x = (X)x.clone(); return xp; } }
4 L’interface Iterator.
L’interface Iterator nécessite l’implémentation des fonctions hasNext(), next(), remove() :
interface Iterator { boolean hasNext(); Object next(); void remove(); }
L’opération remove() est dite optionnelle, c'est-à-dire que son implémentation pourrait être dans ce cas :
public void remove() { throw new UnsupportedOperationException(); }
4.1 L'interface ListIterator.
L'interfaceListIterator est dérivée de Iterator, et ajoute des fonctionnalités de parcours dans le sens inverse, de calcul d’indice, et d’ajout et de modification.
boolean hasPrevious() |
Retourne vrai si l’élément courant à un élément le précédant |
Object previous() |
Retourne l’élément précédant. |
int nextIndex() |
Retourne l’indice de l’élément qui serait retourné par un appel de next |
int previousIndex() |
Retourne l’indice de l’élément qui serait retourné par un appel de previous |
void add(Object o) |
Ajoute un élément dans la liste (opération optionnelle) |
void set(Object o) |
Remplace le dernier élément retourné par next ou previous par o (opération optionnelle) |
5 L’interface Serializable.
La sérialisation d'un objet est le processus de sauvegarde d'un objet complet sur fichier, d'où il pourra être restauré à tout moment. Le processus inverse de la sauvegarde ( restauration ) est connu sous le nom de désérialisation.
Tous les attributs (qui ne sont pas spécifiés transient ) d’une classe implémentant l’interface Serializable sont sauvés et restaurés de façon simple en utilisant les classes ObjectOutputStream et ObjectInputStream.
Exemple : soit la classe suivante, permettant d’implanter une liste, dans laquelle chaque élément possède une référence vers le premier élément entré dans la liste.
public class MaClasse implements Serializable{ String nom; int entier; MaClasse premier ,suivant; public MaClasse(String n, int e, MaClasse s, MaClasse p) { super() ; nom = n; entier = e; suivant = s; premier = p ; } public MaClasse(String n, int e) { this(n, e, null, null); premier = this; } }
On peut alors définir un liste :
MaClasse liste = null ; liste = new MaClass("un", 1) ; premier = liste ; liste = new MaClass("deux", 2, liste, premier) ; liste = new MaClass("trois", 3, liste, premier) ;
La sérialisation ( sauvegarde ) dans le fichier "serial.tmp" se fait alors simplement de la façon suivante :
try{ FileOutputStream sortie = new FileOutputStream("serial.tmp"); ObjectOutputStream p = new ObjectOutputStream(sortie); p.writeObject(liste); p.flush(); sortie.close(); }catch(IOException ioe){ System.out.println("erreur dans la sérialisation : "+ ioe); }
L’intruction p.writeObject(liste) lève l’exception NotSerializableException si la classe MaClasse n’implémente pas l’interface Serializable.
La désérialisation est aussi simple :
try{ FileInputStream instream = new FileInputStream("serial.tmp"); ObjectInputStream p = new ObjectInputStream(instream); liste = (MaClasse)p.readObject(); instream.close(); dlm.clear(); afficher(liste); }catch(IOException ioe){ System.out.println("erreur dans la sérialisation : "+ ioe); }catch(ClassNotFoundException cnfe){ System.out.println (" classe non trouvée : "+ cnfe); }
Pour éviter les copies d’un objet référencé plusieurs fois, le procédé suivant est appliqué :
La liste précédente est donc stockée de la façon ci-contre : |
6 Remarques
L’héritage multiple est autorisé pour les interfaces :
interface MonInterfaceB { void f(); } interface MonInterface1 extends MonInterfaceB { void f1(); } interface MonInterface2 extends MonInterfaceB{ void f2(); } interface MonInterface extends MonInterface1, MonInterface2 { void fd(); }
Les classes implémentant MonInterface doivent implémenter f(), f1(), f2(), et fd().
Une interface peut servir à définir des constantes :
interface Mois{ final int JANVIER = 1, FERVRIER = 2, … DECEMBRE = 12 ; }
6.1 Paramètres méthode
Contrairement à de nombreux langages de programmation, Java n’autorise pas de paramètres qui soient des méthodes. Les interfaces peuvent servir à simuler ce fonctionnement :
interface X{ void f(){ } } class C{ . . . public void m(X x){ . . . x.f() ; } } |
class maClasse implements X{
. . .
public void f(){
. . .
}
}
C c = new C() ;
maClasse mc = new MaClasse() ;
c.m(mc) // la méthode m va appeler la méthode f
// définie dans maClasse.
|