web-dev-qa-db-fra.com

Pourquoi une classe Java implémentera-t-elle de manière comparable?

Pourquoi Java Comparable est-il utilisé? Pourquoi quelqu'un implémenterait-il Comparable dans une classe? Quel est un exemple de la vie réelle où vous devez mettre en œuvre comparable?

132
London

Voici un échantillon de la vie réelle. 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);
}
204
Enno Shioji

Comparable définit un ordre naturel. Cela signifie que vous le définissez lorsqu'un objet doit être considéré comme "inférieur à" ou "supérieur à".

Supposons que vous avez un ensemble d’entiers et que vous souhaitez les trier. C'est assez facile, il suffit de les mettre 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 supposons maintenant 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 la même chose en définissant un comparateur. La différence est que le comparateur définit la logique de classement en dehors de l'objet. Peut-être que dans un processus séparé, je dois commander les mêmes objets par code postal - dans ce cas, l'ordre ne correspond pas nécessairement à la 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é pour les entiers, en les triant par exemple en fonction de 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 Comparable, par exemple, des entiers)

  • fourni dans un comparateur externe, comme dans l'exemple ci-dessus.

36
Steve B.

Cité du javadoc;

Cette interface impose un ordre total aux objets de chaque classe qui l'implémente. Cet ordre est appelé ordre naturel de la classe et la méthode de comparaison de la classe est appelée méthode de comparaison naturelle.

Les listes (et les tableaux) d'objets qui implémentent cette interface peuvent être triées 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 mis le bit important en gras.

14
Qwerky

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 conservent les objets dans l’ordre, dépendent de leur comparabilité (pour trier, vous devez savoir quel objet est le "plus grand", etc.).

8
Amir Rachum

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, disons 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;            
    }
}
7
arviman

Un moyen facile de mettre en œuvre des comparaisons de plusieurs champs 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);
  }
}
6
Ran Adler

Par exemple, lorsque vous souhaitez avoir une collection triée ou map

3
Fernando Miguélez

Lorsque vous implémentez l'interface Comparable, 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 class. Vous avez besoin d'un moyen de comparer vos objets pour pouvoir les trier. Vous avez donc besoin d’une méthode personnalisée compareTo() dans votre classe pour pouvoir l’utiliser avec la méthode de tri ArrayList. La méthode compareTo() renvoie -1,0,1.

Je viens de lire un chapitre correspondant dans Java Head 2.0, j'apprends toujours.

2
lxknvlk

Comparable est utilisé pour comparer des instances de votre classe. Nous pouvons comparer les instances de plusieurs manières, c'est pourquoi nous devons implémenter une méthode compareTo afin de savoir comment (attributs) nous voulons comparer des 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 d'utilisation de comparable en Java:

http://www.onjava.com/pub/a/onjava/2003/03/12/Java_comp.html?page=2

2
nono

OK, mais pourquoi ne pas simplement définir une méthode compareTo() sans implémenter d'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;
}
1
Ale B