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

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

10 ответов

Решение

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

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

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

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

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

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

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

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

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

Простой способ реализовать множественные сравнения полей с помощью 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);
  }
}

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

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

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

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

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