導(dǎo)語
本節(jié)內(nèi)容娃善,比較器Comparable是核心內(nèi)容武契。
主要內(nèi)容
- 重新認(rèn)識Arrays類
- 兩種比較器的使用
具體內(nèi)容
Arrays類
在之前一直使用的“java.util.Arrays.sort()”可以實(shí)現(xiàn)數(shù)組的排序吊履,而Arrays類就是java.util包中提供的一個(gè)工具類醉箕,這個(gè)工具類主要是完成所有與數(shù)組有關(guān)的操作功能爬虱。
在這個(gè)類里面存在有二分查找法:public static int binarySearch(數(shù)據(jù)類型[] a, 數(shù)據(jù)類型 key)瞻离。但是如果要進(jìn)行二分查找,有一個(gè)前提临谱,那么就是數(shù)組必須是排序后的內(nèi)容璃俗。
范例:實(shí)現(xiàn)二分查找
public class TestDemo {
public static void main(String args[]) {
int data [] = new int [] {1, 5, 6, 2, 3, 4, 9, 8, 7, 10};
java.util.Arrays.sort(data); // 進(jìn)行排序
System.out.println(Arrays.binarySearch(data, 9));
}
}
輸出結(jié)果
8
Arrays類提供了數(shù)組比較:public static boolean equals(數(shù)據(jù)類型[] a, 數(shù)據(jù)類型[] a2),只不過借用了equals的方法名稱悉默,與Object類的equals()沒有關(guān)系城豁。
范例:實(shí)現(xiàn)二分查找
public class TestDemo {
public static void main(String args[]) {
int dataA [] = new int [] {1, 2, 3};
int dataB [] = new int [] {2, 1, 3};
int dataC [] = new int [] {1, 2, 3};
System.out.println(Arrays.equals(dataA, dataB));
System.out.println(Arrays.equals(dataA, dataC));
}
}
輸出結(jié)果
false
ture
要想判斷數(shù)組是否相同,需要順序完全一致抄课。
- 填充數(shù)組:public static void fill(數(shù)據(jù)類型[] a, 數(shù)據(jù)類型 val)唱星。
- 將數(shù)組變?yōu)樽址敵觯簆ublic static String toString(數(shù)據(jù)類型[] a)。
范例:使用上面方法
public class TestDemo {
public static void main(String args[]) {
int data[] = new int[10];
Arrays.fill(data, 3);
System.out.println(Arrays.toString(data));
}
}
輸出結(jié)果
[3, 3, 3, 3, 3, 3, 3, 3, 3, 3]
以上實(shí)際上就屬于數(shù)組的基本操作跟磨,只不過這樣的操作在實(shí)際的開發(fā)里面很少出現(xiàn)间聊。
比較器:Comparable(核心)
下面來觀察一下Arrays類中提供的數(shù)組排序方法:public static void sort(Object[] a)。
發(fā)現(xiàn)Arrays類里面可以直接利用sort()方法實(shí)現(xiàn)對象數(shù)組排序抵拘。
范例:編寫測試代碼
public class Book {
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
public String to String() {
return "書名:" + this.title + " 價(jià)格:" + this.price;
}
}
public class TestDemo {
public static void main(String args[]) {
Book books [] = new Book [] {
new Book("Java開發(fā)", 79.8),
new Book("JSP開發(fā)", 69.8),
new Book("Oracle開發(fā)", 99.8),
new Book("Android開發(fā)", 89.8),
};
Arrays.sort(books); // 對象數(shù)組排序
System.out.println(Arrays.toString(books));
}
}
輸出結(jié)果
Exception in thread "main" java.lang.ClassCastException:Book cannot be cast to java.lang.Comparable...
造成此類異常只有一個(gè)原因:丙個(gè)沒有關(guān)系的類對象發(fā)生了強(qiáng)制性的轉(zhuǎn)換哎榴。
每一個(gè)對象實(shí)際上只保留有地址信息,地址里面是有內(nèi)容的僵蛛,所以如果是普通的int型數(shù)組要進(jìn)行比較尚蝌,只要判斷大小就夠了,但是如果是對象數(shù)組充尉,里面包含的如果只是編碼(地址)比較是沒意義的飘言,就拿上面的代碼來講,應(yīng)該按照價(jià)格排序才是有意義的喉酌,所以此處必須要明確地設(shè)置出比較的規(guī)則:
比較的規(guī)則就是由Comparable接口定義的热凹,此接口定義如下:
public interface Comparable<T> {
public int compareTo(T o);
}
實(shí)際上String類就是Comparable接口的子類,之前使用的compareTo()方法就是比較的操作功能泪电,如果用戶現(xiàn)在要針對于對象進(jìn)行比較般妙,建議compareTo()方法返回三類數(shù)據(jù):1(大于)、0(等于)相速、-1(小于)碟渺。
范例:使用比較器
public class Book implements Comparable<Book> { // 實(shí)現(xiàn)比較
private String title;
private double price;
public Book(String title, double price) {
this.title = title;
this.price = price;
}
@Override
public String to String() {
return "書名:" + this.title + " 價(jià)格:" + this.price;
}
@Override
public int compareTo(Book o) { // Arrays.sort()會(huì)自動(dòng)調(diào)用此方法比較
if(this.price > o.price) {
return 1;
} else if(this.price < o.price) {
return -1;
} else {
return 0;
}
}
}
public class TestDemo {
public static void main(String args[]) {
Book books [] = new Book [] {
new Book("Java開發(fā)", 79.8),
new Book("JSP開發(fā)", 69.8),
new Book("Oracle開發(fā)", 99.8),
new Book("Android開發(fā)", 89.8),
};
Arrays.sort(books); // 對象數(shù)組排序
System.out.println(Arrays.toString(books));
}
}
輸出結(jié)果
[書名:JSP開發(fā) 價(jià)格:69.8, 書名:Java開發(fā) 價(jià)格:79.8, 書名:Android開發(fā) 價(jià)格:89.8, 書名:Oracle開發(fā) 價(jià)格:99.8]
compareTo()方法由Arrays.sort()自動(dòng)進(jìn)行調(diào)用。
以后不管何種情況下突诬,只要是一組對象要排序苫拍,對象所在的類一定要實(shí)現(xiàn)Comparable接口。
挽救的比較器:Comparator
Comparable接口的主要特征是在類定義的時(shí)候就默認(rèn)實(shí)現(xiàn)好的接口旺隙,那么如果說現(xiàn)在有一個(gè)類已經(jīng)開發(fā)完善了绒极。
但是由于初期的設(shè)計(jì)并沒有安排此類對象數(shù)組的排序,而后又突然需要實(shí)現(xiàn)對象數(shù)組的排序蔬捷,那么這個(gè)時(shí)候垄提,在不能修改Book類定義的情況下是不能使用Comparable接口的榔袋,為此,在Java里面為了解決這個(gè)問題铡俐,在Java里又出現(xiàn)了另一個(gè)比較器:java.util.Comparator凰兑。
原本在Comparator接口下有兩個(gè)方法:
@FunctionalInterface
public interface Comparator<T> {
public int compare(T o1, T o2);
public boolean equals(Object obj);
}
而真正要實(shí)現(xiàn)的只有compare()方法,需要單獨(dú)準(zhǔn)備出一個(gè)類來實(shí)現(xiàn)Comparator接口审丘,這個(gè)類將作為指定類的排序類吏够。
范例:定義排序的工具類
public class BookComparator implements Comparator<Book> {
@Override
public int compare(Book o1, Book o2) {
if(o1.getPrice() > o2.getPrice()) {
return 1;
} else if(o1.getPrice() < o2.getPrice()) {
return -1;
} else {
return 0;
}
}
}
之前使用Comparable接口的時(shí)候利用的是Arrays類中的sort()方法,可是現(xiàn)在更換了一個(gè)接口之后滩报,那么可以使用另外一個(gè)被重載的sort()方法:public static <T> void sort(T[] a, Comparator<? super T> c)锅知。
范例:實(shí)現(xiàn)排序
public class TestDemo {
public static void main(String args[]) {
Book books [] = new Book [] {
new Book("Java開發(fā)", 79.8),
new Book("JSP開發(fā)", 69.8),
new Book("Oracle開發(fā)", 99.8),
new Book("Android開發(fā)", 89.8),
};
Arrays.sort(books, new BookComparator()); // 對象數(shù)組排序
System.out.println(Arrays.toString(books));
}
}
輸出結(jié)果:
[書名:JSP開發(fā) 價(jià)格:69.8, 書名:Java開發(fā) 價(jià)格:79.8, 書名:Android開發(fā) 價(jià)格:89.8, 書名:Oracle開發(fā) 價(jià)格:99.8]
使用Comparator比較麻煩,因?yàn)橐x一個(gè)專門的排序類脓钾,而且調(diào)用排序的時(shí)候也要明確的指明一個(gè)排序規(guī)則類喉镰。
面試題:請解釋Comparable和Comparator的區(qū)別。
- 如果對象數(shù)組要進(jìn)行排序那么必須設(shè)置排序規(guī)則惭笑,可以使用Comparable或Comparator接口實(shí)現(xiàn)。
- java.lang.Comparable是在一個(gè)類定義的時(shí)候要去實(shí)現(xiàn)好的接口生真,這樣本類的對象數(shù)組就可以進(jìn)行排序沉噩,在Comparable接口下定義有一個(gè)public int compareTo()方法。
- java.util.Comparator是專門定義一個(gè)指定類的比較規(guī)則柱蟀,屬于挽救的比較操作川蒙,里面有兩個(gè)方法:compare()、equals()长已。
總結(jié)
不管何種情況下畜眨,只要牽扯到對象數(shù)組的排序大多數(shù)使用Comparable接口。