f. voisin : introduction à java 1 introduction à java - lhéritage - frédéric voisin fiifo - «...

34
F. Voisin : Introduction à Java 1 Introduction à Java - l’héritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

Upload: lucinde-raynaud

Post on 03-Apr-2015

112 views

Category:

Documents


2 download

TRANSCRIPT

Page 1: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 1

Introduction à Java

- l’héritage -

Frédéric VOISIN

FIIFO - « Remise à Niveau »

Page 2: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 2

Classes et Héritage

Définir une nouvelle classe par « extension » ou « spécialisation » d’une classe existante, en n’en donnant que ce qui diffère.

class SousClasse extends SuperClasse

les instances de SousClasse sont vues comme étant aussi des instances de SuperClasse.

+ spécifique,+ riche(sous-classe)

+ générale(classe)

SuperClasse

SousClasse

Page 3: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 3

Classe et Héritage (suite)

Une sous-classe peut

ajouter de nouveaux attributs (la redéfinition ou l’oubli d’attributs est interdit, mais un attribut peut en masquer un autre dans la super-classe)

ajouter de nouvelles méthodes redéfinir (spécialiser) des méthodes de sa super-classe

On peut interdire

qu’un membre de la super-classe soit visible des sous-classes : Il est alors hérité mais pas

référençable à partir d’une méthode de la sous-classe.

Les membres référençables par les sous-classes sont ceux qui ont une visibilité public ou

protected.

que certaines méthodes soient redéfinies (final), que certaines classes soient dérivables (final)…

L’héritage est une relation transitive !

Page 4: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 4

Les hiérarchies de classes Java

En Java, on ne peut dériver via extends que d’au plus une classe. On parle alors d’héritage simple (par opposition à héritage multiple)

Si une classe n’a pas de super-classe explicite, elle dérive implicitement de la classe prédéfinie Object

Toute classe hérite donc, directement ou non, de Object qui fournit des services par défaut. Ces services par défaut peuvent (et souvent doivent) être redéfinis dans les sous-classes : public boolean equals(Object O) public String toString() protected Object clone()

Page 5: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 5

Un exemple de hiérarchie de classes

Carré …

FigureOrigine: contient(Point2D) dessiner()effacer() move(int dx, int dy)

Point2D x, y: double getX(), getY() move(int dx, int dy)

Rectangle

largeur, longueur: double

contient(Point2D) dessiner() effacer()

Cercle

rayon: double

contient(Point2D) dessiner() effacer()

Segment Opposé:

contient(Point2D) dessiner() effacer()

Page 6: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 6

Héritage et typage

Partout où on attend une Figure, on peut utiliser un Cercle :public void f(Figure fig) {

Cercle c = new Cercle(…);

fig.move(12, 24); // correct, toujours défini

c.move(12, 24); // correct, toujours défini

fig = c; // correct, toujours défini, mais pour le compilateur

// fig référence toujours une Figure arbitraire !

fig.rayon = 12; // KO

c = fig; // KO ! que vaudrait c.rayon si fig était une figure arbitraire ?

}

f(new Cercle); f(new Rectangle); // OK !

Ces conversions implicites vers Figure sont acceptées silencieusement par le compilateur et ne peuvent pas échouer !

Page 7: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 7

Héritage et Liaison Dynamique de Fonctions

On se base sur le type réel de l’objet (et non pas son type apparent) pour savoir

quelle méthode exécuter (polymorphisme, ou liaison dynamique) :Figure fig; Point2D p = new Point2D(1,1);

Math.Random hasard = new Math.Random();

if (hasard.nextInt(2) != 0) // Pile ou face ?

fig = new Cercle(p, Math.Pi);

else fig = new Rectangle(p,1,1);

fig.dessiner(); // quelle dessiner() ?

Les méthodes peuvent s’appuyer sur les comportements redéfinis :

public move(double dx, double dy) { // dans Rectangle

this.effacer(); super.move(dx, dy); this.dessiner();

}

Page 8: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 8

Héritage et constructeurs

Les constructeurs ne sont pas hérités mais il existe un « protocole » pour effectuer les initialisations en cascade en remontant la hiérarchie de classes

dans Figure: protected Figure(Point p) { origine = p; }

dans Rectangle:public Rectangle(Point p, double long, double larg) {

super(p); // Première instruction !

longueur = long; largeur = larg;

}

« Méthodologiquement » un constructeur ne devrait s’occuper que des attributs définis à son niveau.

Page 9: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 9

Héritage et typage: exemple 2

ObjGraphique

dessiner()

Diagramme

ObjGraphique[] elements

dessiner()ajouter(ObjGraphique)supprimer(ObjGraphique)

Figure

Point2D Origine

dessiner()

Cercle

dessiner()

Rectangle

dessiner()

Page 10: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 10

Exemple 2 (suite)

Diagramme d = new Diagramme(); Point2D p = new Point2D(0,0);d.ajouter(new Cercle(p, Math.Pi));d.ajouter(new Rectangle(p, 3.0, 5.0));

public void dessiner() { // dans Diagramme for(int i = 0; i < elements.length; i++)

elements[i].dessiner(); // quelle dessiner() ??}public void supprimer(ObjGraphique p) { for(int i = 0; i < elements.length; i++)

if (elements[i].equals(p)) … // quelle equals() ??} La classe ObjGraphique ne sert qu’à donner un chapeau (type) commun

aux deux sous-classes.

Dynamiquement, il n’y a que des instances des classes concrètes !

Page 11: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 11

Héritage et typage (suite)

On a parfois besoin de la conversion de la super-classe vers la sous-classe : cela doit être explicite : c = (Cercle) fig;

cela échoue à la compilation si la conversion « n’a pas de sens » cela peut échouer à l’exécution (levée d’une exception) : si fig ne contient pas

à cet instant une instance (au sens large) de Cercle.

Rectangle monR = new Rectangle();

Figure fig; Cercle monC;

monC = (Cercle) monR; // KO à la compilation car désespéré !

fig = monR; // toujours OK

monC = (Cercle) fig; // OK à la compilation, KO à  l’exécution

le compilateur ajoute donc le code qui fera la vérification à l’exécution.

Page 12: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 12

Héritage et Typage : exemple 1

C’est notamment le cas avec les classes de la hiérarchie Collection qui implémente différentes structures de données.

dans ArrayList:

public void add(Objet e);

public Object get(int i);

dans Employe:

private static ArrayList listeEmployes = new ArrayList() ;

...

… listeEmployes.add(e); … System.out.println(listeEmployes.get(i).toString());

:-( a priori get renvoie (statiquement) une instance de Object

;-| pourquoi cela compile-t-il ? Pourquoi cela marche-t-il ?

Page 13: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 13

Héritage et Typage : exemple 1(suite)

Si on voulait réellement récupérer l’instance de Employé ??Employe e = listeEmployes.get(i); // KO !

Employe e = (Employe) listeEmployes.get(i); // OK ?

listeEmployes.get(i).imprime() // KO

((Employe) listeEmployes.get(i)).imprime() // OK ?

Attention : si listeEmployes contient autre chose que des instances de Employes (ce n’est pas add que ça dérangerait !!!)

Il faut éviter de tester le type des objets et utiliser la redéfinition de méthodes :

redéfinition de toString()et non pas définition de imprime()

Page 14: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 14

Exemple 3 : Représenter les règles suivantes qui régissent une partie des différents statuts possibles d'une société...

SNC (Société en nom collectif) Capital social : aucun capital requis Nombre d'associés : 2 minimum, pas de maximum Cession des parts : nécessite l'unanimité des associés

SARL (Société à responsabilité limitée) Capital social : 7 500 euros Nombre d'associés : 2 au minimum, 50 au maximum Cession des parts : librement cessibles aux associés, conjoints, ascendants et descendants; accord des 3/4 des associés sinon

SA (Société anonyme) Capital social : 37 000 euros (225 000 euros, en cas d'appel public à l'épargne) Nombre d'associés : 7 minimum, pas de maximum Cession des parts : entièrement libre

Page 15: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 15

Associé

estProche(Associé);

PersonneMorale…

PersonnePhysique…

Société

Associés[] lesAssociés;

int capital;

nom, siège, objet, durée: …

protected Société(…);

cession(Associé, Associé);

addAssocié(Associé);

protected cessionPossible(Associé, Associé);

SNC

SNC(Associé[], int, …);

SNC(Associé[], …);

SARL

SARL(Associé[], capital, …);

cessionPossible(Associé, Associé, ...);

addAssocié(Associé);

SA

SA(Associé[], int, ...);

SAE

SAE(Associé[], int, …);

Association

Page 16: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 16

Il n’existe pas de société sans statut spécifique. On ne veut donc pas pouvoir créer d’instance de Société (classe « abstraite »).

Le même problème se posait avec Figure La classe Société ne sert qu’à factoriser la description :

Attributs communs Méthodes publiques avec « comportement par défaut » Méthodes publiques qui doivent être redéfinies par les sous-classes (méthodes

« abstraites ») Méthodes auxiliaires pour faciliter la réalisation des sous-classes (méthodes avec

visibilité protected ou moins)

Les sous-classes ajoutent des informations ou redéfinissent des comportements De même, un « associé » n’existe pas vraiment ! C’est soit une personne morale,

soit une personne physique ! Associé et PersonneMorale sont abstraites.

Exemple 3 (suite)

Page 17: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 17

Exercice

Précisez les comportements des différentes méthodes (en pseudo-code)

Page 18: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 18

D’autres types de statuts

La hiérarchie peut être beaucoup plus compliquée, selon la complexité du monde à modéliser !

Il n’est pas simple de modifier une hiérarchie a posteriori

Société

SociétéPersonnes SociétéCapitaux SociétéMixte

SARLSASNC Entr.Individuelle

Page 19: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 19

Héritage ou Composition

Il existe deux moyens de « réutiliser » une classe : par héritage (Cercle hérite de Figure) par composition : avoir comme attribut un objet d’une autre classe, comme Point2D qui

est utilisée dans Figure.

Les deux moyens ont des usages différents !

Autre exemple: définition de « points colorés » :

class PointColore {

Point2D lePoint;

Couleur laCouleur;

}

class PointColore

extends Point2D {

Couleur laCouleur;

}

???

Page 20: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 20

Héritage ou Composition (suite)

Héritage : relation « est une sorte de ».

La classe dérivée est vue comme une extension, ou comme une spécialisation de la super-classe. Elle offre de nouveaux comportements et/ou en redéfinit.

Tous les comportements définis dans la super-classe et « visibles » sont applicables aux instances de la sous-classe.

Super-classe et sous-classe doivent être sémantiquement et structurellement « compatibles ».

Héritage ? Seulement si on veut rendre accessibles toutes les méthodes (non protected) de la super-

classe les structures sont compatibles (nombre et type des champs)

Page 21: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 21

Héritage ou Composition (suite)

Composition : relation « est composée de  » :

La classe réutilisée participe à l’implantation de la classe considérée mais les deux ne sont pas compatibles.

Les méthodes ne sont pas vraiment reliées. Pour « réutiliser », on délègue:

Figure.move(dx, dy) { origine.move(dx, dy); }F.getX() n’a pas de sens si F est une instance de Figure.

Les membres de la classe composée ne sont pas visibles a priori : par exemple Point2D devra avoir prévu des méthodes (publiques) d’accès aux

coordonnées de l ’origine.

Page 22: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 22

Héritage ou Composition (fin)

Exercice : A posteriori, quelles relations entre

Figure et Point ?

Figures / ObjetGraphique / Diagrammes ?

Point2D et Point3D ?

Point et PointColoré ?

Date et Durée ?

Page 23: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 23

Héritage, surcharge et redéfinition

une méthode de la sous-classe ne redéfinit (et masque) que la méthode de la super-classe de même profil :

public boolean equals(Point2D) { … } // dans Point2D

ne redéfinit pas et ne masque pas

public boolean equals(Object 0) { … } // dans Object

Selon le type (statique) du paramètre on obtiendra l’une ou l’autre :-(

Ne pas confondre surcharge et redéfinition de méthodes, ni aspect « statique » et « dynamique » : surcharge : plusieurs méthodes de même nom mais de profils différents

redéfinition : cas particulier de « surcharge » en conservant exactement le profil et en présence d’une relation d’héritage.

Page 24: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 24

Héritage, surcharge et redéfinition (suite)

A la compilation, on détermine la « famille » (i.e. ensemble des redéfinitions dans une hiérarchie donnée) de méthodes potentiellement appelables, compte-tenu de la surcharge

A l’exécution, la liaison dynamique appelle la « bonne » méthode dans la famille déterminée statiquement, selon la classe du receveur.

La liaison dynamique se fait donc « à profil constant », le profil ayant été déterminé à la compilation, selon le type des paramètres…

Page 25: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 25

Héritage, surcharge et redéfinition (exercice)

class Object

public boolean equals(Object P)

class Point2D

public boolean equals(Object P)

public boolean equals(Point2D P)

class PointColore

public boolean equals(Object P)

public boolean equals(Point2D P)

public boolean equals(PointColore P)

class A

public boolean equals(Object P)

public boolean equals(A monA)

Déterminez les « familles » de méthodes...

Page 26: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 26

static void t1(Object O1, Object O2) {… O1.equals(O2) … }

static void t2(Point2D P1, Point2D P2) {… P1.equals(P2) … }

Point2D P1 = new Point2D(1.0, 1.0);

Point2D P2 = new Point2D(1.0, 1.0);

PointColoré PC1 = new PointColore(1.0, 1.0, Couleur.Blanc);

PointColoré PC2 = new PointColore(1.0, 1.0, Couleur.Vert);

t1(P1, PC1);

t1(PC1, P1);

t2(P1, PC1);

t2(PC1, P1);

… P1.equals(P1)…

… PC1.equals(P1)…

t1(P1, P2);

t2(P1, P2);

t1(PC1, PC2);

t2(PC1, PC2);

Dans chaque cas, déterminez la méthode appelée dynamiquement …

Qu’en déduit-on ?

Page 27: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 27

Héritage, surcharge et redéfinition (exercice)

public class Object

public boolean equals(Object P)

public class Point2D

public boolean equals(Object P)

public class Point2DColore

public boolean equals(Object P)

public class A

public boolean equals(Object P)

Programmez chaque méthode de la famille...

Page 28: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 28

La visibilité « protected »

public class C {

protected int val;

}

public class C2 extends C {

public void f(C arg, C2 arg2) {

this.val = 1; // OK

C2.val = 1; // OK

C.val = 1; // KO (modulo les règles sur les paquetages)

}

}

Il restera un quatrième niveau de visibilité à voir !

Page 29: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 29

Les classes abstraites

abstract class C { abstract public void f(); // pas de corps pour f !} Classe abstraite = une classe dont on ne veut pas pouvoir créer d’instance !

Racine pour une hiérarchie dans laquelle les sous-classes apporteront leurs particularités

Permet de partager certaines descriptions :Variables d’instances (ou de classes) communesMéthodes définissant un comportement par défautMéthodes abstraites à redéfinir par les sous-classes

Méthode abstraite = une méthode dont on donne uniquement le profil et qui devra être redéfinie dans toute sous-classe instanciable

Toute classe qui comporte une méthode abstraite doit être déclarée abstraite

Toutes les méthodes d’une classe abstraite ne sont pas forcément abstraites Le compilateur interdit l’instanciation des classes abstraites.

Page 30: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 30

Classes abstraites: un exemple

Figure est abstraite : une figure n’existe pas sans une forme précise

contient et dessiner ne sont pas implémentables sans connaître la forme précise.

Par contre, move peut être implémentée directement dans Figure...

Segment Opposé: Point

contient(Point)dessiner()

Figure

Origine: Pointcontient(Point)dessiner()move(int x, int y)

Cercle Rayon: Réel

contient(Point)dessiner()

Rectangle

largeur, long: Réel

contient(Point)dessiner()

Page 31: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 31

La classe Figure en Java

abstract public class Figure {

protected Point2D origine;

public abstract void dessiner();

public abstract boolean contient(Point2D P);

public void move(int x, int y) { origine.move(dx, dy); }

}

public class Rectangle extends Figure {

public void dessiner() { ... }

public boolean contient(Point2D P) { ... }

...

}

Page 32: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 32

Résumé: les « marqueurs » dans les déclarations

static : distingue ce qui est relatif à une classe ou à ses instances

public, private, protected: modifie la visibilité par défaut

final : ce qui ne changera plus ! pour un attribut : une constante (connue à la compilation ou non)

static final int MAX = 100; final String nom = "Java"; final String nom; // devra être initialisé dans tous les constructeurs final MaClasse monObjet = new MaClasse(); // sens ??

pour un argument de méthode: argument non modifiable (voir ci-dessus) pour une méthode: elle ne peut plus être redéfinie dans une sous-classe pour une classe: elle ne peut pas être dérivée.

abstract : pour les classes et méthodes seulement

Page 33: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 33

Le modificateur final: exemple

class Compteur { // Nouvelle valeur à chaque appel à next static int v = 0; public static int next() { return ++v; }}

class Cfinal { final static int i2 = Compteur.next(); final int i3 = Compteur.next(); // type primitif final int i4; final MaClasse monC = new MaClasse(); // type référence public CFinal() { i4 = Compteur.next(); } public String toString() { ... } // à finir ! public void f (maClasse arg) { monC.incr(); // OK ou KO ? monC = arg; // OK ou KO ? }}

Page 34: F. Voisin : Introduction à Java 1 Introduction à Java - lhéritage - Frédéric VOISIN FIIFO - « Remise à Niveau »

F. Voisin : Introduction à Java 34

Le modificateur final: exemple (suite)

class MaClasse { int v = 0; public int incr() { return ++v; } public String toString () { return "v: " + v;}}

public class TestFinal { public static void main(String[] args) { CFinal t1 = new CFinal(); CFinal t2 = new CFinal(); t1.toString(); t2.toString(); t1.monC.incr(); t1.toString(); t2.toString(); }}