繁体   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