Heim  >  Artikel  >  Java  >  Vergleichende Einführung in Comparable und Comparator in Java (Codebeispiel)

Vergleichende Einführung in Comparable und Comparator in Java (Codebeispiel)

不言
不言nach vorne
2019-02-19 15:56:272108Durchsuche


Dieser Artikel bietet Ihnen eine vergleichende Einführung (Codebeispiel) zwischen Comparable und Comparator. Er hat einen gewissen Referenzwert.

1. Übersicht

Die Sortierung in Java erfolgt über die beiden Schnittstellen Comparable und Comparator.

Vergleichbar bedeutet, dass es sortiert werden kann und Objekte von Klassen, die diese Schnittstelle implementieren, automatisch über die Sortierfunktion verfügen.

Komparator stellt einen Komparator dar, der für das Objekt der Zielklasse definiert ist. Im Allgemeinen wird dieser Komparator als Parameter übergeben.

2. Vergleichbar

Die chinesische Bedeutung von Vergleichbar ist, dass es sortiert werden kann, was bedeutet, dass es die Sortierfunktion unterstützt. Solange unsere Klasse diese Schnittstelle implementiert, können Objekte dieser Klasse automatisch sortiert werden. Und diese Ordnung nennt man die natürliche Ordnung der Klassen. Listen von Objekten dieser Klasse können nach Collections.sort und Arrays.sort sortiert werden. Gleichzeitig sind Instanzen dieser Klasse als Schlüssel einer sortierten Karte und Elemente einer sortierten Menge qualifiziert.

Wenn a und b beide Instanzen der Klasse C sind, die die Comparable-Schnittstelle implementiert, wird sie nur dann aufgerufen, wenn das Ergebnis von a.compareTo(b) mit dem Ergebnis von a.equals(b) übereinstimmt Klasse C. Die natürliche Ordnung steht im Einklang mit Gleichen. Es wird dringend empfohlen, die natürliche Reihenfolge der Klasse mit dem Ergebnis von equal in Einklang zu halten, denn wenn sie inkonsistent sind, ändert sich das Verhalten einer sortierten Karte mit Objekten dieser Klasse als Schlüssel und einer sortierten Menge mit Objekten dieser Klasse als Elementen benimm dich seltsam.

Wenn beispielsweise für eine sortierte Menge, die die Comparable-Schnittstelle implementiert, das Ergebnis von a.equals(b) falsch ist und a.compareTo(b)==0, dann ist die zweite die Additionsoperation von Elementen wird fehlschlagen, weil aus Sicht der sortierten Menge die beiden in der Sortierung konsistent sind und keine doppelten Elemente gespeichert werden.

Tatsächlich stimmt die natürliche Reihenfolge der Klassen in Java grundsätzlich mit Gleichen überein, mit Ausnahme von BigDecimal, da die natürliche Reihenfolge in BigDecimal mit den Gleichen von Elementen mit demselben Wert, aber unterschiedlicher Genauigkeit (z. B. 4) übereinstimmt und 4,00) .

Quellcode-Analyse

public interface Comparable<T> {
    public int compareTo(T o);
}

Sie können dem Quellcode entnehmen, dass die Schnittstelle nur eine abstrakte Methode „compareTo“ hat. Diese Methode dient hauptsächlich dazu, die Art und Weise zu definieren, wie unsere Klassen sortiert werden. Die Methode „compareTo“ wird verwendet, um das aktuelle Element a mit dem angegebenen Element b zu vergleichen. Wenn a > int <

3. Komparator

Komparator wird auf Chinesisch als Komparator übersetzt. Er kann als Parameter an die Methoden Collections.sort und Arrays.sort übergeben werden, um einen bestimmten Wert anzugeben Klassenobjekt. Sortieren nach. Gleichzeitig kann auch die Sortiermethode für sortierte Sätze und sortierte Karten angegeben werden.

Ähnlich wie bei Comparable muss bei der Angabe eines Komparators im Allgemeinen sichergestellt werden, dass das Vergleichsergebnis mit dem Gleichheitsergebnis übereinstimmt. Wenn sie inkonsistent sind, ändert sich auch das Verhalten des entsprechenden sortierten Satzes und der sortierten Karte seltsam.

Es wird empfohlen, dass die implementierte Komparatorklasse auch die Schnittstelle java.io.Serializable implementiert, um über Serialisierungsfunktionen zu verfügen, da sie als Sortiermethode für serialisierte Datenstrukturen (TreeSet, TreeMap) verwendet werden kann.

Quellcode-Analyse

@FunctionalInterface
public interface Comparator<T> {
    // 唯一的抽象方法,用于定义比较方式(即排序方式)
    // o1>o2,返回1;o1=o2,返回0;o1<o2,返回-1
    int compare(T o1, T o2);
    boolean equals(Object obj);
    // 1.8新增的默认方法:用于反序排列
    default Comparator<T> reversed() {
        return Collections.reverseOrder(this);
    }
    // 1.8新增的默认方法:用于构建一个次级比较器,当前比较器比较结果为0,则使用次级比较器比较
    default Comparator<T> thenComparing(Comparator<? super T> other) {
        Objects.requireNonNull(other);
        return (Comparator<T> & Serializable) (c1, c2) -> {
            int res = compare(c1, c2);
            return (res != 0) ? res : other.compare(c1, c2);
        };
    }
    // 1.8新增默认方法:指定次级比较器的
    // keyExtractor表示键提取器,定义提取方式
    // keyComparator表示键比较器,定义比较方式
    default <U> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        return thenComparing(comparing(keyExtractor, keyComparator));
    }
    // 1.8新增默认方法:用于执行键的比较,采用的是由键对象内置的比较方式
    default <U extends Comparable<? super U>> Comparator<T> thenComparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        return thenComparing(comparing(keyExtractor));
    }
    // 1.8新增默认方法:用于比较执行int类型的键的比较
    default Comparator<T> thenComparingInt(ToIntFunction<? super T> keyExtractor) {
        return thenComparing(comparingInt(keyExtractor));
    }
    // 1.8新增默认方法:用于比较执行long类型的键的比较
    default Comparator<T> thenComparingLong(ToLongFunction<? super T> keyExtractor) {
        return thenComparing(comparingLong(keyExtractor));
    }
    // 1.8新增默认方法:用于比较执行double类型的键的比较
    default Comparator<T> thenComparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        return thenComparing(comparingDouble(keyExtractor));
    }
    // 1.8新增静态方法:用于得到一个相反的排序的比较器,这里针对的是内置的排序方式(即继承Comparable)
    public static <T extends Comparable<? super T>> Comparator<T> reverseOrder() {
        return Collections.reverseOrder();
    }
    // 1.8新增静态方法:用于得到一个实现了Comparable接口的类的比较方式的比较器
    // 简言之就是将Comparable定义的比较方式使用Comparator实现
    @SuppressWarnings("unchecked")
    public static <T extends Comparable<? super T>> Comparator<T> naturalOrder() {
        return (Comparator<T>) Comparators.NaturalOrderComparator.INSTANCE;
    }
    // 1.8新增静态方法:得到一个null亲和的比较器,null小于非null,两个null相等,如果全不是null,
    // 则使用指定的比较器比较,若未指定比较器,则非null全部相等返回0
    public static <T> Comparator<T> nullsFirst(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(true, comparator);
    }
    // 1.8新增静态方法:得到一个null亲和的比较器,null大于非null,两个null相等,如果全不是null,
    // 则使用指定的比较器比较,若未指定比较器,则非null全部相等返回0
    public static <T> Comparator<T> nullsLast(Comparator<? super T> comparator) {
        return new Comparators.NullComparator<>(false, comparator);
    }
    // 1.8新增静态方法:使用指定的键比较器用于执行键的比较
    public static <T, U> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor,
            Comparator<? super U> keyComparator)
    {
        Objects.requireNonNull(keyExtractor);
        Objects.requireNonNull(keyComparator);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyComparator.compare(keyExtractor.apply(c1),
                                              keyExtractor.apply(c2));
    }
    // 1.8新增静态方法:执行键比较,采用内置比较方式,key的类必须实现Comparable
    public static <T, U extends Comparable<? super U>> Comparator<T> comparing(
            Function<? super T, ? extends U> keyExtractor)
    {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> keyExtractor.apply(c1).compareTo(keyExtractor.apply(c2));
    }
    // 1.8新增静态方法:用于int类型键的比较
    public static <T> Comparator<T> comparingInt(ToIntFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Integer.compare(keyExtractor.applyAsInt(c1), keyExtractor.applyAsInt(c2));
    }
    // 1.8新增静态方法:用于long类型键的比较
    public static <T> Comparator<T> comparingLong(ToLongFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Long.compare(keyExtractor.applyAsLong(c1), keyExtractor.applyAsLong(c2));
    }
    // 1.8新增静态方法:用于double类型键的比较
    public static<T> Comparator<T> comparingDouble(ToDoubleFunction<? super T> keyExtractor) {
        Objects.requireNonNull(keyExtractor);
        return (Comparator<T> & Serializable)
            (c1, c2) -> Double.compare(keyExtractor.applyAsDouble(c1), keyExtractor.applyAsDouble(c2));
    }
}

Es gibt nur zwei Methoden in der alten Version von Comparator, nämlich die ersten beiden Methoden. Alle nachfolgenden Standardmethoden sind die neuen Methoden, die in 1.8 hinzugefügt wurden Schnittstelle kann Standardmethoden hinzufügen. Selbst bei so vielen Methoden ist die Schnittstelle immer noch eine funktionale Schnittstelle, und Compare wird zum Definieren der Vergleichsmethode verwendet.

4. Vergleich zwischen den beiden

Comparable kann als interner Komparator und Comparator als externer Komparator betrachtet werden.

Eine Klasse kann Ordnung schaffen, indem sie die Comparable-Schnittstelle implementiert, oder sie kann Ordnung schaffen, indem sie einen zusätzlichen Komparator angibt.

Die Funktionen der beiden sind eigentlich die gleichen, also vermischen Sie sie nicht.

Sehen wir uns ein Beispiel an:

Definieren Sie zunächst ein Modell: Benutzer

public class User implements Serializable, Comparable<User> {
    private static final long serialVersionUID = 1L;
    private int age;
    private String name;
    public User (){}
    public User (int age, String name){
        this.age = age;
        this.name = name;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    @Override
    public int compareTo(User o) {
        return this.age - o.age;
    }
    @Override
    public String toString() {
        return "[user={age=" + age + ",name=" + name + "}]";
    }
}

Definieren Sie dann eine Comparator-Implementierungsklasse MyComparator

public class MyComparator implements Comparator<User> {
    @Override
    public int compare(User o1, User o2) {
        return o1.getName().charAt(0)-o2.getName().charAt(0);
    }
}

Zuletzt die Testklasse : Main

public class Main {
    public static void main(String[] args) {
        User u1 = new User(12, "xiaohua");
        User u2 = new User(10, "abc");
        User u3 = new User(15,"ccc");
        User[] users = {u1,u2,u3};
        System.out.print("数组排序前:");
        printArray(users);
        System.out.println();
        Arrays.sort(users);
        System.out.print("数组排序1后:");
        printArray(users);
        System.out.println();
        Arrays.sort(users, new MyComparator());
        System.out.print("数组排序2后:");
        printArray(users);
        System.out.println();
        Arrays.sort(users, Comparator.reverseOrder());// 针对内置的排序进行倒置
        System.out.print("数组排序3后:");
        printArray(users);
    }
    public static void printArray (User[] users) {
        for (User user:users) {
            System.out.print(user.toString());
        }
    }
}

Das laufende Ergebnis ist:

数组排序前:[user={age=12,name=xiaohua}][user={age=10,name=abc}][user={age=15,name=ccc}]
数组排序1后:[user={age=10,name=abc}][user={age=12,name=xiaohua}][user={age=15,name=ccc}]
数组排序2后:[user={age=10,name=abc}][user={age=15,name=ccc}][user={age=12,name=xiaohua}]
数组排序3后:[user={age=15,name=ccc}][user={age=12,name=xiaohua}][user={age=10,name=abc}]

Durch das obige Beispiel haben wir eine Schlussfolgerung, das heißt, es gibt zwei Möglichkeiten, die Priorität der Sortierung zu definieren, den Comparator-Komparator hat Vorrang vor der internen Sortierung Vergleichbar.

5. Zusammenfassung

Comparable ist sortierbar, und Objekte von Klassen, die diese Schnittstelle implementieren, verfügen automatisch über die sortierbare Funktion.

Comparator ist ein Komparator. Durch die Implementierung dieser Schnittstelle kann eine Sortiermethode für eine bestimmte Klasse definiert werden.

Wenn Comparator und Comparable gleichzeitig vorhanden sind, hat ersteres eine höhere Priorität.

Das obige ist der detaillierte Inhalt vonVergleichende Einführung in Comparable und Comparator in Java (Codebeispiel). Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Stellungnahme:
Dieser Artikel ist reproduziert unter:cnblogs.com. Bei Verstößen wenden Sie sich bitte an admin@php.cn löschen