Pourquoi Java est-il Comparable
utilisé? Pourquoi quelqu'un implémenterait-il Comparable
dans une classe? Qu'est-ce qu'un exemple concret où vous devez mettre en œuvre comparable?
Pourquoi Java est-il Comparable
utilisé? Pourquoi quelqu'un implémenterait-il Comparable
dans une classe? Qu'est-ce qu'un exemple concret où vous devez mettre en œuvre comparable?
Réponses:
Voici un échantillon réel. Notez que String
implémente également Comparable
.
class Author implements Comparable<Author>{
String firstName;
String lastName;
@Override
public int compareTo(Author other){
// compareTo should return < 0 if this is supposed to be
// less than other, > 0 if this is supposed to be greater than
// other and 0 if they are supposed to be equal
int last = this.lastName.compareTo(other.lastName);
return last == 0 ? this.firstName.compareTo(other.firstName) : last;
}
}
plus tard..
/**
* List the authors. Sort them by name so it will look good.
*/
public List<Author> listAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
Collections.sort(authors);
return authors;
}
/**
* List unique authors. Sort them by name so it will look good.
*/
public SortedSet<Author> listUniqueAuthors(){
List<Author> authors = readAuthorsFromFileOrSomething();
return new TreeSet<Author>(authors);
}
last
?
Comparable définit un ordre naturel. Cela signifie que vous le définissez quand un objet doit être considéré comme "inférieur à" ou "supérieur à".
Supposons que vous ayez un tas d'entiers et que vous vouliez les trier. C'est assez facile, mettez-les simplement dans une collection triée, non?
TreeSet<Integer> m = new TreeSet<Integer>();
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted
Mais maintenant supposons que j'ai un objet personnalisé, où le tri a un sens pour moi, mais n'est pas défini. Disons que j'ai des données représentant les districts par code postal avec la densité de population, et je veux les trier par densité:
public class District {
String zipcode;
Double populationDensity;
}
Maintenant, le moyen le plus simple de les trier est de les définir avec un ordre naturel en implémentant Comparable, ce qui signifie qu'il existe une manière standard de définir ces objets pour être ordonnés:
public class District implements Comparable<District>{
String zipcode;
Double populationDensity;
public int compareTo(District other)
{
return populationDensity.compareTo(other.populationDensity);
}
}
Notez que vous pouvez faire l'équivalent en définissant un comparateur. La différence est que le comparateur définit la logique de commande en dehors de l'objet . Peut-être que dans un processus séparé, j'ai besoin de commander les mêmes objets par code postal - dans ce cas, l'ordre n'est pas nécessairement une propriété de l'objet, ou diffère de l'ordre naturel des objets. Vous pouvez utiliser un comparateur externe pour définir un ordre personnalisé sur les entiers, par exemple en les triant par leur valeur alphabétique.
Fondamentalement, la logique de commande doit exister quelque part. Cela peut être -
dans l'objet lui-même, s'il est naturellement comparable (étend les entiers comparables -eg)
fourni dans un comparateur externe, comme dans l'exemple ci-dessus.
TreeSet<Integer>
place de TreeMap<Integer>
, car ce dernier n'existe pas, les TreeMaps sont toujours des <Key,Value>
paires. Btw, une hypothétique TreeMap<District, Object>
ne fonctionnerait que si le district mettait en œuvre Comparable, non? J'essaie toujours de comprendre cela
Cité du javadoc;
Cette interface impose un ordre total sur les objets de chaque classe qui l'implémente. Cet ordre est appelé ordre naturel de la classe, et la méthode compareTo de la classe est appelée sa méthode de comparaison naturelle.
Les listes (et tableaux) d'objets qui implémentent cette interface peuvent être triés automatiquement par Collections.sort (et Arrays.sort). Les objets qui implémentent cette interface peuvent être utilisés comme clés dans une carte triée ou comme éléments dans un ensemble trié, sans qu'il soit nécessaire de spécifier un comparateur.
Edit: ..et a rendu le bit important en gras.
Le fait qu'une classe implémente Comparable
signifie que vous pouvez prendre deux objets de cette classe et les comparer. Certaines classes, comme certaines collections (fonction de tri dans une collection) qui maintiennent les objets dans l'ordre, reposent sur leur comparaison (pour trier, vous devez savoir quel objet est le «plus gros» et ainsi de suite).
La plupart des exemples ci-dessus montrent comment réutiliser un objet comparable existant dans la fonction compareTo. Si vous souhaitez implémenter votre propre compareTo lorsque vous souhaitez comparer deux objets de la même classe, dites un objet AirlineTicket que vous souhaitez trier par prix (moins est classé en premier), suivi du nombre d'escales (encore une fois, moins est classé premier), vous feriez ce qui suit:
class AirlineTicket implements Comparable<Cost>
{
public double cost;
public int stopovers;
public AirlineTicket(double cost, int stopovers)
{
this.cost = cost; this.stopovers = stopovers ;
}
public int compareTo(Cost o)
{
if(this.cost != o.cost)
return Double.compare(this.cost, o.cost); //sorting in ascending order.
if(this.stopovers != o.stopovers)
return this.stopovers - o.stopovers; //again, ascending but swap the two if you want descending
return 0;
}
}
Un moyen simple d'implémenter des comparaisons de champs multiples est d' utiliser ComparisonChain de Guava - alors vous pouvez dire
public int compareTo(Foo that) {
return ComparisonChain.start()
.compare(lastName, that.lastName)
.compare(firstName, that.firstName)
.compare(zipCode, that.zipCode)
.result();
}
au lieu de
public int compareTo(Person other) {
int cmp = lastName.compareTo(other.lastName);
if (cmp != 0) {
return cmp;
}
cmp = firstName.compareTo(other.firstName);
if (cmp != 0) {
return cmp;
}
return Integer.compare(zipCode, other.zipCode);
}
}
Par exemple, lorsque vous souhaitez avoir une collection ou une carte triée
Comparable est utilisé pour comparer les instances de votre classe. Nous pouvons comparer des instances de plusieurs façons, c'est pourquoi nous devons implémenter une méthode compareTo
afin de savoir comment (attributs) nous voulons comparer les instances.
Dog
classe:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[3];
dogs[0] = d1;
dogs[1] = d2;
dogs[2] = d3;
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* brutus
* medor
* ara
*/
Arrays.sort(dogs, Dog.NameComparator);
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* ara
* medor
* brutus
*/
}
}
Main
classe:package test;
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
Dog d1 = new Dog("brutus");
Dog d2 = new Dog("medor");
Dog d3 = new Dog("ara");
Dog[] dogs = new Dog[3];
dogs[0] = d1;
dogs[1] = d2;
dogs[2] = d3;
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* brutus
* medor
* ara
*/
Arrays.sort(dogs, Dog.NameComparator);
for (int i = 0; i < 3; i++) {
System.out.println(dogs[i].getName());
}
/**
* Output:
* ara
* medor
* brutus
*/
}
}
Voici un bon exemple comment utiliser comparable en Java:
http://www.onjava.com/pub/a/onjava/2003/03/12/java_comp.html?page=2
Lorsque vous implémentez l' Comparable
interface, vous devez implémenter la méthode compareTo()
. Vous en avez besoin pour comparer des objets, afin d'utiliser, par exemple, la méthode de tri de ArrayList
classe. Vous avez besoin d'un moyen de comparer vos objets pour pouvoir les trier. Vous avez donc besoin d'une compareTo()
méthode personnalisée dans votre classe pour pouvoir l'utiliser avec la ArrayList
méthode sort. La compareTo()
méthode renvoie -1,0,1.
Je viens de lire un chapitre correspondant dans Java Head 2.0, j'apprends encore.
OK, mais pourquoi ne pas simplement définir une compareTo()
méthode sans implémenter une interface comparable. Par exemple, une classe City
définie par ses name
et temperature
et
public int compareTo(City theOther)
{
if (this.temperature < theOther.temperature)
return -1;
else if (this.temperature > theOther.temperature)
return 1;
else
return 0;
}