Arrays.binarySearch()方法用于对有序的数组寻找某一对象的位置,其对象数组必须实现Comparable接口,不然就会报错java.lang.ClassCastException,首先写两个小例子验证方法:
首先是基本类型int数组:
public static void testIntSearch() {
int[] array = new int[10];
Random random = new Random(47);
for (int i = 0; i < array.length; i++) {
array[i] = random.nextInt(30);
}
//记录array[0]的值
int flag = array[0];
System.out.println("排序之前的array:" + Arrays.toString(array));
Arrays.sort(array);
System.out.println("排序之后的array:" + Arrays.toString(array));
System.out.println("array[0]=" + flag + ",排序之后的位置:" + Arrays.binarySearch(array, flag));
System.out.println("2在数组中的位置:" + Arrays.binarySearch(array, 2));
System.out.println("-10在数组中的位置:" + Arrays.binarySearch(array, -10));
System.out.println("100在数组中的位置:" + Arrays.binarySearch(array,100));
}
输出:
排序之前的array:[8, 5, 13, 11, 1, 29, 28, 20, 12, 7]100在数组中的位置:-11
数组虽然是Random生成的,但是Random构造参数seed指定之后,random.nextInt(30)每次生成的数字此时就不是随机的数字,也就是说array数组生成的时候每次都是相同的。用flag记录array[0]的值,然后查看排序之后flag的位置。由输出知道flag=8,排序之后其在数组中的位置为3,也就是排序之后flag=array[3]。而若数组中不存在的数字进行查询,如2,其返回为-2,这个值是按照排序规则其插入点决定的,假设其插入点位置为index,则返回值为-(index+1)。如果插入点在数组最开始的地方则返回统一为-1;而插入点在数组末尾,则返回与数组长度有关,假设数组长度为length,则返回为-(length+1)。
上面的验证用的是int型的数组,下面用一般的对象型数组
public static class E23 implements Comparable {
private int value;
public E23(int value) {
this.value = value;
}
@Override
public String toString() {
return value + "";
}
@Override
public int compareTo(E23 o) {
if (this.value > o.value) {
return 1;
} else if (this.value < o.value) {
return -1;
} else {
return 0;
}
}
public static void main(String[] args) {
E23[] a = new E23[10];
Random random = new Random();
for (int i = 0; i < a.length; i++) {
a[i] = new E23(random.nextInt(10));
}
E23 e23 = a[0];
System.out.println(Arrays.toString(a));
Arrays.sort(a);
System.out.println(Arrays.toString(a));
System.out.println(e23.value + "在数组中位置:" + Arrays.binarySearch(a, e23));
}
}
在刚开始的时候,由于没有继承Comparable,所以运行时报了异常,根据异常猜测是需要继承Comparable接口,此处并未深究,原因放到后面源码的解释。E23是一个简单的类,有一个private的int域参数,继承Comparable接口实现comparaTo方法,此处用的是int域比较大小,此处要注意必须返回三种情况的值,大于小于和等于,等于返回0,其他两种情况则根据想制定的排序顺序。由结果可以知道对象类型的排序后的数组也是可查找的,其结果与基础类型一样。
下面就来看一下Arrays.binarySearch()方法的源码:此处用到的是binarySearch(int[] a,int key)与binarySearch(T[] a,T key),我们就看一下一般类型binarySearch(T[] a,T key)方法:
public static int binarySearch(Object[] a, Object key) {
return binarySearch0(a, 0, a.length, key);
}
可以看到其底层其实是binarySearch0(a, 0, a.length, key)方法,继续查看该方法:
private static int binarySearch0(Object[] a, int fromIndex, int toIndex,
Object key) {
int low = fromIndex;
int high = toIndex - 1;
while (low <= high) {
int mid = (low + high) >>> 1;
@SuppressWarnings("rawtypes")
Comparable midVal = (Comparable)a[mid];
@SuppressWarnings("unchecked")
int cmp = midVal.compareTo(key);
if (cmp < 0)
low = mid + 1;
else if (cmp > 0)
high = mid - 1;
else
return mid; // key found
}
return -(low + 1); // key not found.
}
该方法应该就是查找元素的最基本的算法实现了。由于没有指定fromIndex与toIndex,所以默认就是整个数组查找,在while循环中使用了二分法的算法思想查找元素在数组中的位置,while中第一行的意思是找到二分之后区域的中间位置,下面一行代码就解释了为什么要继承Comparable了,如果不继承Comparable此处必然会报出类型转换错误的异常,再下面调用compareTo方法进行比较,在此处就知道了为什么该方法只能用于排序之后的数组了,此处的二分法就是建立在数组是有序的前提之下,如果是没有顺序的,那就有可能出现各种情况。