アセンブリソートcomparableインタフェースとcomparator

6340 ワード

一.関連概念
ComparableとComparatorは、集合内の要素の比較、ソートを実現するために使用されます.(一)Comparable
Comparableはjavaに位置する集合内部で定義されたメソッドによって実現されるソートである.utilの下.String、Integerなどのオブジェクト自体がComparableインタフェースを実装し、比較サイズ操作を完了するために比較に必要なインタフェースをサポートしています.カスタムクラスはlistコンテナに追加してソートできるようにするか、Comparableインタフェースを実装するか、CollectionsクラスのsortメソッドでソートするときにComparatorを指定しないと自然な順序でソートされます.ナチュラルシーケンスとは,Comparableインタフェースの設定を実現するソート方式である.(二)Comparator
Comparatorはjavaにある集合の外部で実装されたソートである.langの下.専用の比較器で、このオブジェクトが自己比較をサポートしていない場合、または自己比較関数が要求を満たすことができない場合、2つのオブジェクト間のサイズの比較を完了するために1つの比較器を書くことができます.Comparatorは、オブジェクト自体を変更せずに、ポリシーオブジェクト(strategy object)でその動作を変更するポリシーモード(strategy design pattern)を体現しています.使用方法はCollectionsクラスのsortメソッドのみであり,2つのパラメータを渡す(List list,Class class),1つ目のパラメータは集合のオブジェクトlist,2つ目はcomparatorインタフェースを実現した実装クラスのオブジェクトである.
要するにComparableは自己完成比較であり,Comparatorは外部プログラム実装比較である.
二詳しく紹介する
(一)comparable定義:
package java.lang;
import java.util.*;
public interface Comparable {
    public int compareTo(T o);
}

(二)Comparatorの定義は以下の通りである.
package java.util;
public interface Comparator {
    int compare(T o1, T o2);
    boolean equals(Object obj);
}

Comparableは、実装された各クラスのオブジェクトを全体的にソートします.このインタフェースはクラス自体が実現する必要があります(この言葉は読めませんか?大丈夫です.次に例を見てわかります).クラスがComparableインタフェースを実装場合、Comparableインタフェースを実装クラスのオブジェクトのリスト(または配列)はCollections.sort(またはArrays.sort)をソートします.さらに、コンパレータを指定することなく、Comparableインタフェースを実装するクラスのオブジェクトを、TreeMapなどの順序マッピングのキーまたはTreeSetの要素として使用できます.
例(クラスPerson 1がComparableインタフェースを実装)
package collections;
 
public class Person1 implements Comparable
{
    private int age;
    private String name;
 
    public Person1(String name, int age)
    {
        this.name = name;
        this.age = age;
    }
    @Override
    public int compareTo(Person1 o)
    {
        return this.age-o.age;
    }
    @Override
    public String toString()
    {
        return name+":"+age;
    }
}

Person 1がComparableインタフェースのcomparareToメソッドを実装していることがわかります.Comparableインタフェースを実装するには、自身のクラス、すなわち、自身のクラスでインタフェースに対応するメソッドを実装する必要があります.
テストコード:
Person1 person1 = new Person1("zzh",18);
        Person1 person2 = new Person1("jj",17);
        Person1 person3 = new Person1("qq",19);
 
        List list = new ArrayList<>();
        list.add(person1);
        list.add(person2);
        list.add(person3);
 
        System.out.println(list);
        Collections.sort(list);
        System.out.println(list);

出力結果:
[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

もし私たちのこのクラスが修正できないならば、例えばString、私たちはまた交換してソートしなければならなくて、もちろんStringの中ですでにComparableインタフェースを実現して、単純にStringで例を挙げるとあまりイメージしません.クラス自体を変更することはできません.これはComparatorというインタフェース(ポリシーモード)を使用します.
public final class Person2
{
    private int age;
    private String name;
 
    public Person2(String name, int age)
    {
        this.name = name;
        this.age = age;
    }
 
    @Override
    public String toString()
    {
        return name+":"+age;
    }
 
    //getter and setter    ....
}

クラスPerson 2のように、このクラスはすでに固定されており、そのクラス自体の修正もできず、修飾語finalもあります.あなたもimplements Comparableを継承したくありません.では、この時どうしますか.クラスの外部でComparatorのインタフェースを使用します.次のテストコード
Person2 p1 = new Person2("zzh",18);
       Person2 p2 = new Person2("jj",17);
       Person2 p3 = new Person2("qq",19);
       List list2 = new ArrayList();
       list2.add(p1);
       list2.add(p2);
       list2.add(p3);
       System.out.println(list2);
       Collections.sort(list2,new Comparator(){
 
           @Override
           public int compare(Person2 o1, Person2 o2)
           {
               if(o1 == null || o2 == null)
                   return 0;
               return o1.getAge()-o2.getAge();
           }
 
       });
       System.out.println(list2);

出力結果:
[zzh:18, jj:17, qq:19]
[jj:17, zzh:18, qq:19]

ここで(public static void sort(List list,Comparator super T>c))は内部クラスの実装方式を採用し,comparare法を実装し,クラスPerson 2のlistをソートする.
例えば、実際のケースでは、Stringをソートし、大文字と小文字を区別しない必要があります.Stringのソートは辞書のソートであることを知っています.例えば、A a Dのソート後にA D aとなるのは明らかに間違っています.では、どうすればいいのでしょうか.上と同じです(次のコードのリストはStringのリストの集合です):
Collections.sort(list, new Comparator()
      {
          @Override
          public int compare(String o1, String o2)
          {
              if(o1 == null || o2 == null)
                  return 0;
              return o1.toUpperCase().compareTo(o2.toUpperCase());
          }
      });

これで大きさを区別せずにソートStringを行う集合が実現できて便利かな~
注意深い学生は疑問に思うかもしれませんが、Comparatorインタフェースで2つの方法を定義しているのに、なぜ継承するときに1つの方法しか実現していないのか、Javaインタフェースの常識を覆すのではないでしょうか.
実際、クラスが明示的に親を継承していない場合、javaというデフォルトの親があることを知っています.lang.Objectは、Objectクラスにequalsメソッドというメソッドがあるので、ここではComparatorインタフェースを実装するクラスにequalsメソッドを実装するよう強制するのではなく、親クラスを直接呼び出せばよい.equals()メソッドwill be a better choiceを明示的に実装しているが.
『Effective Java』では、著者Joshua Bloch氏がカスタムクラスを作成する際にできるだけComparableインタフェースを実現することをお勧めします.Comparableインタフェースを実現すると、多くの汎用アルゴリズムや変更インタフェースに依存する集合と協力することができます.小さな努力をすれば、非常に強力な機能を得ることができます.
実際、Javaプラットフォームクラスライブラリのすべての値クラスはComparableインタフェースを実現しています.値クラスを作成している場合は、アルファベット順、数値順、年代順など、非常に明らかな内在的なソート関係を持っている場合は、このインタフェースの実現を断固として考慮する必要があります.
compareToメソッドは単純な等同性比較のみならず,語順の順序比較も可能であるが,それ以外はObjectのequalsメソッドと類似した特徴を持ち,汎用である.クラスはComparableインタフェースを実現し、そのインスタンスが内在的なソート関係を持っていることを示し、Comparableインタフェースを実現するオブジェクトの配列をソートするのは簡単である:Arrays.sort(a);
コレクションに格納されているComparableオブジェクトの検索、限界値の計算、自動メンテナンスも同様に簡単です.たとえば、次のプログラムはStringに依存してComparableインタフェースを実装し、コマンドラインパラメータリストの重複パラメータを削除し、アルファベット順に印刷します.
public class WordList{
    public static void main(String args[]){
        Set s = new TreeSet();
        Collections.addAll(s,args);
        System.out.println(s);
    }
}

Comparableはソートインタフェースです.クラスにComparableインタフェースが実装されている場合は、「クラスはソートをサポートする」ことを意味します.Comparatorはコンパレータですクラスの順序を制御する必要がある場合は、「クラスの比較器」を作成してソートできます.
前者は固定され、特定のクラスにバインドされるべきであり、後者は比較的柔軟であり、比較機能が必要なクラスごとに使用することができる.前者は「静的バインド」に属し、後者は「動的バインド」に属すると言える.
Comparableは「内部比較器」に相当し、Comparatorは「外部比較器」に相当することがわかります.