- this pour accéder à un membre (masqué par une variable locale) au sein de la classe
Voir la présentation ici.
Autre exemple : la méthode setX() de la classe MobilePoint.
Première possibilité : on donne un nom différent (ord) au membre de la classe.
public class MobilePoint
{
public void setX (int ord)
{
x = ord;
}
}
Deuxième possibilité : nom identique et utilisation de this
public class MobilePoint
{
public void setX (int x)
{
this.x = x;
// this.x : membre (hérité) de la classe
// x : argument de la méthode
}
}
Voir aussi : chapitre 6, sections 9.5.1 et 9.5.1 du livre "Programmer en Java".
- super pour accéder à une méthode de la classe mère (masquée par la redéfinition de cette méthode)
de la même manière qu'une variable locale (e.g. l'argument d'une méthode)
peut masquer la visibilité d'un membre d'une classe,
une méthode redéfinie dans une classe masque la visibilité de la méthode de même signature de la classe mère.
Revoir le transparent 6 de la présentation de la séance 4.
On crée une classe HTMLToken qui étend Token et qui dispose d'un membre "fontFamily"
destiné à recevoir un nom de famille de police (Times, Arial, Verdana, etc.).
On veut que l'invocation de toString () sur un objet de cette classe renvoie une chaîne du type
<span style="font-family: Arial">V:lemmatiser</span>
Une solution possible est :
public class Token
{
private String wordForm;
private String lemma;
private String POS;
// etc.
public String toString ()
{
return getPOS() + ":" + getLemma();
}
}
public class TokenHTML extends Token
{
private String fontFamily;
public String toString ()
{
return "<span style='font-family:" + fontFamily
+ "'>"
+ getPOS() + ":" + getWordForm()
+ "</span>";
}
}
Mais on réimplémente dans TokenHTML ce que fait la méthode toString() de Token.
On aimerait, dans la méthode toString() de TokenHTML, invoquer celle de Token.
Mais si on écrit dans TokenHTML
// methode toString de la classe TokenHTML
public String toString ()
{
return "<span style='font-family:" + fontFamily
+ "'>"
+ toString ()
+ "</span>";
}
la méthode toString () de TokenHTML s'appelle elle-même récursivement, ce qui produit une boucle infinie.
La solution est d'utiliser le mot-clé super pour invoquer la méthode de la super-classe :
// methode toString de la classe TokenHTML
public String toString ()
{
return "<span style='font-family:" + fontFamily
+ "'>"
+ super.toString () // invocation de la méthode toString () de la classe mère (Token)
+ "</span>";
}
Voir aussi : chapitre 6, sections 6.8 (le mot-clé super) du livre "Programmer en Java".
- this() comme constructeur
Comme nous l'avons vu, on peut définir plusieurs constructeurs dans une même classe.
Par exemple, dans la classe Segment, on peut avoir les deux constructeurs suivants :
public Segment (MobilePoint endPoint1, MobilePoint endPoint2)
{
this.endPoint1 = endPoint1;
this.endPoint2 = endPoint2;
}
public Segment (MobilePoint endPoint1, MobilePoint endPoint2, String objName)
{
this (endPoint1, endPoint2);
setObjName(objName);
}
Ces deux constructeurs permettent de créer des segments en passant deux instances de MobilePoint
qui constitueront les extrémités du segment, et en argument facultatif le bom à donner au segment créé :
MobilePoint mp1 = new MobilePoint(2, 5);
MobilePoint mp2 = new MobilePoint(3, -2);
MobilePoint mp3 = new MobilePoint(0, 5);
MobilePoint mp4 = new MobilePoint(-7, -2);
Segment anonymousSeg1 = new Segment (mp1, mp2);
Segment seg2 = new Segment (mp1, mp2, "Segm2");
Mais dans le deuxième constructeur, on duplique le travail réalisé dans le premier.
Ici, il s'agit seulement de deux affectations,
mais on peut imaginer une implémentation qui réalise d'autres tâches lors de la création d'un objet géométrique
(e.g. écriture dans un log d'une trace de cette création, affichage graphique dans une fenêtre dédiée, etc.)
que l'on ne veut pas dupliquer dans les différents constructeurs.
Il existe une solution pour invoquer un constructeur depuis un constructeur de la même classe : this (params);
public Segment (MobilePoint endPoint1, MobilePoint endPoint2)
{
this.endPoint1 = endPoint1;
this.endPoint2 = endPoint2;
Date currentDate = new Date ();
System.out.println ("Date " + currentDate.toString () + " - création du segment " + toString ());
// affichage du segment dans une fenêtre graphique, etc.
}
public Segment (MobilePoint endPoint1, MobilePoint endPoint2, String objName)
{
this (endPoint1, endPoint2); // invocation du constructeur qui prend en argument deux instances de MobilePoint
setObjName(objName); // implémentation spécifique à ce constructeur
}
Il est bien-sûr également possible d'invoquer un constructeur sans argument :
public Segment ()
{
// création d'un segment de longueur nulle positionné à l'origine du repère
setEndPoint1 (new MobilePoint(0, 0));
setEndPoint2 (new MobilePoint(0, 0));
}
public Segment (String objName)
{
this (); // appel du constructeur sans argument (ci-dessus)
setObjName(objName);
}
Dans tous les cas, l'appel au constructeur this() doit être la première instuction du constructeur courant.
- invocation d'un constructeur de la classe mère : super()
De la même manière que dans un constructeur, on peut invoquer un constructeur de la même classe avec this(),
on peut invoquer un constructeur de la classe mère avec super().
Par exemple, si des constucteurs sont déjà définis dans la classe Point,
pour initialiser les coordonnées soit avec des valeurs par défaut, soit avec des valeurs passées en argument,
on ne devrait pas dupliquer le traitement correspondant dans la classe dérivée MobilePoint :
public class Point extends GeomObject
{
public int x; // abs
public int y; // ord
public Point ()
{
// initialisation par defaut
x = 0;
y = 0;
}
public Point (int x, int y)
{
this.x = x;
this.y = y;
}
}
public class MobilePoint extends Point
{
public MobilePoint ()
{
setX(0);
setY(0);
} // MobilePoint ()
public MobilePoint (int x, int y)
{
setX(x);
setY(y);
} // MobilePoint ()
public MobilePoint (int x, int y, String objName)
{
this(x, y);
setObjName(objName);
} // MobilePoint ()
public MobilePoint (String objName)
{
this ();
setObjName(objName);
} // MobilePoint ()
Les affectations dans les deux premiers constructeurs de MobilePoint sont des redites
de celles effectuées dans les constructeurs de la classe Point.
Les traitements correspondants ne sont pas spécifiques à MobilePoint,
ils concernent plus généralement la classe Point.
Par ailleurs, si l'on souhaite changer le comportement de ces classes
lorsqu'on construit un point sans spécifier de coordonnées initiales,
il faut modifier le traitement dans le constructeur par défaut de la classe Point (dont dérive également FixedPoint)
ET de la classe MobilePoint.
Une solution consiste à n'effectuer que les affectations (et autres traitements éventuels qui concernent toutes les sortes de points, i.e. les traitements qui ne sont spécifiques ni aux point fixes ni aux points mobiles)
dans la classe mère Point et à invoquer les constructeurs de la classe mère dans les constructeurs des classes dérivées.
public class MobilePoint extends Point
{
public MobilePoint ()
{
super (); // traitements par défaut délégués à la classe mère
} // MobilePoint ()
public MobilePoint (int x, int y)
{
/*
* appel au constructeur de la classe mère qui prend
* les coordonnées en arguments
* (et qui saura quoi en faire)
*/
super (x, y);
} // MobilePoint ()
public MobilePoint (int x, int y, String objName)
{
this(x, y);
setObjName(objName);
} // MobilePoint ()
public MobilePoint (String objName)
{
this (); // appel du constructeur par defaut pour positionner x et y a (0, 0)
setObjName(objName);
} // MobilePoint ()
Dans les deux derniers constructeurs, on maintient l'appel aux autres constructeurs de la classe MobilePoint via this().
Eux-même invoquent les constructeurs de la classe mère via super().
Classes Point, FixedPoint et MobilePoint modifiées
[ Mention légale ]