L'interface java.lang.Comparable impose un ordre global sur les instances des classes implémentant cette interface.
Une seule méthode est contenue dans l'interface Comparable. Il s'agît de la méthode compareTo() ayant pour fonction de comparer un objet passé en argument à l'instance de classe courante.
public interface Comparable { public int compareTo(Object o); }
L'ordre imposé par cette interface se réfère à l'ordre naturel de la classe et la méthode compareTo() de la classe se réfère également à sa méthode de comparaison naturelle.
Les listes et les tableaux d'objets qui implémentent l'interface Comparable peuvent être respectivement triés automatiquement par les méthodes Collections.sort() et Arrays.sort(). De plus, de tels objets peuvent être utilisés comme clés ou comme éléments dans, respectivement, une collection Map ou Set triée, sans avoir besoin de spécifier un objet Comparator.
import java.util.Arrays; import java.util.Collections; import java.util.List; public class CollectionListe { public static void main(String[] args) { // Video est un classe définie plus bas. Video tableau[] = { new Video("Le jour le plus long", "Ken Annakin", 1962), new Video("Un pont trop loin", "Richard Attenborough", 1977), new Video("Platoon", "Oliver Stone", 1986), new Video("Full metal jacket", "Stanley Kubrik", 1987), new Video("La ligne rouge", "Terrence Malick", 1998), new Video("The patriot", "Roland Emmerich", 2000) }; // ORDRE_DATE est un comparateur défini plus bas. Arrays.sort(tableau, ORDRE_DATE); for(int i = 0; i < tableau.length; i++) System.out.print(tableau[i].toString() + " "); List liste = Arrays.asList(tableau); Collections.sort(liste); System.out.println(liste); } }
L'ordre naturel pour une classe est dit consistant avec equals(), si et seulement si (e1.compareTo((Object)e2) == 0) possède la même valeur booléenne que e1.equals((Object)e2) pour chacun des éléments de cette classe.
Etant donné que des collections triées (SortedSet ou SortedMap) risquent de se comporter anormalement, il est fortement recommandé que l'ordre naturel soit consistant avec equals().
La relation qui définit l'ordre naturel sur une classe donnée est :
{(x, y) tel que x.compareTo((Object)y) <= 0}
Le quotient pour l'ordre total est :
{(x, y) tel que x.compareTo((Object)y) == 0}
Cela suit directement du contrat pour la méthode compareTo(), que le quotient soit une relation d'équivalence sur la classe et que l'ordre naturel soit un ordre global sur cette classe. Lorsque l'ordre naturel d'une classe est dit consistant avec equals(), cela signifie que le quotient de l'ordre naturel est la relation d'équivalence définie par la méthode equals() de cette classe.
{(x, y) tel que x.equals((Object)y)}
Si l'objet spécifié ne peut être comparé à l'objet spécifié, la méthode compareTo() lancera une exception ClassCastException.
La valeur null n'étant pas une instance de classe, une exception NullPointerException sera levée si une tentative de comparaison est tentée.
// provoque une exception boolean res = objet.compareTo(null);
La méthode compareTo() suite à la comparaison de l'objet passé en argument par rapport à l'objet courant, retourne une valeur entière qui indique l'ordre de ces objets.
L'implémenteur doit s'assurer des règles suivantes :
Bien que la dernière règle ne soit pas strictement requise, il est fortement recommandée de l'appliquer.
La notation sgn(expression) désigne la fonction mathématique signum(), laquelle est définie pour retourner les valeurs -1, 0 et 1 pour respectivement toutes les valeurs négatives, nulles et positives renvoyées par l'expression.
Exemple [voir]import java.util.GregorianCalendar; import java.util.Calendar; public class Video implements Comparable { private String titre, realisateur; private int annee; public Video (String titre, String realisateur, int annee){ if (titre == null || realisateur == null) throw new NullPointerException(); this.titre = titre; this.realisateur = realisateur; this.annee = annee; } public String obtenirTitre(){ return this.titre; } public String obtenirRealisateur(){ return this.realisateur; } public int obtenirAnnee(){ return this.annee; } public int compareTo(Object o){ if(!(o instanceof Video)) throw new ClassCastException(); Video v = (Video)o; int comparaison; if((comparaison = titre.compareTo(v.obtenirTitre())) != 0) return comparaison; else if((comparaison = realisateur.compareTo(v.obtenirRealisateur())) != 0) return comparaison; else return (new Integer(annee)).compareTo(new Integer(v.obtenirAnnee())); } public int hashCode(){ return annee * titre.hashCode() + realisateur.hashCode(); } public boolean equals(Object o){ if(!(o instanceof Video)) return false; Video v = (Video)o; return true; } public String toString(){ StringBuffer res = new StringBuffer("["); res.append(titre); res.append(", "); res.append(realisateur); res.append(", "); res.append(annee); return res.append("]").toString(); } } // Classe mettant en oeuvre la classe Video import java.util.Comparator; import java.util.TreeSet; public class CollectionComparable { public static void main(String[] args) { TreeSet t = new TreeSet(); t.add(new Video("Le jour le plus long", "Ken Annakin", 1962)); t.add(new Video("Un pont trop loin", "Richard Attenborough", 1977)); t.add(new Video("Platoon", "Oliver Stone", 1986)); t.add(new Video("Full metal jacket", "Stanley Kubrik", 1987)); t.add(new Video("La ligne rouge", "Terrence Malick", 1998)); t.add(new Video("The patriot", "Roland Emmerich", 2000)); System.out.println("Tri par titre :\n" + t); } } |