Post Page Advertisement [Top]


ComparableはComparableインタフェースに含まれている唯一のメソッドです。


Objectのequalsメソッドと特性は似ていますが、

単純な等価検査に加えて、順番比較が可能です。


まず、CompareToの規約です。



  • 本メソッドは、このオブジェクトとパラメータのオブジェクトを比較する。このオブジェクトの値がパラメータオブジェクトよりも小さい場合、負の、等しい場合に0を、大きい正を返す。パラメータとして渡されたオブジェクトの型が、このオブジェクトと比較できないデータ型である場合には、ClassCast Exception例外を投げる。
  • 下に登場するsgn(expression)は、数学でのsignum関数を示すもので-1、0、1の一の値を返します。どのような値が返されるかはexpressionの値が負のか、ゼロか、正かによって決定される。

1.  compareToを実装する時は、すべてのxとyについてsgn(x.compareTo(y))== -sgn(y.compareTo(x))が満足されるようにしなければならない。 y.compareTo(x)が例外を発生させるとx.compareTo(y)も例外を発症する。このようにその逆も成立しなければならない。

2. compareToを実装するときは推移性が満たされなければならない。つまり、x.compareTo(y)> 0 && y.compareTo(z)であれば、x.compareTo(z)> 0でなければならない。

3. 最後に、x.compareTo(y)== 0であればsgn(x.compareTo(z))== sgn(y.compareTo(z))の関係がすべてのzに対して成立するようにしなければならない。

4. 強くお勧めるが必修条件じゃない一つはx.compareTo(y)== 0 ==(x.equals(y))である。一般的に、Comparableインタフェースを実装して、この条件を満たしていないクラスは、必ずその事実を明示しなければならない。このように記しておくことをお勧めする「注意:このクラスのオブジェクトは、equalsを満たしていない自然の順序に従う。」




一つ目は方向が違っても関係は維持されなければならないという条件です。

例えば、sgn(1.compareTo(2))は、値が-1であるでしょう。
これ裏返しても1です。 (2.compareTo(1)= 2 - 1)


そこにマイナス( - )が付くような値になります。このように方向を裏返しても、オブジェクト間の大小関係は維持されなければなりません。

二つ目は推移性です。 equalsをオーバーライドする時、x <yであり、y <zであれば、zは、xより大きくなければなりません。


compareToをオーバーライドする時、同じルールを守る必要があります。


三つ目は反射です。 x.compareTo(y)== 0なら、xとyが同じ数字ということです。その後、sgn(x.compareTo(z))== sgn(y.compareTo(z))の関係のz値がどのような値でも、常に同じ関係が維持されます。



四つ目は守るべきルールよりは、勧告です。 compareToとequalsの結果が同じでない場合は、コレクションインターフェイス(Collection、Set、Map)の一般規約をやぶる可能性があります。このようなインターフェースの一般的な規約がequalsメソッドに基づいて作成されたが、実際の等価はequalsの代わりcompareToを使って検査するからです。


今自分で作ったサンプルコードです。

import java.util.ArrayList;
import java.util.Collections;

public class Point implements Comparable<Point>{
    int xnum=0;

    public Point(int xnum) {
        this.xnum = xnum;
    }

    @Override
    public int compareTo(Point o) {
        if(xnum>o.xnum) return 1;
        else if(xnum==o.xnum) return 0;
        return -1;
    }

    public static void main(String[] args){

        Point p1 = new Point(1);
        Point p2 = new Point(2);
        Point p3 = new Point(3);
        Point p4 = new Point(4);

        ArrayList<Point> list = new ArrayList<Point>();
        list.add(p3);
        list.add(p2);
        list.add(p1);
        list.add(p4);

        for (Point point : list){
            System.out.print(point.xnum +" ");
        }
        System.out.println("\n");

        Collections.sort(list);

        for (Point point : list){
            System.out.print(point.xnum +" ");
        }
        System.out.println("\n");

    }
}







簡単に作成したクラスの中にintを入れました。
その後Comparebleを実装して、整列メソッドをテストしました。

listの値は3, 2, 1, 4の順番で入れ、compareToをオーバーライドしました。

compareToメソッドのフィールドを比較方式は、等価検査より順番比較の方式です。

このため、mainを実行すると、オブジェクト参照フィールドは、compareToメソッドを再帰的に呼び出して実装の内容に沿って並べます。

通常の配列の場合(int、long、doubleなど)は、Arrays.sort()を利用してください。

結果を見れば昇順で並べ替えされたことを確認できます。

import java.util.Collections;
import java.util.Set;
import java.util.TreeSet;

public class WorldList {
    public static void main(String[] args){
        Set<String> s = new TreeSet<String>();

        String[] a = {"f", "z", "z", "z", "a", "b", "j", "j", "q"};

        Collections.addAll(s, a);
        System.out.print(s);
    }
}



Stringは、基本的にComparableを実装している参照クラスです。

そのため、引数をアルファベット順に並べ替えると同時に重複を除去しています。


public int compareTo(PhoneNumber pn) {
    
    int areaCodeDiff = areaCode - pn.areaCode;

    if (areaCodeDiff != 0) return areaCodeDiff;
    
    int prefixDiff = prefix = pn.prefix;
    return prefixDiff;

    return lineNumber - pn.lineNumber;
}



このコードは、イペクチブJavaの例です。

電話番号を比較して前の数が大きいか小さい場合、その値を返します。

それだけで大小関係は確認が可能だからです。

もし0であれば、次の桁まで確認をする方式です。


この方法を使用する場合の注意すべきことは、
フィールドが負ではならないということです。

もしフィールドが負の値になると、
integer.Max_Value値を超え、32ビットを超えることになり得るので、

オーバーフローが発生します。

댓글 없음:

댓글 쓰기

Bottom Ad [Post Page]

| Designed by Colorlib