Java中的比較器詳細(xì)解析
引入的背景
我們知道基本數(shù)據(jù)類型的數(shù)據(jù)(除boolean類型外)需要比較大小的話,直接使用比較運(yùn)算符即可,但是引用數(shù)據(jù)類型是不能直接使用比較運(yùn)算符來比較大小的。那么,如何解決這個(gè)問題呢?
在Java中經(jīng)常會(huì)涉及到對(duì)象數(shù)組的排序問題,那么就涉及到對(duì)象之間的比較問題。 Java實(shí)現(xiàn)對(duì)象排序的方式有兩種:
- 自然排序:java.lang.Comparable
- 定制排序:java.util.Comparator
自然排序:java.lang.Comparable
Comparable接口強(qiáng)行對(duì)實(shí)現(xiàn)它的每個(gè)類的對(duì)象進(jìn)行整體排序。這種排序被稱為類的自然排序。
實(shí)現(xiàn) Comparable 的類必須實(shí)現(xiàn) compareTo(Object obj) 方法,兩個(gè)對(duì)象即通過 compareTo(Object obj) 方法的返回值來比較大小。
- 如果當(dāng)前對(duì)象this大于形參對(duì)象obj,則返回正整數(shù)。
- 如果當(dāng)前對(duì)象this小于形參對(duì)象obj,則返回負(fù)整數(shù)。
- 如果當(dāng)前對(duì)象this等于形參對(duì)象obj,則返回零。
package java.lang;
public interface Comparable{
int compareTo(Object obj);
}
Comparable 的典型實(shí)現(xiàn):(默認(rèn)都是從小到大排列的)
- String:按照字符串中字符的Unicode值進(jìn)行比較
- Character:按照字符的Unicode值來進(jìn)行比較
- 數(shù)值類型對(duì)應(yīng)的包裝類以及BigInteger、BigDecimal:按照它們對(duì)應(yīng)的數(shù)值大小進(jìn)行比較
- Boolean:true 對(duì)應(yīng)的包裝類實(shí)例大于 false 對(duì)應(yīng)的包裝類實(shí)例
- Date、Time等:后面的日期時(shí)間比前面的日期時(shí)間大
測(cè)試String
代碼示例:
@Test
public void test1(){
//測(cè)試String已經(jīng)寫好的
String [] a = new String[]{"Jack", "Tom", "Lucy"};
//排序之前
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+"\t");
}
System.out.println();
//使用Arrays進(jìn)行排序
Arrays.sort(a);
//排序之后進(jìn)行展示
for (int i = 0; i < a.length; i++) {
System.out.print(a[i]+"\t");
}
}
運(yùn)行效果:

測(cè)試自己實(shí)現(xiàn)comparable接口
Product類
package cn.edu.chd.exer1;
import java.util.Objects;
public class Product implements Comparable{
private String name;
private double prices;
//無參構(gòu)造
public Product() {
}
//全參構(gòu)造
public Product(String name, double prices) {
this.name = name;
this.prices = prices;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrices() {
return prices;
}
public void setPrices(double prices) {
this.prices = prices;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", prices=" + prices +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
}
@Override
public int hashCode() {
return Objects.hash(name, prices);
}
@Override
public int compareTo(Object o) {
//如果是同一個(gè)對(duì)象,return 0
if (this == o){
return 0;
}
//兩個(gè)對(duì)象比較的標(biāo)準(zhǔn)是:價(jià)格從小到大,價(jià)格一樣的話,按照名字從小到大
if (o instanceof Product){
Product p = (Product)o;
int v = Double.compare(this.prices, p.prices);
// return v;
if (v != 0){
return v;
}
//價(jià)格如果相同,名字按照從小到大
return this.name.compareTo(p.name);
}
//手動(dòng)拋異常
throw new RuntimeException("類型不匹配");
}
}
測(cè)試
//對(duì)不同對(duì)象的大小進(jìn)行排序
@Test
public void test2(){
//商品數(shù)組
Product[] products = new Product[5];
//全參構(gòu)造器,在new對(duì)象時(shí)就對(duì)屬性進(jìn)行賦值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//使用arrays進(jìn)行排序
Arrays.sort(products);
System.out.println("排序之后");
//排序后的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}
運(yùn)行效果

定制排序:java.util.Comparator
思考
- 當(dāng)元素的類型沒有實(shí)現(xiàn)java.lang.Comparable接口而又不方便修改代碼(例如:一些第三方的類,你只有.class文件,沒有源文件)
- 如果一個(gè)類,實(shí)現(xiàn)了Comparable接口,也指定了兩個(gè)對(duì)象的比較大小的規(guī)則,但是此時(shí)此刻我不想按照它預(yù)定義的方法比較大小,但是我又不能隨意修改,因?yàn)闀?huì)影響其他地方的使用,怎么辦?(例如:我想要String按照字母從大到小的順序排序,而不是默認(rèn)的從小到大)
JDK在設(shè)計(jì)類庫之初,也考慮到這種情況,所以又增加了一個(gè)java.util.Comparator接口。強(qiáng)行對(duì)多個(gè)對(duì)象進(jìn)行整體排序的比較。
- 重寫compare(Object o1,Object o2)方法,比較o1和o2的大?。喝绻椒ǚ祷卣麛?shù),則表示o1大于o2;如果返回0,表示相等;返回負(fù)整數(shù),表示o1小于o2。
- 可以將 Comparator 傳遞給 sort 方法(如 Collections.sort 或 Arrays.sort),從而允許在排序順序上實(shí)現(xiàn)精確控制。
Product類
package cn.edu.chd.exer2;
import java.util.Objects;
public class Product implements Comparable{
private String name;
private double prices;
//無參構(gòu)造
public Product() {
}
//全參構(gòu)造
public Product(String name, double prices) {
this.name = name;
this.prices = prices;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrices() {
return prices;
}
public void setPrices(double prices) {
this.prices = prices;
}
@Override
public String toString() {
return "Product{" +
"name='" + name + '\'' +
", prices=" + prices +
'}';
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Product product = (Product) o;
return Double.compare(product.prices, prices) == 0 && name.equals(product.name);
}
@Override
public int hashCode() {
return Objects.hash(name, prices);
}
@Override
public int compareTo(Object o) {
//如果是同一個(gè)對(duì)象,return 0
if (this == o){
return 0;
}
//兩個(gè)對(duì)象比較的標(biāo)準(zhǔn)是:價(jià)格從小到大,價(jià)格一樣的話,按照名字從小到大
if (o instanceof Product){
Product p = (Product)o;
int v = Double.compare(this.prices, p.prices);
// return v;
if (v != 0){
return v;
}
//價(jià)格如果相同,名字按照從小到大
return this.name.compareTo(p.name);
}
//手動(dòng)拋異常
throw new RuntimeException("類型不匹配");
}
}
按照商品的價(jià)格從低到高排序的comparator
@Test
public void test1(){
//new一個(gè)comparator接口的匿名實(shí)現(xiàn)類
Comparator comparator = new Comparator() {
//按照商品的價(jià)格從低到高排序
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2){
return 0;
}
if (o1 instanceof Product && o2 instanceof Product){
//強(qiáng)轉(zhuǎn)
Product p1 = (Product) o1;
Product p2 = (Product) o2;
return Double.compare(p1.getPrices(), p2.getPrices());
}
throw new RuntimeException("類型不匹配");
}
};
//商品數(shù)組
Product[] products = new Product[5];
//全參構(gòu)造器,在new對(duì)象時(shí)就對(duì)屬性進(jìn)行賦值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//將comparator對(duì)象作為參數(shù)進(jìn)行傳入,排序
Arrays.sort(products, comparator);
System.out.println("排序之后");
//排序后的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}
運(yùn)行效果:

按照名稱進(jìn)行排序的comparator
//按照名稱進(jìn)行排序
@Test
public void test2(){
//new一個(gè)comparator接口的匿名實(shí)現(xiàn)類
Comparator comparator = new Comparator() {
//按照商品的名稱進(jìn)行排序
@Override
public int compare(Object o1, Object o2) {
if (o1 == o2){
return 0;
}
if (o1 instanceof Product && o2 instanceof Product){
//強(qiáng)轉(zhuǎn)
Product p1 = (Product) o1;
Product p2 = (Product) o2;
return p1.getName().compareTo(p2.getName());
}
throw new RuntimeException("類型不匹配");
}
};
//商品數(shù)組
Product[] products = new Product[5];
//全參構(gòu)造器,在new對(duì)象時(shí)就對(duì)屬性進(jìn)行賦值
products[0] = new Product("Huawei", 5999);
products[1] = new Product("XiaoMi", 4999);
products[2] = new Product("iPhone", 9999);
products[3] = new Product("vivo", 3999);
products[4] = new Product("Honer", 5999);
System.out.println("排序之前");
//排序之前的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
System.out.println("----------------------------------------------");
//將comparator對(duì)象作為參數(shù)進(jìn)行傳入,排序
Arrays.sort(products, comparator);
System.out.println("排序之后");
//排序后的遍歷
for (int i = 0; i < products.length; i++) {
System.out.println(products[i]);
}
}
運(yùn)行效果:

到此這篇關(guān)于Java中的比較器詳細(xì)解析的文章就介紹到這了,更多相關(guān)Java中的比較器內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
相關(guān)文章
Spring Boot如何優(yōu)雅的使用多線程實(shí)例詳解
這篇文章主要給大家介紹了關(guān)于Spring Boot如何優(yōu)雅的使用多線程的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2020-05-05
RabbitMQ?延遲隊(duì)列實(shí)現(xiàn)訂單支付結(jié)果異步階梯性通知(實(shí)例代碼)
這篇文章主要介紹了RabbitMQ?延遲隊(duì)列實(shí)現(xiàn)訂單支付結(jié)果異步階梯性通知,本文通過實(shí)例代碼給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2022-02-02
SpringData JPA實(shí)體映射與關(guān)系映射的實(shí)現(xiàn)
Spring Data JPA作為Spring生態(tài)系統(tǒng)中的核心項(xiàng)目,通過JPA規(guī)范提供了優(yōu)雅而強(qiáng)大的實(shí)體映射與關(guān)系處理機(jī)制,下面就來介紹一下,感興趣的可以了解一下2025-04-04
swagger的請(qǐng)求參數(shù)不顯示,@Apimodel的坑點(diǎn)及解決
這篇文章主要介紹了swagger的請(qǐng)求參數(shù)不顯示,@Apimodel的坑點(diǎn)及解決方案,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2023-11-11
Java8中Lambda表達(dá)式使用和Stream API詳解
這篇文章主要給大家介紹了關(guān)于Java8中Lambda表達(dá)式使用和Stream API的相關(guān)資料,文中通過示例代碼介紹的非常詳細(xì),對(duì)大家學(xué)習(xí)或者使用Java8具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧2019-05-05
學(xué)習(xí)SpringMVC——如何獲取請(qǐng)求參數(shù)詳解
本篇文章主要介紹了SpringMVC——如何獲取請(qǐng)求參數(shù)詳解,詳細(xì)的介紹了每種參數(shù)注解的用法。具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下。2016-12-12
spring?boot中spring框架的版本升級(jí)圖文教程
Spring Boot是一款基于Spring框架的快速開發(fā)框架,它提供了一系列的開箱即用的功能和組件,這篇文章主要給大家介紹了關(guān)于spring?boot中spring框架的版本升級(jí)的相關(guān)資料,需要的朋友可以參考下2023-10-10

