實現了Comparable接口的元素就可以排序,compareTo方法是Comparable接口要求必須實現的,它與equals方法有關係嗎?有關係,在compareTo的返回為0時,它表示的是進行比較的兩個元素是相等的。equals是不是也應該對此作出相應的動作呢?我們看如下代碼。
class City implements Comparable<City>{
//城市編碼
private String code;
//城市名稱
private String name;
public City(String_code, String_name){
code=_code;
name=_name;
}
/*code、name的getter/setter方法省略*/
@Override
public int compareTo(City o){
//按照城市名稱排序
return new CompareToBuilder()
.append(name, o.name)
.toComparison();
}
@Override
public boolean equals(Object obj){
if(obj==null){
return false;
}
if(obj==this){
return true;
}
if(obj.getClass()!=getClass()){
return false;
}
City city=(City)obj;
//根據code判斷是否相等
return new EqualsBuilder()
.append(code, city.code)
.isEquals();
}
}
與上一個建議類似,把多個城市對像放在一個List中,然後使用不同的方法查找同一個城市,看看返回值有什麼異常。代碼如下:
public static void main(Stringargs){
List<City>cities=new ArrayList<City>();
cities.add(new City("021","上海"));
cities.add(new City("021","滬"));
//排序
Collections.sort(cities);
//查找對象
City city=new City("021","滬");
//indexOf方法取得索引值
int index1=cities.indexOf(city);
//binarySearch查找到索引值
int index2=Collections.binarySearch(cities, city);
System.out.println("索引值(indexOf):"+index1);
System.out.println("索引值(binarySearch):"+index2);
}
輸出的index1和index2應該一致吧,都是從一個列表中查找相同的元素,只是使用的算法不同嘛。但是很遺憾,結果不一致:
索引值(indexOf):0
索引值(binarySearch):1
indexOf返回的是第一個元素,而binarySearch返回的是第二個元素(索引值是1),這是怎麼回事呢?
這是因為indexOf是通過equals方法判斷的,equals等於true就認為找到符合條件的元素了,而binarySearch查找的依據是compareTo方法的返回值,返回0即認為找到符合條件的元素。
仔細審查一下代碼,我們覆寫了compareTo和equals方法,但是兩者並不一致。使用indexOf方法查找時,遍歷每個元素,然後比較equals方法的返回值,因為equals方法是根據code判斷的,因此當第一次循環時,equals就返回了true, indexOf方法結束,查找到指定值。而使用binarySearch二分法查找時,依據的是每個元素的compareTo方法返回值,而compareTo方法又是依賴name屬性的,name相等就返回0,binarySearch就認為找到元素了。
問題明白了,修改也就很容易了,將equals方法修改成判斷name是否相等即可,雖然可以解決問題,但這是一個很無奈的解決辦法,而且還要依賴我們的系統是否支持此類修改,因為相等邏輯已經發生了很大的變化。
從這個例子中,我們可以理解兩點:
indexOf依賴equals方法查找,binarySearch則依賴compareTo方法查找。
equals是判斷元素是否相等,compareTo是判斷元素在排序中的位置是否相同。
既然一個是決定排序位置,一個是決定相等,那我們就應該保證當排序位置相同時,其equals也相同,否則就會產生邏輯混亂。
注意 實現了compareTo方法,就應該覆寫equals方法,確保兩者同步。