既存の Comparatorインターフェイスを使う。

右下のようなクラスがあり、それを使った実験用の配列を生成し、その配列を取得するため、 以下のクラスがあるとします。

package rec;
import rec.Record2;
import rec.Record3;
public class Rec23Data{
	//実験用の配列を生成し、その配列を戻り値とするメソッド
	public static Record2[] getData(){
		Record2[] a = new Record2[]{ 
			new Record2("A01", 1),
			new Record3("A02", 2, 200),
			new Record2("A03", 3),
			new Record2("A04", 4),
			new Record3("B01", 10,1000),
			new Record3("B02", 20,2000),
			new Record2("B02", 30),
			new Record3("B03", 30,300),
		};
		return a;
	}
	// iStart から(iEnd-1)の添え字情報を表示
	public static void display(Record2[] a,int iStart,int iEnd){
		for (int i = iStart; i < iEnd; i++){
			a[i].display(i);
		}
	}

	public static void main(String[] arg){
		Record2[] a = Rec23Data.getData();
		Rec23Data.display(a, 0, 8);//確認用表示
	}
}

ページ先頭のRec23Data.getData()で得られる配列から、数量が10のレコードを探す2分探索のプログラムを検討します。
これまでは、標準で使うであろうと考えられる商品コードで探しましたが、それと違うフィールドで検索するわけです。
そして、前回はjava,lang.Comparableインターフェイスを利用しましたが、 今度は、通常と違う比較や等価用のComparatorインターフェイスを利用します。 これは、 java.utilパッケージで次のように用意されています。(なお、以下はJDK.1.4以前の古い形式です)

package java.util;
public interface Comparator {
    int compare(Object o1, Object o2);// o1とo2の大小比較
    boolean equals(Object obj);//等価チェック
}

既存 の上記Comparatorインターフェイスを利用して、まず汎用的に使えるメソッドを anyパッケージに、ObjArrayクラスのstaticメソッドとして作る例を以下に示します。
引数の最後のcmpで、比較方法のメソッドを持つオブジェクトを与えて、その比較で2分探索を 行うイメージです。

package any;

import java.util.Comparator;

public class ObjArray
{
	public static int binSearch(Object[] a, Object key, int iStart, int iEnd, Comparator cmp){
		int iL = iStart;	//現在の探索範囲で、先頭の添え字(左)
		int iR = iEnd - 1;	//現在の探索範囲で、末尾の添え字(右)
		while (iL <= iR){
			int iC = (iL + iR) / 2;	//現在の探索範囲で、中央の添え字(中心)

			int val = cmp.compare(a[iC],  key);//比較
			
			if (val == 0){
				return iC;//見つかった
			} else if (val < 0){//keyが大きい
				iL = iC + 1;
			} else {/* keyが小さい */
				iR = iC - 1;
			}
		}
		return -1; //見つからない
	}
}

Comparator cmpのインターフェイスの引数を使い、 cmp.compare(a[iC], key)で、2つの引数を比較しています。
検索対象が、Object[] a, Object keyとObjectクラスなので、これから作る任意クラスのオブジェクトでも指定できます。 よって、Comparatorインターフェイスをimplementsするクラスは、Record2でないくてもよく、 任意のクラスで作れます。以下では新しく、RecSuuCmp.javaのファイルで作成した例です。 Record2のsuuで数量を比較するだけのクラスです。
Comparatorインターフェイスでは、equalsメソッドの宣言もあるので、 それも実装するところですが、Objectクラスで、既に存在するメソッドなので、 作らなくてもエラーになりません。
(必要なら、compareの戻り値が0になるような比較をequalsで行った時、戻り値がtrueになるような 同じ種類の等価が調べられよう作るべきでしょう。)

package rec;
import java.util.Comparator;

public class RecSuuCmp implements Comparator{

	// o1とo2の大小比較を行うComparatorインターフェイス実装メソッド
	public int compare(Object o1, Object o2){
		Record2 r1 = (Record2)o1;
		Record2 r2 = (Record2)o2;
		return r1.suu - r2.suu;	
	}
	
	//等価チェックするComparatorインターフェイス実装メソッド
	// 必要なら、以下のコメントを外し、オーバーライドします。
	// Objectクラスのequalsと同じチェックでよい場合は、省略します。
	//public boolean equals(Object obj)
	//{
	//	return this.equals(obj);//Objectクラスのequals呼び出し
	//}
}

以下でこれを利用して、数量が10のレコードを探すプログラムを示します。

import rec.Record2;
import rec.RecSuuCmp;

public class Test
{
	public static void main(String[] arg)	{

		Record2[] a = rec.Rec23Data.getData();
		Object key = new Record2("", 10);// 探したいデータ
		int iFound = any.ObjArray.binSearch(a, key, 0, 8, new RecSuuCmp()); 
						//実際に存在するデータ範囲のを指定
			
		if (iFound == -1){
			System.out.println("見つかりません");
			System.exit(0);//実行終了
		}
		a[iFound].display(iFound);
	}
}

これは、binSearchメソッドの最後の引数RecSuuCmpオブジェクトで比較し、探索させています。
以下に実行例をし示します。

D:\java>java Test
   4番目レコード
        商品コード:B01
        数量:10
        単価:1000

D:\java>

なお、このプログラム JDK1.5 以上でコンパイルすると、次のような警告がでます。

D:\java>javac Test.java
注: .\any\ObjArray.java の操作は、未チェックまたは安全ではありません。
注: 詳細については、-Xlint:unchecked オプションを指定して再コンパイルしてください。

D:\java>javac -Xlint:unchecked Test.java
.\any\ObjArray.java:13: 警告: [unchecked] raw 型 java.util.Comparator のメンバと
しての compare(T,T) への無検査呼び出しです。
                        int val = cmp.compare(a[iC], key);//比較
                                             ^
警告 1 個

D:\java>

警告は出ますが、問題なくコンパイルできます。
実は、上記Comparatorインターフェイスの使い方が、JDK1.4 以下の作り方で、 JDK1.5以上では、避けるべき作り方であるためです。詳細は後述しますが、このような警告を避ける場合は、 次の指定でコンパイルください。

D:\java>javac -source 1.4 Test.java

D:\java>javac Test.java

-source 1.4の指定で、ソースの書き方が1.4であることを指定しています。


参考にComparatorインターフェイスのequalsメソッドを追加して実装した例も示します。

package rec;
import java.util.Comparator;

public class RecSuuCmp implements Comparator
{
	int value;//等価チェックするデータ

	public RecSuuCmp() { }//コンストラクタ
	public RecSuuCmp(int key){//コンストラクタ
		this.value = key;
	}
	
	// o1とo2の大小比較を行うComparatorインターフェイス実装メソッド
	public int compare(Object o1, Object o2){
		Record2 r1 = (Record2)o1;
		Record2 r2 = (Record2)o2;
		return r1.suu - r2.suu;
	}
	
	//等価チェックするComparatorインターフェイス実装メソッド
	public boolean equals(Object obj){
		Record2 iObj = (Record2)obj;
		return this.value == iObj.suu;
	}
}

2分探索(binSearch)に変更はありません。 この追加したequalsメソッドは、次のようにTest.javaで 使ってみます。

import rec.Record2;
import rec.RecSuuCmp;

public class Test
{
	public static void main(String[] arg)	{

		Record2[] a = rec.Rec23Data.getData();
		Object key = new Record2("", 10);// 探したいデータ
		int iFound = any.ObjArray.binSearch(a, key, 0, 8, new RecSuuCmp()); 
					//実際に存在するデータ範囲のを指定
					
		if (iFound == -1){
			System.out.println("見つかりません");
			System.exit(0);//実行終了
		}
		a[iFound].display(iFound);
		RecSuuCmp suuCmp = new RecSuuCmp(10); //比較したいデータ
		System.out.println("比較結果:" + suuCmp.equals(a[iFound]));
	}
}

以下にコンパイルして実行する例を示します

D:\java>javac -source 1.4 Test.java

D:\java>java Test
   3番目レコード
        商品コード:B01
        数量:10
        単価:1000
比較結果:true

D:\java>