Почему класс Java должен быть сопоставим?


137

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



Вот хороший пример: java67.blogspot.com/2012/10/…
james.garriss

Ответы:


213

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

15
Я просто хочу отметить, что часто вы захотите переопределить equals(и, следовательно hashCode), чтобы соответствовать вашему compareToметоду. Например, это необходимо, если вы хотите, чтобы класс хорошо играл с a TreeSet.
Pidge

Почему бы просто не вернуться last?
Анирбан Наг 'tintinmj'

@ AnirbanNag'tintinmj 'для автоматической сортировки по имени в случае совпадения фамилии.
OddDev

Плюс один за хорошее объяснение того, почему CompareTo возвращает int и что это значит. Самый полезный
james.garriss

1
@ user3932000: Да, в этом и заключается смысл всех интерфейсов. Но обратите внимание, что «другие методы Java» включают методы, написанные пользователем! На самом деле, я бы сказал, что большинство интерфейсов потребляется кодом пользователя. В больших кодовых базах «вы» быстро становятся «другими»
Энно

40

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 -eg целые числа)

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


хороший пример, но он должен быть TreeSet<Integer>вместо TreeMap<Integer>, так как последний не существует, TreeMaps всегда <Key,Value>-pairs. Кстати, гипотетический TreeMap<District, Object>будет работать только в том случае, если Район реализует сопоставимый, верно? Все еще пытаюсь понять это
phil294

14

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

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

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

Изменить: ..и сделал важный бит жирным.


4
Я бы сказал, что предложение после того, которое вы выделили, так же важно (если не больше).
Майкл Боргвардт

8

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


8

В большинстве приведенных выше примеров показано, как повторно использовать существующий сопоставимый объект в функции 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

Простой способ реализовать множественные сравнения полей с помощью Guar's ComparisonChain - тогда вы можете сказать,

   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

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


Что Фернандо означает: если вы храните «вещи», которые реализуют Comparable, в отсортированном классе контейнера, отсортированный контейнерный класс может автоматически упорядочить эти «вещи».
Ян Дуркан

2

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

Dog класс:

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 класс:

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


2

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

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


1

Хорошо, но почему бы просто не определить 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;
}

Это не работает. Без реализации сопоставимых - я получаю исключение в классе
Каран
Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.