Java Comparable及Comparator接口區(qū)別詳解
在實(shí)際應(yīng)用中,我們往往有需要比較兩個(gè)自定義對象大小的地方。而這些自定義對象的比較,就不像簡單的整型數(shù)據(jù)那么簡單,它們往往包含有許多的屬性,我們一般都是根據(jù)這些屬性對自定義對象進(jìn)行比較的。所以Java中要比較對象的大小或者要對對象的集合進(jìn)行排序,需要通過比較這些對象的某些屬性的大小來確定它們之間的大小關(guān)系。
一般,Java中通過接口實(shí)現(xiàn)兩個(gè)對象的比較,比較常用就是Comparable接口和Comparator接口。首先類要實(shí)現(xiàn)接口,并且使用泛型規(guī)定要進(jìn)行比較的對象所屬的類,然后類實(shí)現(xiàn)了接口后,還需要實(shí)現(xiàn)接口定義的比較方法(compareTo方法或者compare方法),在這些方法中傳入需要比較大小的另一個(gè)對象,通過選定的成員變量與之比較,如果大于則返回1,小于返回-1,相等返回0。
一般簡單的回答可以這么說:
1)首先這兩個(gè)接口一般都是用來實(shí)現(xiàn)集合內(nèi)的排序,comparable還可以用于兩個(gè)對象大小的比較。
2)Comparable接口在java.lang包下面。里面有一個(gè)compareTo(T)接口方法。當(dāng)一個(gè)類需要比較的時(shí)候,需自行實(shí)現(xiàn)Comparable接口的CompareTo方法。當(dāng)調(diào)用集合排序方法的時(shí)候,就會(huì)調(diào)用對象的compareTo()方法來實(shí)現(xiàn)對象的比較。
3)Comparator接口在java.util包下面。Comparator是一個(gè)比較器接口,一般單獨(dú)定義一個(gè)比較器實(shí)現(xiàn)該接口中的比較方法compare();在集合sort方法中傳入對應(yīng)的比較器實(shí)現(xiàn)類。一般使用匿名內(nèi)部類來實(shí)現(xiàn)比較器。
4)Comparator相對于Comparable來說更加的靈活,耦合度低。
首先呢,我們可以先了解一下List是如何排序的,我通過寫一個(gè)例子來說明;
先寫一個(gè)實(shí)體類;
public class User {
private String name;
private Integer age;
public static void main(String[] args) {
List<User> users=new ArrayList<>();
users.add(new User("yao",19));
users.add(new User("zhang",20));
users.add(new User("li",17));
users.add(new User("xu",15));
users.add(new User("xupeng",15));
users.sort(new UserComparator());
System.out.println(users);
}
public User(){
}
public User(String name, Integer age) {
this.name = name;
this.age = age;
}
@Override
public String toString() {
return "User{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Integer getAge() {
return age;
}
public void setAge(Integer age) {
this.age = age;
}
}
再寫一個(gè)實(shí)現(xiàn)比較器接口的類方法;
/**
* 實(shí)現(xiàn)比較器接口,并重寫compare方法
*/
public class UserComparator implements Comparator<User> {
@Override
public int compare(User o1, User o2) {
int age=o1.getAge()- o2.getAge();
return age!=0?age:o1.getName().length()-o2.getName().length();
}
}
最后,我們的測試結(jié)果是這樣的,說明成功了;

一、Comparable接口
1)什么是Comparable接口:
此接口強(qiáng)行對實(shí)現(xiàn)它的每個(gè)類的對象進(jìn)行整體排序。此排序被稱為該類的自然排序 ,類的 compareTo方法被稱為它的自然比較方法 。實(shí)現(xiàn)此接口的對象列表(和數(shù)組)可以通過 Collections.sort(和 Arrays.sort )進(jìn)行自動(dòng)排序。實(shí)現(xiàn)此接口的對象可以用作有序映射表中的鍵或有序集合中的元素,無需指定比較器。
2)實(shí)現(xiàn)什么方法:
int compareTo(T o)
比較此對象與指定對象的順序。如果該對象小于、等于或大于指定對象,則分別返回負(fù)整數(shù)、零或正整數(shù)。
參數(shù): o - 要比較的對象。
返回:負(fù)整數(shù)、零或正整數(shù),根據(jù)此對象是小于、等于還是大于指定對象。
拋出:ClassCastException - 如果指定對象的類型不允許它與此對象進(jìn)行比較。
3)實(shí)例(注:代碼基本上只改動(dòng)我圈出來的即可測試,其它的照List排序的元代碼使用即可測試出結(jié)果):
當(dāng)前對象 this與傳入的其他對應(yīng)的比較方法時(shí);

二、Comparator接口
1)實(shí)例說明:

Comparator接口與Comparable接口不同的是:
①Comparator位于包java.util下,而Comparable位于包java.lang下。
②Comparable接口將比較代碼嵌入需要進(jìn)行比較的類的自身代碼中,而Comparator接口在一個(gè)獨(dú)立的類中實(shí)現(xiàn)比較。
③comparator接口相對更靈活些,因?yàn)樗涌趯?shí)現(xiàn)的類是耦合在一起的,可以通過換比較器來換不同的規(guī)則進(jìn)行比較,即如果前期類的設(shè)計(jì)沒有考慮到類的Compare問題而沒有實(shí)現(xiàn)Comparable接口,后期可
以通過Comparator接口來實(shí)現(xiàn)比較算法進(jìn)行排序,并且為了使用不同的排序標(biāo)準(zhǔn)做準(zhǔn)備,比如:升序、降序。
④Comparable接口強(qiáng)制進(jìn)行自然排序,而Comparator接口不強(qiáng)制進(jìn)行自然排序,可以指定排序順序。
⑤換一種說法,簡單的說:
Comparable:使user類具有自比較的能力,可以讓自己跟同類型的數(shù)據(jù)做比較;
Comparator:就是一個(gè)比較器,像一個(gè)第三方,傳入兩個(gè)對象,讓比較器去判斷誰大誰?。?/p>
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Java日常練習(xí)題,每天進(jìn)步一點(diǎn)點(diǎn)(15)
下面小編就為大家?guī)硪黄狫ava基礎(chǔ)的幾道練習(xí)題(分享)。小編覺得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧,希望可以幫到你2021-07-07
SpringBoot基于Jackson解決Long型長度丟失問題
本文主要介紹了SpringBoot基于Jackson解決Long型長度丟失問題,通過自定義Jackson ObjectMapper子類添加String序列化器,并在SpringMVC配置中注冊該轉(zhuǎn)換器,使ID在JSON傳輸中保持完整,與數(shù)據(jù)庫數(shù)據(jù)一致2025-08-08
Java?Shell?springboot通用Shell啟動(dòng)腳本方式
這篇文章主要介紹了Java?Shell?springboot通用Shell啟動(dòng)腳本方式,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2024-05-05
Java實(shí)現(xiàn)的AES256加密解密功能示例
這篇文章主要介紹了Java實(shí)現(xiàn)的AES256加密解密功能,結(jié)合完整實(shí)例形式分析了Java實(shí)現(xiàn)AES256加密解密功能的步驟與相關(guān)操作技巧,需要的朋友可以參考下2017-02-02
Java 中的 Class.forName(類名) 使用及原理解析
Class.forName是Java中用于動(dòng)態(tài)加載類的強(qiáng)大工具,廣泛應(yīng)用于數(shù)據(jù)庫驅(qū)動(dòng)加載、反射機(jī)制和插件系統(tǒng)等場景,它通過ClassLoader加載類并執(zhí)行靜態(tài)初始化代碼,但在使用時(shí)需要注意類路徑、初始化副作用和類加載器的選擇等問題,感興趣的朋友一起看看吧2024-12-12
詳解Java?POI?excel自定義設(shè)置單元格格式
這篇文章主要介紹了Java?POI?excel設(shè)置單元格格式,自定義設(shè)置,設(shè)置單元格格式:來源_formats,更多數(shù)據(jù)類型從formats里面發(fā)現(xiàn),需要的朋友可以參考下2024-01-01
SpringBoot制作Docker鏡像接入SkyWalking的詳細(xì)過程
本文通過實(shí)際操作完成了如何基于springboot項(xiàng)目接入skyalking的詳細(xì)過程,并進(jìn)一步將springboot項(xiàng)目制作容器對接skyalking的詳細(xì)操作,感興趣的朋友一起看看吧2025-05-05
Java 使用 HttpClient 發(fā)送 GET請求和 POST請求
本文主要介紹了Java 使用 HttpClient 發(fā)送 GET請求和 POST請求,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2021-08-08

