classe Object

Transcription

classe Object
Héritage et polymorphisme
Observez les schémas de quelques classes vues. Ils
sont utiles pour comprendre les notions d’héritage
et de polymorphisme.
classe Object
public String toString();
public boolean equals(Object autre);
. . . etc . . .
classe Vector<E> (dérivée de Object)
public String toString();
. . . etc . . .
Number
classe Stack<E>
(Pile, dérivée de Vector)
public Stack();
public E peek();
public E pop();
public E push(E obj);
public boolean empty();
pas de toString() ni de equals()
etc . . .
classe Integer
(déjà vue)
public Integer(int n);
public String toString();
public boolean equals(Object obj);
. . . etc . . .
classe StringTokenizer
public StringTokennizer(String ch);
pas de toString() ni de equals
. . . etc . . .
Object est la super-classe de toutes les classes.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
112
La programmation orientée objet est basée sur trois nouveaux concepts :
- Encapsulation (déjà vu et travaillé dans les travaux pratiques)
- Héritage ( tel père => tel fils et plus!!! )
- Polymorphisme (capacité de se présenter sous plusieurs formes différentes : la
lampe magique d’Aladin???)
Héritage
La POO favorise la réutilisation des classes, des méthodes, du codage. Grâce à l'héritage,
on peut modifier une classe sans avoir à la réécrire complètement :
Pour gérer une pile selon le principe LIFO (Last In First Out : dernière entrée, première
sortie), on n'a pas besoin de casser la tête : la plupart des méthodes existantes dans Vector
nous permettent de traiter une pile.
Stack est une classe où on profite des méthodes existantes de la classe Vector.
Dans les documents de Java, on trouve la description suivante de cette classe :
public class java.util.Stack<E>
extends java.util.Vector<E> {
// constructeur :
public Stack(); // construire une pile VIDE
// méthodes :
public boolean empty() ; // la pile est-elle vide ?
// consulter l'objet au sommet sans le retirer de la pile
public E peek();
// retirer l'objet au sommet et le retourne
public E pop();
// empiler un objet au sommet de la pile
public E push ( E item) ;
// retourne la distance d'un objet vs le sommet
public int search(Object obj);
}
Le mot extends signale que Stack étend (dérive de) Vector . C'est une sous-classe de
Vector.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
113
Terminologie :
Vector est une super-classe de Stack
Vector est une classe de base
Vector est une surclasse
Vector est une classe parente
etc ….
Stack est une sous-classe de Vector
Stack est une classe dérivée de Vector
Stack est une classe étendue de Vector
Stack est une classe enfante de Vector
etc …
Comment écrire la méthode push (empiler) de la sous-classe Stack ?
public Object push( Object item) {
// ajouter l'item à la pile (dans le vecteur!!!)
addElement (item );
// retourner l'item (selon la syntaxe de cette méthode )
return item;
}
Conclusion : on profite (réutilise) la méthode addElement de la classe Vector.
Une version plus logique :
public void push( E item) {
// ajouter l'item à la pile (dans le vecteur!!!)
addElement (E );
}
Comment afficher le contenu d'une pile ???
Notez que la méthode toString() n'existe pas dans Stack. Cependant elle existe dans la
classe Vector. L'affichage le contenu d'une pile n'est pas une action importante de la
gestion d'une pile. Au lieu de perdre le temps de développer une telle méthode, pourquoi
ne pas utiliser celle qui existe dans la super classe Vector?
Supposons qu'une pile contient 7 journées d'une semaine dont on a empilé
successivement les journées "Lundi", "Mardi", …, "Dimanche".
La méthode suivante permet d'afficher le contenu de la pile :
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
114
static void afficher( Stack unePile, String message) {
if ( unePile.empty() )
System.out.println("La pile est vide. Sa taille est " +
unePile.size());
else {
System.out.println("Contenu de la pile " + message + " : ");
System.out.println( unePile );
}
System.out.println();
}
Comme toString() n'esiste pas dans Stack mais elle existe dans Vector.
Java utilise la méthode toString() de la classe Vector pour afficher
le contenu de la pile :
Contenu de la pile apres avoir empile les 7 journees :
[Lundi, Mardi, Mercredi, Jeudi, Vendredi, Samedi, Dimanche]
Conclusion : on profite (réutilise) la méthode toString() de la classe Vector.
Héritage simple : une classe peut hériter d'une seule super-classe
classe Triangle avec 3 côtés (côté1, côté2, côté3)
Triangle rectangle
Triangle isocèle
Triangle équilatéral
(3 côtés égaux)
Un triangle équilatéral est un triangle isocèle.
Un triangle isocèle est aussi un triangle.
etc . . .
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
115
Java permet d'implémenter facilement l'héritage simple.
Ce type d'héritage est fréquent dans les classes prédéfinies de Java:
La seule super classe de Stack est Vector.
La seule super classe de Vector est Object.
Notez qu’une super-classe (exemple Number dans java.lang) peut disposer
de plusieurs sous-classes : Integer, Double, Float, Long.
Héritage multiple:
une classe peut hériter de plus d'une super-classe
Ce concept est permis en C++ mais non en Java. Java utilise la notion de l'interface
(matière vers la fin de session) pour contourner ce problème.
Surdéfinir (surcharger, overloading)
La surdéfinition permet au programmeur de déclarer plusieurs méthodes ou constructeurs
ayant le même nom, mais ayant des paramètres différents ou du genre différent (avec
return, de type void).
On a déjà vu fréquemment des constructeurs sans paramètres, constructeurs avec
paramètres qui portent le même nom (de la classe) :
public Rectangle() { } // constructeur d'un rectangle
public Rectangle(int lo, int la) {. . . } // constructeur avec paramètres
La méthode afficher est aussi fréquemment surdéfinie dans les projets:
public void afficher(int nombre, int nbCol) // afficher un nombre avec tant de colonnes
public void afficher(String nom) // afficher un objet en connaissant son nom
public void afficher(Vector v, String message) // afficher le contenu d'un vecteur …
Redéfinir (overriding):
Avec l'héritage, il est utile, dépendant des besoins, de redéfinir des méthodes existantes
d'une super-classe. C'est le cas des deux méthodes toString() et equals qui sont souvent
redéfinies dans la plupart des sous-classes d'Object .
La méthode toString() est redéfinie dans String, Integer. Par cette raison, l'affichage
suivant fonctionne parfaitement :
String souhait = "Bonne chance!" ;
Vector<Integer> v = new Vector<Integer> ();
v.addElement ( new Integer (23) );
v. addElement ( new Integer (15);
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
116
System.out.println(souhait);
System.out.println("Contenu de v : " + v );
Par contre, toString() n'est pas redéfinie dans StringTokenizer. Java utilise alors la
méthode toString() de la classe Object pour afficher une chaîne décomposable en
mots :
StringTokenizer st = new StringTokenizer( "Bonsoir tout le monde ");
System.out.println("La chaîne est : " + st );
L'affichage est du genre : java.util.StringTokenizer@etc ….
qui n'est pas du tout la chaîne voulue.
Avec String ch1 = "Bonsoir",
ch2 = "bonsoir",
ch3 = "Bonsoir";
on savait que :
ch1.equals(ch2) retourne false (pas le même contenu)
ch1.equals(ch3) retourne true (même contenu).
Les résultats sont parfaits car la méthode equals a été redéfinie dans String.
Avec Integer n1 = new Integer(25),
n2 = new Integer(77),
n3 = new Integer (25);
on a :
n1.equals(n2) retourne false (pas le même contenu)
n1.equals(n3) retourne true (même contenu).
Les résultats sont parfaits car la méthode equals a été redéfinie dans Integer.
Cependant, avec :
StringTokenizer st1 = new StringTokenizer( "Bonsoir"),
st2 = new StringTokenizer( "Bonsoir");
on a :
st1.equals(st2) retourne false (pas le même contenu!)
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
117
Le résultat est erroné car la méthode equals n'a pas été redéfinie dans StringTokenizer
Java utilise alors la méthode equals de la super classe Object qui retourne false quand ce
n’est pas la même référence :
Dans Object, selon une source de Java :
public boolean equals (Object obj) {
return this == obj ;
}
Conclusion: pour utiliser convenablement des méthodes toString, equals,
etc . . . d'une super classe, il est utile de les redéfinir dans la sous-classe.
Remarque: La méthode equals est redéfinie dans Vector dans les dernières versions
de JDK alors qu’elle n’est pas redéfinie dans VJ++.
Avec :
Vector<Integer> v1 = new Vector<Integer>();
v1.addElement ( new Integer (10) );
Vector<Integer> v2 = new Vector<Integer> ();
v2.addElement ( new Integer (10) );
on a :
v1.equals(v2) retourne true (dernières versions de JDK ).
v1.equals(v2) retourne false (sous VJ++)
Exemple de redéfinition des 2 méthodes toString() et equals:
Pour les besoins pédagogiques, les champs longueur et largeur de la classe
Rectangle sont de type int pour l'exemple (en programmation, on ne compare pas
deux réels avec reel1 == reel2, on doit travailler avec un epsilon près. C'est une
notion de la présentation interne des nombres qui n'est pas notre intérêt pour
comprendre l'héritage!).
public class Rectangle
{ private int longueur, largeur;
. . . constructeurs + autres méthodes . . .
public int perimetre() { return 2 * (longueur + largeur) ; }
// redéfinir toString() : conversion d'un rectangle en String
public String toString() {
return "Rectangle : <" + longueur + ", "
+ largeur + ", " + perimetre() + ">\n";
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
118
}
/* redéfinir equals : l'objet courant est-il égal un autre?
Il y a plusieurs manières de programmer equals. C’est un sujet
de réflexion qu’on va aborder vers la fin de session
*/
public boolean equals ( Object autre ) {
Rectangle rect =(Rectangle) autre;
return longueur == rect.longueur &&
largeur == rect.largeur;
}
. . .
}
Polymorphisme :
Le mot polymorphisme est issu d'un mot grec signifiant "qui possède plusieurs formes"
(la lampe magique d'Aladin : Maître, sous quelle forme voulez-vous que je me
transforme?).
En JAVA, le but de polymorphisme est de permettre d'identifier clairement lequel des
champs, lequel des objets, laquelle des méthodes qu'on travaille lors d'une possibilité
de confusion dans leur utilisation.
La redéfinition d'une méthode fait partie de polymorphisme.
Auto-référence avec le mot this (qui fait partie de polymorphisme)
this
En Java,
désigne l'objet courant.
On a déjà vu le constructeur d'un rectangle comme le suivant :
public Rectangle (int lo, int la) {
longueur = lo ;
largeur = la ;
}
L'instruction Rectangle r = new Rectangle(12, 8);
construit un rectangle r de longueur 12 et de largeur 8. On n'a pas de problème.
Le programmeur généralise l'écriture de ce constructeur comme le suivant :
public Rectangle (int longueur, int largeur) {
longueur = longueur ;
largeur = largeur ;
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
119
}
en espérant que Java comprenne que longueur à gauche de l'affectation est la longueur
du rectangle courant (à créer) tandis que celle à droite de l'affectation est un paramètre.
Malheureusement, Java réagit très mal à cette écriture.
Il faut alors utiliser l'auto référence this qui représente l'objet courant :
public Rectangle (int longueur, int largeur) {
this.longueur = longueur ;
this.largeur = largeur ;
}
Exemple 2 sur this : retourner l'objet courant:
Supposons que la classe Rectangle dispose déjà d'une méthode permettant de
calculer et retourner le périmètre :
public int perimetre() { return 2 * (longueur + largeur) ; }
Écrivez une méthode permettant de déterminer et de retourner le rectangle ayant le plus
grand paramètre entre l'objet courant et un autre rectangle.
public Rectangle plusGrandPerimetre (Rectangle autre) {
if ( autre.perimetre() > perimetre() )
return autre ;
else
return this ;
}
Exemple 3 sur this : appel d’un constructeur dans la même classe:
Supposons que la classe Rectangle dispose déjà du constructeur à 2 paramètres, par
exemple :
public Rectangle (int lo, int la) {
longueur = lo ;
largeur = la ;
}
Dans la même classe Rectangle, on peut avoir des constructeurs suivants :
// par défaut : longueur et largeur valent zéro
public Rectangle () {
this (0, 0);
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
120
}
// un rectangle où longueur = largeur = cote (un carré)
public Rectangle (int cote) {
this (cote, cote);
}
// un rectangle construit à partir d'un autre rectangle
public Rectangle (Rectangle autre) {
this (autre.longueur, autre.largeur);
}
Résumé sur this :
Il y a trois formes d'utilisation de this :
1. this.champ => champ de donné de l'objet courant
2. this( . . .) => première instruction dans un constructeur pour appeler
un autre constructeur de la même classe
3. return this ; => retourner l'objet courant
Le mot clé super (venant de super classe)
(fait partie aussi de la polymorphisme)
On utilise souvent le mot super dans les 2 situations suivantes :
1. première instruction d'un constructeur d'une sous-classe pour appeler
un constructeur approprié de la super classe;
2. appel d'une méthode de la super classe quand la sous-classe dispose
d'une méthode portant le même nom.
Exemple sur this et super:
// classe RectangleEntier
public class RectangleEntier
{
private int longueur ; // non accessible dans les sous-classes
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
121
/* champ protégé :
- accessible dans les sous-classes
- accessible aussi des autres classes du même paquet
*/
protected int largeur ;
// revoir le this
public RectangleEntier(int longueur, int largeur) {
this.longueur = longueur;
this.largeur = largeur ;
}
// revoir le this
public RectangleEntier() {
this (10, 8); // valeurs par défaut
}
// revoir le this
public RectangleEntier(int cote) {
this (cote, cote);
}
/* une parmi plusieurs manières de redéfinir equals(...) de Object
Il y a des points pour, points contre d'une manière à l'autre
On va aborder vers la fin de la session
*/
public boolean equals(Object autre) {
if (this == autre)
return true;
if (this.getClass() == ((RectangleEntier) autre).getClass()) {
return longueur == ((RectangleEntier) autre).longueur &&
largeur == ((RectangleEntier) autre).largeur;
}
return false;
}
// redéfinition de toString()
public String toString() {
return "<longueur: " + longueur + ", largeur : " + largeur
+ ", perimetre: " + perimetre() + ">\n";
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
122
}
public int perimetre() {
return 2 * (longueur+largeur);
}
public int getLongueur() { return longueur; }
}
/* classe RectangleColore dérivée de RectangleEntier
exemple sur super :
- appel d'un constructeur d'une super-classe
- appel d'une méthode d'une super-classe
*/
public class RectangleColore
extends RectangleEntier
{
private int couleurInterieure,
couleurBordure;
public RectangleColore(int lo, int la, int cI, int cB) {
/* - appel d'un constructeur d'une super-classe
il faut être première instruction
*/
super(lo, la);
couleurInterieure = cI;
couleurBordure = cB;
}
public int surface() {
// accès au champ PROTÉGÉ largeur est faisable
return getLongueur() * largeur;
}
public String toString() {
// appel d'une méthode d'une super-classe
return super.toString() + "<surface: " + surface() +
", coul. interieure : " + couleurInterieure +
", coul. bordure : " + couleurBordure + ">\n";
}
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
123
}
// classe CarreVisible dérivée de RectangleEntier
public class CarreVisible
extends RectangleEntier
{
private boolean estVisible ;
public CarreVisible(int cote, boolean estVisible) {
super(cote);
this.estVisible = estVisible;
}
public double diagonale() {
return getLongueur() * Math.sqrt(2.0);
}
public String toString() {
if (estVisible)
return "\nJe suis un carre visible : " +
super.toString() + "<diagonale : " + diagonale() + ">\n";
else
return "\nJe ne suis pas un carre visible!\n";
}
}
/**
* Fichier TestSuper.java
*
*
super classe RectangleEntier
*
*
/
\
*
classe dérivée
classe dérivée
*
RectangleColore CarreVisible
*
* Tester le bon fonctionnement de this, super, redéfinition des méthodes
*/
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
124
public class TestSuper
{
public static void main (String[] args)
{
RectangleEntier re1 = new RectangleEntier(12,10);
System.out.println("Infos de re1 : " + re1);
RectangleEntier re2 = new RectangleEntier(9);
System.out.println("Infos de re2 : " + re2);
System.out.println("re1.equals(re2) vaut : " + re1.equals(re2));
RectangleColore rc1 = new RectangleColore(12,10, 5, 12);
System.out.println("Infos de rc1 : " + rc1);
System.out.println("re1.equals(rc1) vaut : " + re1.equals(rc1));
CarreVisible cv1 = new CarreVisible(10, true);
System.out.println(cv1);
CarreVisible cv2 = new CarreVisible(7, false);
System.out.println(cv2);
}
}
/* Exécution:
Infos de re1 : <longueur: 12, largeur : 10, perimetre: 44>
Infos de re2 : <longueur: 9, largeur : 9, perimetre: 36>
re1.equals(re2) vaut : false
Infos de rc1 : <longueur: 12, largeur : 10, perimetre: 44>
<surface: 120, coul. interieure : 5, coul. bordure : 12>
re1.equals(rc1) vaut : true
Je suis un carre visible : <longueur: 10, largeur : 10, perimetre: 40>
<diagonale : 14.142135623730951>
Je ne suis pas un carre visible!
*/
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
125
Classe Stack dérivée de Vector :
classe Object
public String toString();
public boolean equals(Object autre);
. . . etc . . .
Classe Vector<E>
void addElement(E obj)
Adds the specified component to the end of this vector, increasing
its size by one.
E elementAt(int index)
Returns the component at the specified index.
boolean equals(Object o)
Compares the specified Object with this Vector for equality.
int indexOf(Object elem)
Searches for the first occurence of the given argument, testing for
equality using the equals method.
void insertElementAt(E obj, int index)
Inserts the specified object as a component in this vector at the
specified index.
boolean isEmpty()
Tests if this vector has no components.
boolean removeElement(Object obj)
Removes the first (lowest-indexed) occurrence of the argument from
this vector.
int size()
Returns the number of components in this vector.
String toString()
Returns a string representation of this Vector, containing the String
representation of each element.
etc …
. . . autres méthodes ...
Sous-classe Stack de Vector
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
126
La classe Stack (une pile) qui est dérivée de la classe Vector. Sur le site de
Sun, on y trouve :
public class Stack
extends Vector
=> Stack est étendue (dérivée) de la classe Vector.
“The Stack class represents a last-in-first-out (LIFO) stack of objects. It extends class
Vector with five operations that allow a vector to be treated as a stack.” :
La classe Stack représente le concept LIFO (dernière entrée, première sortie : comme une
pile d’assiettes). Elle est étendue de la classe Vector avec 5 opérations permettant de
gérer une pile.
Constructor Summary : résumé du constructeur
Stack()
Creates an empty Stack : création d’une pile VIDE (pas d’éléments)
Method Summary : résumé des méthodes
boolean empty()
Tests if this stack is empty :
tester si Oui ou Non la pile soit vide (empty).
E peek()
Looks at the object at the top of this stack without removing it from the stack.
Consulter l’objet au sommet de la pile sans le retirer.
E pop()
Removes the object at the top of this stack and returns that object as the value
of this function.
Supprimer (retirer) l’objet au sommet de la pile et retourne cet objet (de la
classe Object) comme résultat de la méthode.
E push(E item)
Pushes an item onto the top of this stack.
Empiler (ajouter au sommet) d’un objet et retourner l’objet ajouté comme
résultat de la méthode.
int search(Object o)
Returns the 1-based position where an object is on this stack.
Retourner un indice pour l’objet o trouvé dans la pile ou -1 si non trouvé.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
127
Method Detail : détails de ces méthodes
push
public E push(E item)
Pushes an item onto the top of this stack. This has exactly the same effect as:
addElement(item)
empiler un item (un Élément) au sommet de la pile. Elle a le même
effet que la méthode de sa super-classe : addElement(item)
Parameters:
item - the item to be pushed onto this stack.
l’item à ajouter au sommet de la pile
Returns:
the item argument (l’argument item)
l’argument de la méthode
pop
public E pop()
Removes the object at the top of this stack and returns that object as the value of
this function.
Supprimer (retirer) l’élément au sommet de la pile et retourne cet objet (de
la classe Object) comme résultat de la méthode.
Returns:
The object at the top of this stack (the last item of the Vector object).
L’objet au sommet de la pile (qui est le dernier élement du vecteur).
peek
public E peek()
Looks at the object at the top of this stack without removing it from the stack.
Consulter l’objet au sommet de la pile sans le retirer.
Returns:
the object at the top of this stack (the last item of the Vector object).
L’objet au sommet de la pile (qui est le dernier element du vecteur).
empty
public boolean empty()
Tests if this stack is empty.
Tester si Oui ou Non la pile soit vide (empty).
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
128
Returns:
true if and only if this stack contains no items; false otherwise.
Vrai si et seulement si la pile ne contient aucun element, faux autrement.
search
public int search(Object o)
Returns the 1-based position where an object is on this stack. If the object o
occurs as an item in this stack, this method returns the distance from the top of the
stack of the occurrence nearest the top of the stack; the topmost item on the stack
is considered to be at distance 1. The equals method is used to compare o to
the items in this stack.
(Traduction « libre » : la méthode retourne – 1 si l’objet est non trouvé et la
distance vs le sommet si trouvé. Notez que la distance du sommet vaut 1 (ce
n’est pas l’indice 0). Cette recherche est basée sur la comparaison du contenu
utilisant la redéfinition de la méthode equals).
Ainsi, pour vérifier si un objet d’une classe C fait partie d’une pile, il faut
s’assurer que la méthode equals est redéfinie dans la classe C)
Parameters:
o - the desired object.
Returns:
the 1-based position from the top of the stack where the object is located; the
return value -1 indicates that the object is not on the stack.
Voir quelques exemples aux prochaines pages pour comprendre la méthode de recherche
search.
Observations à travers ces schémas :
les méthodes toString() et equals() ont été redéfinies dans la super-classe
Vector mais non dans Stack.
Ainsi :
- l’affichage du contenu d’une pile (classe Stack) utilisera la méthode
toString() de Vector
- la comparaison du contenu de deux vecteurs utilisera la méthode equals
redéfinie dans Vector. Cette méthode est de nouveau basée sur la redéfinition
de equals dans la classe contenant les objets d’une pile, d’un vecteur.
- la redéfinition de equals permet d’utiliser correctement la méthode search.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
129
Exemple 1 sur la classe Stack :
/* Fichier Pile1.java
Exemple d'utilisation de la sous-classe Stack (notion de pile)
dérivée de la classe Vector
*/
import java.util.*;
public class Pile1
{
public static void main (String[] args)
{String[] pourTester = { "Bonsoir", "monde", "tout", "pile", "file",
"le"};
Stack<String> pile = new Stack<String>(); // construire une pile
VIDE
if (pile.empty()) // si la pile est VIDE
System.out.println("La pile est vide au debut ");
// empiler : ajouter au sommet de la pile seulement 5 des 6 chaînes
pile.push( pourTester[1]);
pile.push( pourTester[5]);
pile.push( pourTester[2]);
pile.push( pourTester[0]);
pile.push( pourTester[4]);
// utiliser toString() de la super-classe Vector
System.out.println("Le contenu de la pile :\n" + pile );
System.out.println("\n");
// peek() => Consulter (sans retirer) le sommet
System.out.println("Au sommet de la pile, on trouve : " +
pile.peek());
// pop() : retirer et retourner le sommet :
System.out.print("On retire maintenant cette chaine de la pile ");
String auSommet = pile.pop();
System.out.println("qui est " + auSommet);
// afficher le contenu final de la pile :
System.out.println("\nLe contenu final de la pile :\n" + pile);
// la recherche :
System.out.println("Indices retournes par la methode search pour"
+ " rechercher ");
for (int i = 0; i < pourTester.length ; i++)
System.out.println( pourTester[i] + " : " +
pile.search(pourTester[i]));
System.out.println("\n\nAu revoir!");
}
}
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
130
/* Exécution:
La pile est vide au debut
Le contenu de la pile :
[monde, le, tout, Bonsoir, file]
Au sommet de la pile, on trouve : file
On retire maintenant cette chaine de la pile qui est file
Le contenu final de la pile :
[monde, le, tout, Bonsoir]
Indices retournes par la methode search pour rechercher
Bonsoir : 1
monde : 4
tout : 2
pile : -1
file : -1
le : 3
Au revoir!
*/
Exercice :
Programmez vous-même la classe Pile qui joue le même rôle que la classe Stack.
Tester le bon fonctionnement de votre classe Pile avec :
a) la création de divi100 : la pile des diviseurs de 100. On affiche son contenu.
b) la création de divi450 : la pile des diviseurs de 450. On affiche son contenu.
c) la création et l’affichage de diviCommun : la pile des diviseurs communs de 100
et de 450.
Conseils :
Notez que Pile est dérivée de Vector. On devrait alors d’importer la classe Vector du
paquet java.util et on a le droit d’utiliser des méthodes disponibles dans la classe Vector.
Une solution possible :
/**
*
Programmer soi-même Stack.java
*
On ne traite pas les exceptions au niveau IFT 1170
*
(C'est une des matières du IFT 1176)
*
*/
import java.util.*;
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
131
public class Pile<E>
extends Vector<E>
{
/**
*
Programmer soi-même Stack.java
*
On ne traite pas les exceptions au niveau IFT 1170
*
(C'est une des matières du IFT 1176)
*
*/
import java.util.*;
class Pile<E>
extends Vector<E>
{
// comme empty()
public boolean estVide() {
return size() == 0;
}
// comme push(E item)
public void empiler( E item) {
addElement (item);
}
// comme peek()
public E consulterSommet() {
return elementAt( size()-1 );
}
// comme pop()
public E depiler() {
E auSommet = elementAt( size() - 1 );
removeElementAt (size() - 1 );
return auSommet;
}
// comme search(Object obj)
public int recherche( Object obj) {
if (
lastIndexOf (obj) > - 1 )
return size() - lastIndexOf (obj);
else
return - 1;
}
}
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
132
/**
* Fichiers Pile.java (à peu près comme Stack.java)
*
Pile2.java : tester la classe Pile.java
*/
public class Pile2
{
// création de la pile des diviseurs d'un nombre
static Pile<Integer> creerPile(int nombre)
{ Pile<Integer> diviNombre = new Pile<Integer>();
for (int candidat = 1 ; candidat <= nombre ; candidat++)
if ( nombre % candidat == 0 )
diviNombre.empiler( candidat );
return diviNombre;
}
// affichage du contenu d'une pile avec message
static void afficher(Pile<Integer> p, String message) {
System.out.print("La pile des diviseurs " + message );
if (p.estVide())
System.out.println(" est VIDE");
else
System.out.println(" :\n" + p);
System.out.println();
}
// Cette méthode foncionne avec n'importe quel objet :
static boolean faitPartie( Object obj, Pile<Integer> unePile ) {
for (int i = 0 ; i < unePile.size() ; i++)
if ( obj.equals( unePile.elementAt(i)) )
return true;
return false;
}
// une solution possible sans utiliser la méthode search
static Pile<Integer> creerPile( Pile<Integer> pile1,
Pile<Integer> pile2) {
Pile<Integer> commune = new Pile<Integer>();
for (int i = 0 ; i < pile1.size() ; i++)
if ( faitPartie( pile1.elementAt(i), pile2 ))
commune.empiler( pile1.elementAt(i) );
return commune;
}
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
133
public static void main (String[] args)
{
final int NOMBRE1 = 100,
NOMBRE2 = 450;
Pile<Integer> diviN1 = creerPile(NOMBRE1),
diviN2 = creerPile(NOMBRE2);
afficher(diviN1, "de " + NOMBRE1);
afficher(diviN2, "de " + NOMBRE2);
Pile<Integer> diviN1N2 = creerPile(diviN1, diviN2);
afficher(diviN1N2, "communs de " + NOMBRE1 +
" et " + NOMBRE2);
}
}
/* Exécution:
La pile des diviseurs de 100 :
[1, 2, 4, 5, 10, 20, 25, 50, 100]
La pile des diviseurs de 450 :
[1, 2, 3, 5, 6, 9, 10, 15, 18, 25, 30, 45, 50, 75, 90, 150, 225, 450]
La pile des diviseurs communs de 100 et 450 :
[1, 2, 5, 10, 25, 50]
*/
Remarques sur la redéfinition de toString() et equals() :
A) Cas d’une classe où ces deux méthodes sont redéfinies : Integer
Constrctor Summary : résumé des 2 constructeurs
Integer(int value)
Constructs a newly allocated Integer object that
represents the specified int value.
Integer(String s)
Constructs a newly allocated Integer object that
represents the int value indicated by the String parameter.
Method Summary : quelques méthodes dont la redéfinition de ….
double doubleValue()
Returns the value of this Integer as a double.
boolean equals(Object obj)
Compares this object to the specified object.
int intValue()
Returns the value of this Integer as an int.
long longValue()
Returns the value of this Integer as a long.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
134
static int parseInt(String s)
Parses the string argument as a signed decimal integer.
short shortValue()
Returns the value of this Integer as a short.
String toString()
Returns a String object representing this Integer's value.
L’affichage du contenu d’une pile des « Integer », d’un
« Integer » avec System.out.print fonctionne très bien.
les méthodes relatives à la recherche seront basées sur
equals qui a été redéfinie : Java va chercherv selon le
vecteur des
De plus, toutes
la fonction
contenu.
B) Cas d’une classe que ces deux méthodes ne sont pas du tout redéfinies :
StringTokenizer
La classe
(chaîne decomposable en mots) du paquet
Java.util (le même pour Vector et Stack).
java.lang.Object
|
+-java.util.StringTokenizer
Constructor Summary : quelques constructeurs
StringTokenizer(String str)
Constructs a string tokenizer for the specified string.
StringTokenizer(String str, String delim)
Constructs a string tokenizer for the specified string.
Method Summary
int countTokens()
Calculates the number of times that this tokenizer's nextToken method
can be called before it generates an exception.
boolean hasMoreElements()
Returns the same value as the hasMoreTokens method.
boolean hasMoreTokens()
Tests if there are more tokens available from this tokenizer's string.
Object nextElement()
Returns the same value as the nextToken method, except that its
declared return value is Object rather than String.
String nextToken()
Returns the next token from this string tokenizer.
String nextToken(String delim)
Returns the next token in this string tokenizer's string.
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
135
L’exemple suivante démontre le non fonctionnement de l’affichage et de la recherche.
/**
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*
*/
Par LVN pour IFT 1170 (Révisé par MR)
Classes :
Employe dont la méthode equals est redéfinie
Pile3 : mes commentaires sur la recherche
d'un élément (d'un objet) dans 1 vecteur,
dans une pile
Conclusions importance :
- Dans une classe dont la méthode equals n'est
pas du tout redéfinie (exemple : StringTokenizer)
les méthodes de recherche pré-implémentées (search,
indexOf, contains, ...) ne donnent pas de bons résultats
- Pour utiliser correctement la recherche :
. s'assurer que equals a été redéfinie (Integer, String, ...)
. ou redéfinir nous-même cette méthode (exemple dans Employe
de cet exemple)
import java.util.*;
class Employe
{ private String NAS;
private int age;
public Employe(String NAS, int age) {
this.NAS = NAS;
this.age = age;
}
public String toString() {
return "NAS : " + NAS + " et age = " + age + " ans\n";
}
public boolean equals (Object autre) {
Employe emp = (Employe) autre;
return NAS.equals(emp.NAS) ;
}
}
public class Pile3
{ static Stack<String> creer(String ch1, String ch2, String ch3, String
ch4) {
Stack<String> p = new Stack<String>();
p.push(ch1);
p.push(ch2);
p.push(ch3);
p.push(ch4);
return p;
}
/* Pas de type déclaré pour les éléments des Stack passées en
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
136
* paramètres car la méthodes sera appelée avec des Stack contenant
* des éléments de types différents à chaque appel.
*/
static void afficher(Stack pile, String message) {
if (pile.empty())
System.out.println("La pile " + message + " est VIDE\n");
else
System.out.println("Contenu de la pile " + message +
":\n" +pile );
}
static Stack<StringTokenizer> creerMots(String ch1, String ch2,
String ch3, String ch4) {
Stack<StringTokenizer> p = new Stack<StringTokenizer>();
p.push(new StringTokenizer(ch1));
p.push(new StringTokenizer(ch2));
p.push(new StringTokenizer(ch3));
p.push(new StringTokenizer(ch4));
return p;
}
/* Pas de type déclaré pour les éléments des Stack passées en
* paramètres pour la même raison que pour afficher.
*/
static Stack commune(Stack a, Stack b) {
Stack<Object> c = new Stack<Object>();
for (int i = 0; i < a.size() ; i++)
if ( b.search(a.elementAt(i)) > -1 )
c.push(a.elementAt(i));
return c;
}
static void demo1Search(){
System.out.println("Premiere demonstration\n");
Stack<String> pile1 = creer("Bonsoir", "tout", "le", "monde"),
pile2 = creer("Bonjour", "le", "monde", " de Java");
afficher(pile1, " # 1 ");
afficher(pile2, " # 2 ");
afficher( commune(pile1, pile2),
" commune de pile # 1 et pile # 2 ");
}
static void afficher(StringTokenizer chaine) {
while (chaine.hasMoreElements())
System.out.print(chaine.nextElement() + " ");
}
static void afficher(String message, Stack<StringTokenizer> pile )
{
if (pile.empty())
System.out.println("La pile " + message + " est VIDE");
else
{
System.out.println("Contenu de la pile " + message +":\n");
for (int i = 0 ; i < pile.size() ; i++) {
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
137
StringTokenizer chaine = pile.elementAt(i);
afficher(chaine);
System.out.print(" ");
}
System.out.println();
}
}
static void demo2Search(){
System.out.println("\nDeuxieme demonstration\n");
Stack<StringTokenizer> pile1 =
creerMots("Bonsoir", "tout", "le", "monde"),
pile2 = creerMots("Bonjour", "le", "monde", " de Java");
afficher(pile1, " # 1 ");
afficher(pile2, " # 2 ");
afficher( commune(pile1,pile2),
" commune de pile # 1 et pile # 2 ");
afficher( " # 1 ", pile1);
afficher( " # 2 ", pile2);
afficher( commune(pile1, pile2),
" commune de pile # 1 et pile # 2 ");
}
static void demo3Search(){
System.out.println("\nTroisieme demonstration\n");
Stack<Employe> employe = new Stack<Employe>();
employe.push( new Employe("123 456 789", 25) );
employe.push( new Employe("111 222 333", 44 ));
employe.push( new Employe("456 987 555", 30 ));
System.out.println("Pile des employes :\n" + employe);
Employe aChercher = new Employe("456 987 555", 30 );
System.out.println("\nLa recherche de " + aChercher);
System.out.println("1. avec search
: " +
employe.search(aChercher));
System.out.println("2. avec indexOf
: " +
employe.indexOf(aChercher));
System.out.println("3. avec lastIndexOf : " +
employe.lastIndexOf(aChercher));
System.out.println("4. avec contains
: " +
employe.contains(aChercher));
}
public static void main (String[] args)
{
demo1Search();
demo2Search();
demo3Search();
}
}
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
138
/* Exécution:
Premiere demonstration
Contenu de la pile # 1 :
[Bonsoir, tout, le, monde]
Contenu de la pile # 2 :
[Bonjour, le, monde, de Java]
Contenu de la pile commune de pile # 1 et pile # 2 :
[le, monde]
Deuxieme demonstration
Contenu de la pile # 1 :
[java.util.StringTokenizer@16, java.util.StringTokenizer@19,
java.util.StringTok
enizer@1c, java.util.StringTokenizer@1f]
Contenu de la pile # 2 :
[java.util.StringTokenizer@24, java.util.StringTokenizer@27,
java.util.StringTok
enizer@2a, java.util.StringTokenizer@2d]
La pile commune de pile # 1 et pile # 2 est VIDE
Contenu de la pile
# 1 :
Bonsoir tout le monde
Contenu de la pile # 2 :
Bonjour
La pile
le monde de Java
commune de pile # 1 et pile # 2
est VIDE
Troisieme demonstration
Pile des employes :
[NAS : 123 456 789 et age = 25 ans
, NAS : 111 222 333 et age = 44 ans
, NAS : 456 987 555 et age = 30 ans
]
La recherche de NAS : 456 987 555 et age = 30 ans
1.
2.
3.
4.
avec
avec
avec
avec
search
indexOf
lastIndexOf
contains
:
:
:
:
1
2
2
true
*/
IFT 1170, été 2009
Chapitre 8 : Héritage simple et polymorphisme
139

Documents pareils