簡體   English   中英

使用某些條件在Java中對數組進行排序

[英]Sorting an array in java with certain conditions

我有一類叫做“運動員”的類,它是人類的一個副類。 在“人”類中,我實現了可比較的界面,並使用compareTo方法來比較不同運動員的年齡。 在運動員課中,我還有一個名為Year的字段,它對應於運動員開始比賽的年份。 在我程序的主要方法中,我有一個添加運動員和人類的數組列表。 我希望,如果運動員的年齡與開始比賽的年份相同。 我使用instanceof來檢查班級實例中的實例是否是運動員類型的對象,但此后我不知道如何使其工作。

    public int compareTo(Human other)
    {

        if(this instanceof Athlete && other instanceof Athlete && this.age == other.age){
            return ;
        }
        return this.age - other.age;
    }
}

使用多態性 ,而不是運算符instanceof

即:重載Athlete類中的compareTo方法。

public int compareTo(Athlete other) {
//This method will be invoked if and only if you compare an athlete with another athlete
}

另外,請考慮equals方法的結果應與compareTo方法的結果一致。

一種可能的解決方案是在Athlete類中也添加一個compareTo方法,其內容如下(需要重寫,因為很久以前我一直沒有從事Java的工作):

public int compareTo(Athlete other){
    int result = super.compareTo((Human)other);

    if(result == 0){
        return this.year - other.year;
    }

    return result;
}

作為代碼審查,我想說完整的代碼應類似於以下內容:

人的java

public int compareTo(Human other){
    return age - other.age;
}

Athlete.java

@Override
public int compareTo(Human other){
    if(other instanceof Athlete){
        return compareTo((Athlete)other);
    }

    return super.compareTo(other);
}

public int compareTo(Athlete other){
    int result = super.compareTo((Human)other);

    if(result == 0){
        return this.year - other.year;
    }

    return result;
}

使用您的示例,您也可以只比較年份:

public int compareTo(Human other)
{

    if(this instanceof Athlete && other instanceof Athlete && this.age == other.age){
        String tYear = ((Athlete)this).getYear();
        String oYear = ((Athlete)other).getYear();
        int tYearInt = 0;
        int oYearInt = 0;
        try {
           tYearInt = Integer.parseInt(tYear);
           oYearInt = Integer.parseInt(oYear);
        } catch (Exception e){
           e.printStackTrace();
        }
        return  tYearInt - oYearInt;
    }
    return this.age - other.age;
}

但是,話雖如此,請隨時考慮@Andres答案,無論何時使用instanceof,都應質疑您的設計是否錯誤。

就像安德列斯(Andres)所說的,使用多態。 這樣做的方法如下:

首先,在“ Human類中this instanceof Athlete不是好的樣式,因為從“ Human類的角度來看,“ Athlete是一個子類,而引用子類在某些情況下會導致問題。 而是,將另一個compareTo()方法放入Athlete類。 如果Athlete.compareTo()被調用,你已經知道, this是類型的Athlete ,如果你要比較的year場,你只需要檢查other instanceof Athlete ,這是確定的,因為現在我們是在透視Athlete類,從這里開始, Athlete不是子類。

就是說,在Athlete課程中,使用以下命令:

public int compareTo(Human other) {
    int humanComp = super.compareTo(other);
    if (humanComp != 0){
        return humanComp;
    }

    if (other instanceof Athlete) {
        return ((Athlete)other).year - this.year;
    }

    return 0;
}

該解決方案首先使用Human.compareTo() (與super.compareTo(other)一起super.compareTo(other) )來檢查Human類是否已經知道如何對thisother實例進行排序。 如果不是,即該調用返回0,則必須繼續比較更多詳細信息,在本例中為year字段。
因為我們使用了Human.compareTo() ,所以我們必須確保它存在於Human類中並且可以正常工作:

public int compareTo(Human other) {
    return this.age - other.age;
}

這只是按age進行比較,因為這是Human類中我們知道可用於比較的唯一字段。

compareTo文檔說:

最后,實現者必須確保對於所有zx.compareTo(y)==0意味着sgn(x.compareTo(z)) == sgn(y.compareTo(z))

您提出的方法不符合此要求。 例如,假設

x = Athlete, age = 35, start date = 2000
y = Human,   age = 35
z = Athlete, age = 35, start date = 2001

在這個例子中

x.compareTo(y) == 0   // y is not an athlete
x.compareTo(z) < 0    // Both athletes, different start dates.
y.compareTo(z) == 0   // y is not an athlete

如果您不遵守Comparable的合同,則未指定Arrays.sortCollections.sort的行為。 理想情況下,您會得到一個異常,但是麻煩的是,這些排序方法根據數組或列表的大小使用不同的算法,並且如果輸入數組或列表包含以下內容 ,則您更有可能因不正確的compareTo方法而引發異常大量的要素 這意味着您應該使用隨機生成的長數組非常仔細地測試您的compareTo方法,否則,您的代碼中可能會包含難以發現的細微錯誤。

正確的compareTo方法如下所示:

public int compareTo(Human other) {
    int result = Integer.compare(age, other.age);
    if (result != 0)
        return result;
    if (!(this instanceof Athlete))
        return other instanceof Athlete ? -1 : 0;
    return other instanceof Athlete 
               ? Long.compare(((Athlete) this).startDate(), ((Athlete) other).startDate()) 
               : 1;
}

該方法首先按年齡排序。 如果兩個人的年齡相同,則按類型將其排在第一位(運動員排在第一位)。 年齡相同的運動員按開始日期排序。 具有相同年齡的非運動員不會以任何特定順序出現。

最后,請注意,通常最好使用多態性而不是instanceof 這里的問題是Human implements Comparable<Human> 因此compareTo方法必須接受一個Human而不是一個Athlete 即使您在Athlete重寫compareTo ,該參數也必須是Human ,並且無論如何您都必須使用instanceof來檢查參數的類型(如@GentianKasa的回答), 或者編寫一個完全獨立的方法compareToAthlete(Athlete athlete)滲漏compareToAthlete(Athlete athlete)和在Athlete執行以下操作

@Override 
public int compareTo(Human human) {
    return -human.compareToAthlete(this);  // Note the minus sign!
}

compareToAthlete也將需要兩個版本。 在此有效的同時,這意味着compareTo方法的邏輯分布在四種方法中,這使得更難於推理其正確性。 在這種情況下,我會nose之以鼻並使用instanceof

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM