Почему класс Java должен быть сопоставим? - PullRequest
131 голосов
/ 15 сентября 2010

Почему используется Java Comparable?Зачем кому-то внедрять Comparable в классе?Что такое пример из реальной жизни, где вам нужно реализовать сопоставимые?

Ответы [ 10 ]

201 голосов
/ 15 сентября 2010

Вот пример из реальной жизни. Обратите внимание, что String также реализует 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;
    }
}

позже ..

/**
 * 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);
}
36 голосов
/ 15 сентября 2010

Comparable определяет естественный порядок. Это означает, что вы определяете, когда один объект следует считать «меньше» или «больше чем».

Предположим, у вас есть целая куча и вы хотите отсортировать их. Это довольно просто, просто поместите их в отсортированную коллекцию, верно?

TreeSet<Integer> m = new TreeSet<Integer>(); 
m.add(1);
m.add(3);
m.add(2);
for (Integer i : m)
... // values will be sorted

Но теперь предположим, что у меня есть некоторый пользовательский объект, где сортировка имеет смысл для меня, но не определена. Допустим, у меня есть данные, представляющие районы по почтовому индексу с плотностью населения, и я хочу отсортировать их по плотности:

public class District {
  String zipcode; 
  Double populationDensity;
}

Теперь самый простой способ их сортировки - это определить их с естественным упорядочением, реализуя Comparable, что означает, что есть стандартный способ, которым эти объекты определены для упорядочения.

public class District implements Comparable<District>{
  String zipcode; 
  Double populationDensity;
  public int compareTo(District other)
  {
    return populationDensity.compareTo(other.populationDensity);
  }
}

Обратите внимание, что вы можете сделать эквивалентную вещь, определив компаратор. Разница в том, что компаратор определяет логику упорядочения вне объекта . Возможно, в отдельном процессе мне нужно упорядочить одни и те же объекты по почтовому индексу - в этом случае упорядочение не обязательно является свойством объекта или отличается от естественного упорядочения объектов. Вы можете использовать внешний компаратор для определения пользовательского порядка целых чисел, например, сортируя их по алфавитному значению.

В принципе, логика упорядочения должна где-то существовать. Это может быть -

  • в самом объекте, если он естественно сопоставим (расширяет Comparable - например, целые числа)

  • поставляется во внешнем компараторе, как в примере выше.

14 голосов
/ 15 сентября 2010

Цитируется из javadoc;

Этот интерфейс накладывает полное упорядочение на объекты каждого класса, который его реализует.Это упорядочение называется естественным упорядочением класса, а метод CompareTo класса называется его естественным методом сравнения.

Списки (и массивы) объектов, которые реализуют этот интерфейс, могут автоматически сортироватьсяCollections.sort (и Arrays.sort). Объекты, которые реализуют этот интерфейс, могут использоваться в качестве ключей в отсортированной карте или в качестве элементов в отсортированном наборе, без указания компаратора.

Редактировать: ... и выделил важный бит жирным шрифтом.

8 голосов
/ 15 сентября 2010

Тот факт, что класс реализует Comparable, означает, что вы можете взять два объекта из этого класса и сравнить их.Некоторые классы, например определенные коллекции (функция сортировки в коллекции), которые поддерживают порядок объектов, полагаются на их сопоставимость (для сортировки необходимо знать, какой объект является «самым большим» и т. Д.).

7 голосов
/ 16 марта 2013

В большинстве приведенных выше примеров показано, как повторно использовать существующий сопоставимый объект в функции CompareTo. Если вы хотите реализовать свой собственный метод CompareTo, когда хотите сравнить два объекта одного и того же класса, скажем, объект AirlineTicket, который вы хотите отсортировать по цене (меньше занимает первое место), а затем число остановок (опять же, меньше это занимает первое место), вы бы сделали следующее:

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;            
    }
}
6 голосов
/ 17 июня 2013

Простой способ осуществить множественное сравнение полей - это ComparisonChain от Guava - тогда вы можете сказать

   public int compareTo(Foo that) {
     return ComparisonChain.start()
         .compare(lastName, that.lastName)
         .compare(firstName, that.firstName)
         .compare(zipCode, that.zipCode)
         .result();
   }

вместо

  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);
  }
}
3 голосов
/ 15 сентября 2010

Например, если вы хотите иметь отсортированную коллекцию или map

2 голосов
/ 09 июля 2014

При реализации интерфейса Comparable необходимо реализовать метод compareTo().Это нужно для сравнения объектов, чтобы использовать, например, метод сортировки класса ArrayList.Вам нужен способ сравнить ваши объекты, чтобы иметь возможность их сортировать.Поэтому вам нужен собственный метод compareTo() в вашем классе, чтобы вы могли использовать его с методом ArrayList sort.Метод compareTo() возвращает -1,0,1.

Я только что прочитал соответствующую главу в Java Head 2.0, я все еще учусь.

2 голосов
/ 04 февраля 2014

Comparable используется для сравнения экземпляров вашего класса.Мы можем сравнивать экземпляры разными способами, поэтому нам нужно реализовать метод compareTo, чтобы узнать, как (атрибуты) мы хотим сравнивать экземпляры.

Dog class:

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 class:

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
         */

    }
}

Вот хороший пример использования сопоставимого в Java:

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

1 голос
/ 25 июля 2017

ОК, но почему бы просто не определить метод compareTo() без реализации сопоставимого интерфейса.Например, класс City, определенный его name и temperature и

public int compareTo(City theOther)
{
    if (this.temperature < theOther.temperature)
        return -1;
    else if (this.temperature > theOther.temperature)
        return 1;
    else
        return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...