FMIN 110 GMIN 327 Liaison statique et dynamique
- Slides: 48
FMIN 110 -GMIN 327 Liaison statique et dynamique Variables et méthodes de classe
Liaison dynamique Liaison statique
Liaison dynamique • message Appt a; a = new Appt. Luxe(…); … a. loyer(); • Type statique (type de la variable), utilisé pour vérifier si loyer() existe sur les Appt • Type dynamique (type de l’objet/de l’instance, derrière le new), utilisé pour choisir (lier) la méthode loyer() la plus spécifique
Liaison dynamique • Pour un message o. m() • une méthode m() est recherchée en commençant par le type dynamique de o (sa classe) et en remontant dans ses super-classes • la méthode exécutée est celle qui est trouvée dans la classe la plus proche en possédant une
Soient les classes A et B contenant les méthodes : Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } Qu’affiche le programme suivant : B b = new B(); System. out. println(b. f()); System. out. println(b. g()); System. out. println(b. h()); System. out. println(b. k()); System. out. println(b. i());
Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } B b = new B(); System. out. println(b. f()); f. B f. A • b de type dynamique B • f apparaît dans B • affiche f. B • appelle super. f() pour b • f recherchée à partir de A, elle apparaît dans A • affiche f. A
Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } B b = new B(); System. out. println(b. g()); g. A • b de type dynamique B • g n’apparaît pas dans B – on remonte dans A • g apparaît dans A • affiche g. A
Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } B b = new B(); System. out. println(b. h()); h. B f. A • b de type dynamique B • h apparaît dans B • affiche h. B • appelle super. f() pour b • f recherchée à partir de A, elle apparaît dans A • affiche f. A
Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } B b = new B(); System. out. println(b. k()); k. B g. A • b de type dynamique B • k apparaît dans B • affiche k. B • appelle g() = this. g()) pour b • g recherchée à partir de B, elle apparaît dans la superclasse A • affiche g. A
Classe A Classe B String f() {return "f. A "; } String g() {return "g. A "; } String i() {return "i. A "+ this. f(); } String f() {return "f. B " + super. f(); } String h() {return "h. B "+ super. f(); } String k() {return "k. B " + g(); } B b = new B(); System. out. println(b. i()); i. A f. B f. A • b de type dynamique B • i cherchée à partir de B, trouvée dans A • affiche i. A • appelle this. f() pour this = b • f recherchée à partir de B • affiche f. B et appelle super. f() • f recherchée à partir de A, trouvée dans A • affiche f. A
Retour super = accès à la méthode masquée Classe A Classe B String f() {return "f. A"; } String g() {return "g. A"; } String f() {return "f. B " + super. f(); } String h() {return "h. B " + super. f(); } String k() {return "k. B " + super. g(); } Dans h() : super. f() bof - conception ? Dans k() : super. g() NON - écrire g() Règle : on utilise super. f() dans une nouvelle définition de f()
On ne peut faire appel qu'à la méthode masquée Classe A void f() Classe B void f(){. . . super. f()} Classe C void f() { …. super. f() ; } f() de A
Peut-on "redéfinir" une méthode privée? A B private f() public f() { super. f(). . } super. f() impossible car f() privée en A En fait c'est comme si B définissait une nouvelle méthode
Redéfinition de méthode dans une sous-classe Une redéfinition de méthode se fait - sans changer la liste de types paramètres - le type de retour peut être spécialisé (> Java 1. 5) La protection peut être affaiblie (package -> protégée -> publique) Ce sont des mesures pour garantir la substituabilité syntaxique et la liaison dynamique
surcharge = Liaison statique A B public void f(int a) public void f(String b) Une instance de B possède 2 méthodes f B b = new B(); b. f(5); //f de A b. f("5"); // f de B
Un exemple de surcharge • Dans la classe Appartement une méthode set. Superficie : public void set. Superficie(double s){superficie=s; } • Dans la classe Appartement. Normal une méthode set. Superficie : public void set. Superficie(int s) { if (s <= 200) super. set. Superficie(s); else System. out. println("Erreur superficie trop grande pour un appartement normal"); }
A l’exécution : public static void main(String[] args) { Appartement a 2 = new Appartement. Normal("rue des sapins", 1870, 100, 6, 2); Appartement. Normal a 6 = new Appartement. Normal("rue des sapins", 1870, 100, 6, 2); System. out. println("avec a 2"); a 2. set. Superficie(250); ----------------------------------------affiche : avec a 2 et appelle set. Superficie(double) dans Appartement – set. Superficie(int) ne redéfinit pas set. Superficie (double) – a 2 est de type statique Appartement le compilateur cherche une méthode à laquelle a 2. set. Superficie(250) peut être conforme dans Appartement Il trouve set. Superficie (double) qui n’est pas redéfini
A l’exécution : public static void main(String[] args) { Appartement a 2 = new Appartement. Normal("rue des sapins", 1870, 100, 6, 2); Appartement. Normal a 6 = new Appartement. Normal("rue des sapins", 1870, 100, 6, 2); (…) System. out. println("avec a 6"); a 6. set. Superficie(250); } ----------------------------------------affiche : avec a 6 et appelle set. Superficie(int) dans Appartement. Normal affiche : Erreur superficie trop grande pour un appartement normal – a 6 est de type statique Appartement. Normal le compilateur cherche une méthode à laquelle a 6. set. Superficie(250) peut être conforme dans Appartement. Normal Il trouve set. Superficie (int)
Tests de type … Une méthode d’égalité sur les appartements • Dans la classe Appartement : public boolean equals(Appartement autre) { return this. adresse. equals(autre. adresse) && this. annee. Construction==autre. annee. Construction && this. superficie==autre. superficie && this. nb. Pieces==autre. nb. Pieces; }
On aimerait écrire ainsi une méthode d’égalité sur les appartements de luxe • Dans la classe Appartement. Luxe on écrirait equals : public boolean equals(Appartement. Luxe autre) { return super. equals(autre) && this. quartier. equals(autre. quartier); } • PB : Ce n’est pas une redéfinition mais une surcharge • Il faut être vigilant sur le comportement
La méthode main public static void main(String[] args) { Appartement a 1 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement a 2 = new Appartement. Normal("rue des sapins", 1870, 150, 6, 2); Appartement a 3 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Montferrier"); Appartement. Luxe a 4 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement. Luxe a 5 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Clapiers"); System. out. println("a 1 égale a 2 : "+ a 1. equals(a 2)); System. out. println("a 1 égale a 3 : "+ a 1. equals(a 3)); System. out. println("a 1 égale a 4 : "+ a 1. equals(a 4)); System. out. println("a 4 égale a 5 : "+ a 4. equals(a 5)); }
Etat des lieux • Les méthodes equals des classes Appartement. Normal et Appartement. De. Luxe n’ont pas la même signature que la méthode equals de la classe Appartement. Ce ne sont pas des redéfinitions mais des surcharges.
public static void main(String[] args) { Appartement a 1 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement a 2 = new Appartement. Normal("rue des sapins", 1870, 150, 6, 2); Appartement a 3 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Montferrier"); Appartement. Luxe a 4 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement. Luxe a 5 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Clapiers"); System. out. println("a 1 égale a 2 : "+ a 1. equals(a 2)); appelle equals de Appartement et compare les attributs d’appartement TRUE (pourtant les types sont différents) System. out. println("a 1 égale a 3 : "+ a 1. equals(a 3)); appelle equals de Appartement et compare les attributs d’appartement TRUE (pourtant les quartiers sont différents) System. out. println("a 1 égale a 4 : "+ a 1. equals(a 4)); appelle equals de Appartement et compare les attributs d’appartement TRUE (et en effet les quartiers sont semblables) System. out. println("a 4 égale a 5 : "+ a 4. equals(a 5)); appelle equals de Appartement. Luxe et compare tous les attributs FALSE (et en effet les quartiers sont différents) }
La coercition et le test de type • Dans la classe Appartement. Luxe, on va redéfinir la méthode equals et non la surcharger : Test de type public boolean equals(Appartement autre) { Coercition autre Appartement. Luxe autre. L=null; est de type if (autre instanceof Appartement. Luxe) { statique autre. L = (Appartement. Luxe) autre; Appartement. Luxe return super. equals(autre) && this. quartier. equals(autre. L. quartier); } else return false; }
Ce sont bien des redéfinitions !
public static void main(String[] args) { Appartement a 1 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement a 2 = new Appartement. Normal("rue des sapins", 1870, 150, 6, 2); Appartement a 3 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Montferrier"); Appartement. Luxe a 4 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Arceaux"); Appartement. Luxe a 5 = new Appartement. Luxe("rue des sapins", 1870, 150, 6, "Clapiers"); System. out. println("a 1 égale a 2 : "+ a 1. equals(a 2)); appelle equals de Appartement. Luxe FALSE (en effet les types sont différents) System. out. println("a 1 égale a 3 : "+ a 1. equals(a 3)); appelle equals de Appartement. Luxe et compare tous les attributs FALSE (en effet les quartiers sont différents) System. out. println("a 1 égale a 4 : "+ a 1. equals(a 4)); appelle equals de Appartement. Luxe et compare tous les attributs TRUE (et en effet les attributs sont semblables, y compris les quartiers) System. out. println("a 4 égale a 5 : "+ a 4. equals(a 5)); appelle equals de Appartement. Luxe et compare tous les attributs FALSE (et en effet les quartiers sont différents) }
La coercition et le test de type • Application : si on recherche des appartements dans les appartements gérés par une agence immobilière, il faut utiliser la version de la méthode « equals » avec coercition et test de type. • La coercition de type est ici sans risque car appart. Geres ne contient que des instances des sous-classes de la classe Appartement (et qu’elle est faite sous condition de type). • Règle générale : le moins possible de coercitions et de tests de type. A part le cas présent (multi-méthodes) ils révèlent souvent une mauvaise conception.
Principe de substitution de Liskov • Lorsqu’un type S est sous-type d’un type T Tout objet de type S peut remplacer un objet de type T sans que le programme n’ait de comportement imprévu ou ne perde de propriétés souhaitées.
Substituabilité La substituabilité syntaxique demande - la contravariance des paramètres - les paramètres varient en sens inverse de la redéfinition. - la covariance du type de retour - le type de retour varie dans le même sens que la redéfinition
Le choix de Java pour la redéfinition de méthode • Invariance des paramètres – Dans Appartement, Appartement. Luxe et Appartement. Normal, on a la même signature pour equals public boolean equals(Appartement autre); • Covariance des types de retour – Dans Appartement : public abstract Appartement clone(); – Dans Appartement. Luxe : public Appartement. Luxe clone(); – Dans Appartement. Normal : public Appartement. Normal clone();
Substituabilité La substituabilité comportementale demande qu’il n’y ait pas de comportement d’une instance d’une sous-classe inattendu pour une instance de la classe Appartement public void set. Superficie(double s){superficie=s; } Appartement. Normal public void set. Superficie(double s) { if (s <= 200) super. set. Superficie(s); else System. out. println("Erreur superficie trop grande"); } … main … { Appartement a = new Appartement. Normal("rue des sapins", 1870, 100, 6, 2); a. set. Superficie(250); } L’erreur est inattendue pour un appartement
Constantes • Notion de constante – attribut ou paramètre ou variable locale – initialisé une seule fois – introduit par final
Constante (attribut) public class Personne { private String nom; private final Personne mère; private final int année. Naissance; … }
Constante public class Personne { private String nom; private final Personne mère; private final int année. Naissance; public Personne() { } Ne peut être écrit si on l'appelle, il y a un risque mère et année. Naissance ne soient pas initialisées
Constante public class Personne { private String nom; private final Personne mère; private final int année. Naissance; Pour effectuer une unique initialisation (à la création) public Personne(String nom, Personne mère, int année. Naissance) { this. nom = nom; this. mère = mère; this. année. Naissance = année. Naissance; }
Constante public class Personne { private String nom; private final Personne mère; private final int année. Naissance; public void set. Année. Naissance(int année. Naissance) {this. année. Naissance = année. Naissance; } Ne peut être écrit si on l'appelle, il y a un risque de modifier la valeur de année. Naissance
Constante (paramètre) public (…) affiche. Plus. Petit(int i, int j) { if (i<j) System. out. println(i); else System. out. println(j); }
Constante (paramètre) public (…) affiche. Plus. Petit(int i, int j) { Eviter car i, j passés par valeur if (i<j) j=i; System. out. println(j); } Pour l’empêcher : public (…) affiche. Plus. Petit(final int i, final int j) { ………… }
Variable de classe • Variable globale, partagée par toutes les instances de la classe (et de ses sous-classes) • introduite par static • Les variables locales peuvent aussi être static, mais nous n’étudierons pas leur utilisation dans ce cours
Variable de classe public abstract class Objet. Postal { abstract public double tarif. Base(); } public class Lettre extends Objet. Postal { private static double tarif. Base. Le = 0. 5; public double tarif. Base(){return Lettre. tarif. Base. Le; } } public class Colis extends Objet. Postal { private static double tarif. Base. Co = 2; public double tarif. Base(){return Colis. tarif. Base. Co; } }
Variable de classe public class Lettre extends Objet. Postal { private static double tarif. Base. Le = 0. 5; public double tarif. Base(){return Lettre. tarif. Base. Le; } } • Valeur non enfouie dans le code par opposition à l’écriture avec public double tarif. Base(){return 0. 5; } • Eviter de les initialiser dans un constructeur car elles ne sont pas propres à une instance
Variable de classe public class Lettre extends Objet. Postal { private static double tarif. Base. Le = 0. 5; public double tarif. Base(){return Lettre. tarif. Base. Le; } } public class Colis extends Objet. Postal { private static double tarif. Base. Co = 2; public double tarif. Base(){return Colis. tarif. Base. Co; } } Lettre. tarif. Base. Le 0. 5 Colis. tarif. Base. Co 2
Variable de classe versus d’instance Lettre l 1 = new Lettre("montpellier", "kouk, igloo 2, banquise nord", "345", 0. 2, 0. 005, 1, Type. Urgence. ordinaire); Lettre l 2 = new Lettre( "nîmes", "igloo 17, banquise sud", "7775", 0. 4, 0. 007, 1, Type. Urgence. urgente); l 2 l 1 "montpellier" "kouk, igloo 2, banquise nord" "345" 0. 2 0. 005 1 Type. Urgence. ordinaire Lettre. tarif. Base. Le 0. 5 origine "nîmes" "igloo 17, banquise sud" "7775" 0. 4 0. 007 1 Type. Urgence. urgente Colis. tarif. Base. Co 2 Plusieurs attributs origine (1 par objet), un seul attribut Lettre. tarif. Base. Le un seul attribut Colis. tarif. Base. Co origine
Variable de classe • Peut-on faire ? public class Objet. Postal { private static double tarif. Base; public double tarif. Base(){return Objet. Postal. tarif. Base; } } • Puis donner la valeur dans Lettre et Colis ? • Non: car c’est une unique variable (unique emplacement mémoire) donc elle ne peut pas avoir en même temps 2 valeurs différentes
Constante de classe • attribut de classe qui ne sera initialisé qu’une fois • Final static public class Carre { private double largeur, hauteur; private static final int nombre. Cotes = 4; …. }
Méthode de classe • méthode se rapprochant d’une fonction (paradigme impératif) • pour gérer des attributs static ou pour effectuer des calculs ne se rapportant pas à une instance • définie dans une classe • non héritée • appelée avec le nom de la classe comme receveur (pas this, ni super) • pas de liaison dynamique
Méthode de classe public class Personne { …. private static int nb. Personnes; public static int get. Nb. Personnes() { return nb. Personnes; } public static void set. Nb. Personnes(int nb. Personnes) { Personne. nb. Personnes = nb. Personnes; } public static void main(String[] s) { System. out. println(Personne. get. Nb. Personnes()); }
Méthode de classe (dans l’API) class Collections{ static (…) void sort(List<T> list) …. } … main … Array. List ma. Liste = …; Collections. sort(ma. Liste); class Math{ static double PI; static int max(int a, int b) …. } … main … double pi = Math. PI; …. System. out. println(Math. max(4, 8));
- Transistor bipolaire resumé
- 110 000 110 111 000 111
- Numero niss
- Pfs exemple
- P=f/s
- Pfs graphique
- Calcul poutre bois excel
- Statique appliquée
- Ecart statique
- Principe fondamental de la statique
- L'électricité statique
- Nat statique
- Analyse statique du code
- électricité statique station essence
- Transfert thermique
- L'électricité statique c'est quoi
- étude statique arc-boutement
- Statique
- Routage statique definition
- L'électricité statique
- Bride hydraulique fonctionnement
- Tp poussée d'archimède correction
- Méthode statique équivalente
- L'électricité statique
- Rapport de transformation
- Phet électricité statique
- Igz/v
- Problème de statique
- 327 farenheit to celcius
- Principezinho
- Inf 327
- What is 871 rounded to the nearest ten
- 327 milli emlak genel tebliği
- Xkcd drop table
- What is 15 327 rounded to the nearest ten thousand
- Xkcd 327
- Xkcd 327
- Tying
- Géosciences et dynamique des paysages
- Dynamique du solide
- Principe fondamental de la dynamique
- Inverse dynamique
- Exercice corrigé dynamique de rotation
- Sur la dynamique du transfert
- Cyclothymique
- Type de leadership
- Poussée d'archimède formule
- Dynamique
- Dynamique motivationnelle