日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當(dāng)前位置: 首頁 > 编程语言 > java >内容正文

java

Java 中类的比较与排序方法(应用Comparable接口与Comparator接口)通俗易懂

發(fā)布時(shí)間:2025/3/21 java 26 豆豆
生活随笔 收集整理的這篇文章主要介紹了 Java 中类的比较与排序方法(应用Comparable接口与Comparator接口)通俗易懂 小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

引言

在平時(shí)寫Java的程序的時(shí)候,如果要進(jìn)行一些基本類型的變量的比較,可以很方便得調(diào)用Math.max()、Math.min()等方法,如果要對數(shù)組或者列表進(jìn)行排序,也可以用Arrays.sort()和Collections.sort()等已經(jīng)封裝好的方法來進(jìn)行。但是,如果是一個(gè)自定義的類的對象呢?比如自定義的兩個(gè)圖形、兩個(gè)日期等,這時(shí),應(yīng)該怎么對這些對象進(jìn)行大小比較乃至排序呢?

基本類型及其包裝類的排序

在介紹自定義的類的比較與排序之前,還是先簡單回顧一下Java中的基本類型的數(shù)據(jù)與其包裝類的元素所組成的數(shù)組的排序方式:

public static void primitiveDataTypeSort() {// 基本數(shù)據(jù)類型可以直接排序int[] ints = {3, 1, 5, 2, 4};java.util.Arrays.sort(ints);for(int number: ints)System.out.print(number + " ");System.out.println();// 包裝器類型(即對象形式)也可以直接進(jìn)行排序Character[] characters = { new Character('a'), new Character('c'),new Character('d'), new Character('b'),};java.util.Arrays.sort(characters);for (Character character: characters) {System.out.print(character + " ");}}

輸出:

1 2 3 4 5 a b c d

對于List中的類:

public static void collectionsSortTest() {List<Double> doubleList = new ArrayList<>();doubleList.add(10.5);doubleList.add(-0.5);doubleList.add(1.5);for (double num: doubleList) System.out.print(num + " ");System.out.println();Collections.sort(doubleList);for (double num: doubleList) System.out.print(num + " ");}

輸出:

10.5 -0.5 1.5 -0.5 1.5 10.5

可以看到,對于基本類型與其包裝類的對象而言,應(yīng)用Java自帶的Arrays.sort()與Collections.sort()可以很方便地對其進(jìn)行排序操作。

使用Comparable接口

Comparable接口定義了compareTo方法,用于對象之間的比較

為了實(shí)現(xiàn)這樣自定義對象的排序,我們可以將這樣的類定義為“可比較”的,為了實(shí)現(xiàn)這樣的要求,應(yīng)該使每個(gè)對象可以調(diào)用一個(gè)共同的比較方法。在Java中已經(jīng)對于這樣的“可比較”做了定義,即規(guī)定了Comparable接口來對“可比較”進(jìn)行了抽象,因此對于我們希望其實(shí)例之間可以相互比較的自定義的類,需要實(shí)現(xiàn)Comparable接口,使每個(gè)對象都有共同方法comparable。
Comparable接口的定義如下所示:

package java.lang; import java.util.*;public interface Comparable<T> {public int compareTo(T o); }

compareTo方法判斷這個(gè)對象相對于給定對象o的順序,當(dāng)這個(gè)對象小于、等于或大于給定對象o時(shí),分別返回負(fù)整數(shù)、0或正整數(shù)。

Comparable接口是一個(gè)反省接口。在實(shí)現(xiàn)該接口時(shí),泛型類型E被替換成一種具體的類型。Java類庫中的許多類實(shí)現(xiàn)了Comparable接口以定義對象的自然順序。Byte、Short、Integer、Long、Float、Doule等基本類型的包裝類,Character、BigInteger、BigDecimal、Calendar、String以及Date這樣常用的類,都實(shí)現(xiàn)了Comparable接口。

如在Java API中,Integer類中有如下定義:

public final class Integer extends Number implements Comparable<Integer> {//... class body omitted..@Overridepublic int compareTo(Integer anotherInteger) {return compare(this.value, anotherInteger.value);} }

因此,整型數(shù)字時(shí)可以比較的,類似的,其它類型的數(shù)字也是可以比較的,字符串是可以比較的,日期也是如此。若需要直接比較其大小,可以使用compareTo方法來進(jìn)比較。

對于compareTo方法直接進(jìn)行調(diào)用的效果如下:

public static void compareToTest() {System.out.println(new Integer(3).compareTo(new Integer(5)));System.out.println("ABC".compareTo("ABE"));java.util.Date date1 = new java.util.Date(2013, 1, 1);java.util.Date date2 = new java.util.Date(2012, 1, 1);System.out.println(date1.compareTo(date2)); }

輸出:

-1 -2 1

第一行顯示一個(gè)負(fù)數(shù),因?yàn)?小于5,第二行i按時(shí)一個(gè)負(fù)數(shù),因?yàn)锳BC小于ABE,最后顯示一個(gè)正數(shù),因?yàn)閐ate1大于date2。

由于所有Comparable對象都有compareTo()方法,如果對象是Comparable接口類型的實(shí)例的話,Java API中的java.util.Arrays.sort(Object[])方法就可以使用compareTo()方法來對數(shù)組中的對象進(jìn)行比較和排序。

下面,我們來自定義一個(gè)類來實(shí)驗(yàn)這個(gè)接口的用法。首先,我們定義一個(gè)圓圈的類Circle:

public class Circle {private double radius;public Circle() { this.radius = 0; }public Circle(double radius) { this.radius = radius;}public double getArea() { return Math.PI * radius * radius; }public void getName() {System.out.print(" Circle:" + this.radius);} }

這時(shí),如果我們定義一個(gè)Circle類型的數(shù)組,然后直接對其進(jìn)行排序,就會得到一個(gè)“未實(shí)現(xiàn)Comparable接口”的錯(cuò)誤,如下:

public static void main(String[] args) {Circle[] circles = new Circle[] {new Circle(4), new Circle(3), new Circle(5)};for (Circle circle: circles)System.out.println(circle.getArea());Arrays.sort(circles); }

輸出:

50.26548245743669 28.274333882308138 78.53981633974483 Exception in thread "main" java.lang.ClassCastException: learning_java.sortTry.Circle cannot be cast to java.lang.Comparable

由輸出的前三行顯示可以看到我們已經(jīng)成功地得到了三個(gè)圓圈的實(shí)例,但是由于Circle類并沒有實(shí)現(xiàn)Comparable接口,因此不能直接使用Arrays.sort()方法來對這個(gè)數(shù)組進(jìn)行排序。

這時(shí),我們重新定義一個(gè)實(shí)現(xiàn)了Comparable接口的圓圈的類CircleComparable:

public class CircleComparableextends Circleimplements Comparable<CircleComparable> {public CircleComparable(double radius) {super(radius);}public int compareTo(CircleComparable circleToCom) {if (this.getArea() > circleToCom.getArea())return 1;else if (this.getArea() < circleToCom.getArea())return -1;elsereturn 0;} }

在上面的代碼中,定義了一個(gè)擴(kuò)展自Circle的類CircleComparable,并在這個(gè)擴(kuò)展類中實(shí)現(xiàn)了Comparable接口,用compareTo(CircleComparable circleToCom)方法來比較兩個(gè)圓的面積。因此,CircleComparable類的實(shí)例既是自己的一個(gè)實(shí)例,也是Circle和Comparable的實(shí)例,當(dāng)然也是Object的一個(gè)實(shí)例。接下來再來對其進(jìn)行一次測試:

public static void main(String[] args) {CircleComparable c = new CircleComparable(1);System.out.println("c instanceof CircleComparable:\t" + (c instanceof CircleComparable));System.out.println("c instanceof Circle:\t" + (c instanceof Circle));System.out.println("c instanceof Comparable:\t" + (c instanceof Comparable));System.out.println("c instanceof Object:\t" + (c instanceof Object));Circle[] circles = new CircleComparable[] {new CircleComparable(4), new CircleComparable(3), new CircleComparable(5)};for (Circle circle: circles)System.out.print(circle.getArea() + " ");System.out.println();Arrays.sort(circles);for (Circle circle: circles)System.out.print(circle.getArea() + " "); }

輸出:

c instanceof CircleComparable: true c instanceof Circle: true c instanceof Comparable: true c instanceof Object: true 50.26548245743669 28.274333882308138 78.53981633974483 28.274333882308138 50.26548245743669 78.53981633974483

可以看到,排序后我們得到了正確的升序輸出。

接口提供了通用程序設(shè)計(jì)的一種形式,在這個(gè)例子中,如果不同接口,很難使用通用的sort()方法來排序?qū)ο?#xff0c;因?yàn)楸仨毷褂枚嘀乩^承才能同時(shí)繼承Comparable和其基類。

在這一部分的最后再提一點(diǎn),Object類包含equals方法,它的目的就是為了讓Object類的子類來覆蓋它,以比較對象的內(nèi)容是否相同。假設(shè)Object類包含一個(gè)類似于Comparable接口中所定義的comnpareTo方法,那么sort方法可以用來比較一組任意的對象。Object類中是否應(yīng)該包含一個(gè)compareTo方法尚有爭論,由于在Object類中沒有定義compareTo方法,所以Java中定義了Comparable接口,以便能夠?qū)蓚€(gè)Comparable接口的實(shí)例對象進(jìn)行比較。在這里,雖然即使不遵守,編譯器也不會進(jìn)行報(bào)錯(cuò),但是強(qiáng)烈建議compareTo應(yīng)該與equals保持一致,即對于兩個(gè)對象o1與o2,o1.equals(o2)為true與o1.compareTo(o2)==0成立的條件應(yīng)該相同。

使用Comparator接口

Comparator可以用于比較沒有實(shí)現(xiàn)Comparable的類的對象

在前一節(jié)中我們已經(jīng)實(shí)現(xiàn)了使用Comparable接口來比較元素,Java API中的許多常用的類,比如Number的子類Integer、BigInteger、BigDecima等與String、Date等類,都實(shí)現(xiàn)了Comparable接口,因此,這些類可以直接用于比較。

但是,如果我們所要處理的元素的類沒有實(shí)現(xiàn)Comparable接口呢?此時(shí)這些元素可以進(jìn)行比較么?在上面,我們舉了一個(gè)例子,一個(gè)沒有實(shí)現(xiàn)Comparable接口的類Circle,并創(chuàng)建了一個(gè)Circle類型的數(shù)組,實(shí)驗(yàn)表明,并不能直接將其進(jìn)行排序,那么是不是對于這些類就不能實(shí)現(xiàn)比較與排序了呢?

答案是我們可以通過定義一個(gè)比較器(comparator)來實(shí)現(xiàn)不同類的元素的比較。要做到這一點(diǎn),需要創(chuàng)建一個(gè)實(shí)現(xiàn)java.util.Comparator接口的類并重寫它的cmopare方法。

在這里,我們先來看一下這個(gè)Comparator接口的定義:

public interface Comparator<T> {// ...int compare(T o1, T o2);// .. }

之后,我們可以通過實(shí)現(xiàn)這個(gè)接口來寫一個(gè)Circle類的比較器CircleComparator:

import java.util.Comparator;public class CircleComparatorimplements Comparator<Circle> {public int compare(Circle o1, Circle o2) {if (o1.getArea() > o2.getArea())return 1;else if (o1.getArea() < o2.getArea())return -1;elsereturn 0;} }

在這個(gè)類中,我們通過覆蓋compare方法來實(shí)現(xiàn)了Comparator接口,完成了一個(gè)Circle的比較器。在compare()方法中,對輸入的兩個(gè)Circle的對象的面積進(jìn)行判斷,若第一個(gè)圓的面積大于第二個(gè)圓的面積,則返回1,反之則返回-1,而若兩個(gè)圓的面積相同,則返回0。

若簡單地調(diào)用這個(gè)比較器:

Circle circleOne = new Circle(3); Circle circleTwo = new Circle(5); CircleComparator comparator = new CircleComparator(); System.out.println(comparator.compare(circleOne, circleTwo)); //的一個(gè)圓比第二個(gè)圓的面積小,則會返回-1

則輸出:

-1

而若我們想要像前面的例子一樣,實(shí)現(xiàn)數(shù)組的排序,我們可以先看一下`Arrays’類的部分源碼:

public static <T> void sort(T[] a, Comparator<? super T> c) {if (c == null) {sort(a);} else {if (LegacyMergeSort.userRequested)legacyMergeSort(a, c);elseTimSort.sort(a, 0, a.length, c, null, 0, 0);} }

可以看到上面這段代碼中是’Arrays.sort()'的一種實(shí)現(xiàn),在這個(gè)方法中,輸入的第二個(gè)參數(shù)就是我們上面所構(gòu)造的比較器。而這種數(shù)組的排序方法,其實(shí)就是按照我們所寫的對于對象的比較方法,來對數(shù)組進(jìn)行排序。

其應(yīng)用可以看如下例子:

public static void circleSortTest2() {Circle[] circles = {new Circle(3), new Circle(1), new Circle(2)};java.util.Arrays.sort(circles, new CircleComparator());for (Circle circle: circles) {System.out.print(circle.getArea() + " ");} }

輸出:

3.141592653589793 12.566370614359172 28.274333882308138

從輸出可以看到,3個(gè)圓類的對象確實(shí)按照面積大小進(jìn)行了升序排列。

結(jié)合匿名內(nèi)部類Comparator接口

如果在程序中我們只是在某個(gè)地方需要使用一次Comparator接口來對某個(gè)沒有實(shí)現(xiàn)Comparable接口的類的對象的數(shù)組或列表來進(jìn)行比較或者排序,這時(shí),可能會覺得需要專門寫一個(gè)類似乎有些麻煩?;蛘哒f,我們在調(diào)用一個(gè)不能排序的對象的時(shí)候,想要將它可以排序這個(gè)特性封裝到一個(gè)類中(比如在leetcode上做題的時(shí)候,只能提交一個(gè)類),這時(shí),我們便可以結(jié)合內(nèi)部類及匿名內(nèi)部類來編寫代碼。

這里給出一個(gè)例子,還是對于上面我們的圓來進(jìn)行排序,但是,在這里我們使用匿名內(nèi)部類來完成這個(gè)操作。定義在另一個(gè)類的內(nèi)部的類便被稱為內(nèi)部類,而沒有顯式地寫出其類名的內(nèi)部類便被稱為匿名內(nèi)部類,其詳細(xì)解釋可以看匿名內(nèi)部類里的解釋。

代碼:

import java.util.*;public class TestSort {public static void main(String[] args) {CircleSortWithInner();}public static void CircleSortWithInner() {Circle circle1 = new Circle(3);Circle circle2 = new Circle(1);Circle circle3 = new Circle(4);Circle circle4 = new Circle(2);Circle[] circles = {circle1, circle2, circle3, circle4};for (Circle circle: circles) circle.getName();Arrays.sort(circles, new Comparator<Circle>() {@Overridepublic int compare(Circle o1, Circle o2) {if(o1.getArea() > o2.getArea()) return 1;else if(o1.getArea() < o2.getArea()) return -1;else return 0;}});System.out.println();for (Circle circle: circles) circle.getName();} }

輸出:

Circle:3.0 Circle:1.0 Circle:4.0 Circle:2.0 Circle:1.0 Circle:2.0 Circle:3.0 Circle:4.0

可以看到,這個(gè)圓的數(shù)組已經(jīng)被正確地排序了。

在這個(gè)例子中,向Arrays.sort方法中傳入的第二個(gè)參數(shù),應(yīng)為Comparator接口的一個(gè)對象,這里就是用匿名內(nèi)部類來實(shí)現(xiàn)定義這樣一個(gè)實(shí)現(xiàn)Comparator接口的類并生成一個(gè)其對象并將其傳入方法。

如果只需使用一次的話,這種定義比較器的方法還是比較方便的,但是也會讓代碼的可讀性下降,因此使用的時(shí)候需要權(quán)衡一下。

下面說一下降序

升序排列代碼

import java.util.Arrays; import java.util.Comparator; public class Test{public static void main(String args[]) {//注意這里的數(shù)據(jù)類型必須為Integer而不能為int,因?yàn)橹挥蠭nteger類繼承了Comparator接口而不是intInteger[] _arr = new Integer[] { 5, 3, 1, 2, 4 };Arrays.sort(_arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o1-o2;}});for(int number: _arr)System.out.print(number + " ");System.out.println();} }

輸出:1 2 3 4 5
降序排列代碼

import java.util.Arrays; import java.util.Comparator; public class Test{public static void main(String args[]) {//注意這里的數(shù)據(jù)類型必須為Integer而不能為int,因?yàn)橹挥蠭nteger類繼承了Comparator接口而不是intInteger[] _arr = new Integer[] { 5, 3, 1, 2, 4 };Arrays.sort(_arr, new Comparator<Integer>() {@Overridepublic int compare(Integer o1, Integer o2) {return o2-o1;}});for(int number: _arr)System.out.print(number + " ");System.out.println();} }

輸出:5 4 3 2 1

總結(jié)

以上是生活随笔為你收集整理的Java 中类的比较与排序方法(应用Comparable接口与Comparator接口)通俗易懂的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。