java比較器
java基礎的運算相關的基本都是涉及到基本類型的數值類型的計算,比如>,<,+,-
等,但是如果是對象的比較應該如何進行呢?
比如我們京東上買東西,挑選商品時候需要對商品價格進行排序。萬事萬物皆對象,所以引出我們的java比較器。
1. 排序比較
在Java中經常會涉及到對象數組的排序問題,那么就涉及到對象之間的比較問題。Java中的對象,正常情況下,只能進行比較: ==或!=(也就是兩個對象的引用地址是否相同),不能使用>或<來比較對象的大小。但是在實際的開發場景中,我們需要對多個對象進行排序,言外之意,就需要比較對象的大小,如何實現?使用兩個接口中的任何一個: Comparable或 Comparator
。
Java實現對象排序的方式有兩種:
自然排序:java.lang.Comparable
定制排序:java.util.Comparator
1.1 自然排序
Comparable接口強行對實現它的每個類的對象進行整體排序。這種排序被稱為類的自然排序。
-
實現 Comparable 的類必須實現 compareTo(Object obj) 方法,兩個對象即通過 compareTo(Object obj) 方法的返回值來比較大小。如果當前對象this大於形參對象obj,則返回正整數,如果當前對象this小於形參對象obj,則返回負整數,如果當前對象this等於形參對象obj,則返回零。
-
Comparable可以認為是一個內比較器,實現了Comparable接口的類有一個特點,就是這些 類是可以和自己比較的。若一個類實現了Comparable接口,就意味着該類支持排序。
-
實現Comparable接口的對象列表(比如list集合)和數組可以通過 Collections.sort 或Arrays.sort進行自動排序( Collections或Arrays的排序的參數分別適用於集合和數組,牢記)。實現此接口的對象可以用作有序映射中的鍵或有序集合中的元素,無需指定比較器。
-
Comparable 的典型實現:(默認都是從小到大排列的)
String:按照字符串中字符的Unicode值進行比較
Character:按照字符的Unicode值來進行比較
數值類型對應的包裝類以及BigInteger、BigDecimal:按照它們對應的數值大小進行比較
Boolean:true 對應的包裝類實例大於 false 對應的包裝類實例
Date、Time等:后面的日期時間比前面的日期時間大
public class CompareTest {
@Test
public void test01(){
String[] arr = {"AA","CC","KK","DD","JJ","MM","BB","GG","DQ"};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));
}
@Test
public void test02(){
Goods[] goodsArr = new Goods[4];
goodsArr[0] = new Goods("lenovoMouse",45);
goodsArr[1] = new Goods("dellMouse",34);
goodsArr[2] = new Goods("xiaomiMouse",12);
goodsArr[3] = new Goods("huaweiMouse",89);
Arrays.sort(goodsArr);
System.out.println(goodsArr.toString());
}
@Test
public void test03(){
List<Goods> list = new ArrayList<>();
Goods goods0 = new Goods("lenovoMouse",45);
Goods goods1 = new Goods("dellMouse",34);
Goods goods2 = new Goods("xiaomiMouse",12);
Goods goods3 = new Goods("huaweiMouse",89);
list.add(goods0);
list.add(goods1);
list.add(goods2);
list.add(goods3);
Collections.sort(list);
System.out.println(list.toString());
}
}
class Goods implements Comparable{
private String goodsName;
private double price;
public Goods() {
}
public Goods(String goodsName, double price) {
this.goodsName = goodsName;
this.price = price;
}
public String getGoodsName() {
return goodsName;
}
public void setGoodsName(String goodsName) {
this.goodsName = goodsName;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
@Override
public String toString() {
return "Goods{" +
"goodsName='" + goodsName + '\'' +
", price=" + price +
'}';
}
@Override
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods = (Goods) o;
if (this.price > ((Goods) o).price){
return 1;
}else if (this.price < ((Goods) o).price ){
return -1;
}
}
return 0;
}
}
1.2 定制排序
疑問:什么時候選擇定制排序Comparator?
Comparator是比較接口,我們如果需要控制某個類的次序,而該類本身不支持排序(即沒有實現Comparable接口),那么我們就可以建立一個“該類的比較器”來進行排序,這個“比較器”只需要實現Comparator接口即可。
個人認為有兩種情況可以使用實現Comparator接口的方式:
- 對象不支持自己和自己比較(沒有實現Comparable接口),但是又想對兩個對象進行比較(大都是這種情況);
- 對象實現了Comparable接口,但是開發者認為compareTo方法中的比較方式並不是自己想要的那種比較方式;
-
可以將 Comparator 傳遞給 sort 方法(如 Collections.sort 或 Arrays.sort),從而允許在排序順序上實現精確控制。
-
還可以使用 Comparator 來控制某些數據結構(如有序 set或有序映射)的順序,或者為那些沒有自然順序的對象 collection 提供排序。
package com.ethan;
import org.junit.Test;
import java.util.*;
public class CompareTest {
@Test
public void test04(){
Goods[] goodsArr = new Goods[4];
goodsArr[0] = new Goods("lenovoMouse",45);
goodsArr[1] = new Goods("dellMouse",34);
goodsArr[2] = new Goods("xiaomiMouse",12);
goodsArr[3] = new Goods("huaweiMouse",89);
//重點
Arrays.sort(goodsArr, new Comparator<Goods>(){
@Override
public int compare(Goods o1, Goods o2) {
return -o1.compareTo(o2);
}
});
System.out.println(Arrays.toString(goodsArr));
}
}
//set/get/toString/構造函數省略
class Goods implements Comparable{
private String goodsName;
private double price;
@Override
public int compareTo(Object o) {
if(o instanceof Goods){
Goods goods = (Goods) o;
if (this.price > ((Goods) o).price){
return 1;
}else if (this.price < ((Goods) o).price ){
return -1;
}
}
return 0;
}
}
1.3現實場景的例子:
package com.ethan;
import java.io.BufferedReader;
import java.io.FileReader;
import java.util.*;
/**
* 將文件中的英文文檔中的英文單詞讀取出來並對重復單詞出現的次數進行排序
*/
public class CountWords {
public static void main(String[] args) throws Exception {
BufferedReader br = new BufferedReader(new FileReader("D:\\upload\\4.txt"));
StringBuffer sb = new StringBuffer();//可變字符串,用來存放文檔中的所有英文單詞
String text =null;
while ((text=br.readLine())!= null){
sb.append(text);// 將讀取出的字符追加到Stringbuffer中
}
br.close(); // 關閉讀入流
String str = sb.toString().toLowerCase(); // 將stringBuffer轉為字符並轉換為小寫
System.out.println(str);
String[] words = str.split("[^a-zA-Z]+"); // 通過正則表達式,得到所有單詞
Map<String ,Integer> map = new HashMap<String, Integer>();//因為hashmap的鍵值是不允許重復的,可以用來歸檔重復單詞
for(String word :words){//遍歷所有單詞,將單詞放在key里,value里存放單詞出現次數
if(map.get(word)==null){ // 若不存在說明是第一次,則加入到map,出現次數為1
map.put(word,1);
}else{
map.put(word,map.get(word)+1); // 若存在,次數累加1
}
}
// 這塊運用了比較器排序。
List<Map.Entry<String ,Integer>> list = new ArrayList<>(map.entrySet());
Comparator<Map.Entry<String,Integer>> comparator = new Comparator<Map.Entry<String, Integer>>() {
public int compare(Map.Entry<String, Integer> left, Map.Entry<String, Integer> right) {
return (left.getValue().compareTo(right.getValue()));
}
};
// 集合默認升序排列
Collections.sort(list,comparator);
for(int i=0;i<list.size();i++){// 由高到低輸出
if(i>99){
break;
}
System.out.println(list.get(list.size()-i-1).getKey() +":"+list.get(list.size()-i-1).getValue());
}
}
}