【问题标题】:Using collections.sort() with compareTo, not sorting将 collections.sort() 与 compareTo 一起使用,而不是排序
【发布时间】:2017-11-10 00:25:46
【问题描述】:

所以目前我正在执行一项任务,我必须参加两个班级,一个名为 Fysiker,另一个名为 Human。 Fysiker 只是 Human 类的扩展。 Human 有两个属性:name 和 age,而 Fysiker 有三个属性:name、age 和 startyear。我创建了一个包含 Human 和 Fysiker 的数组,我想先按年龄对其进行排序,但如果两个 fysiker 的年龄相同,我希望它按我的第三个属性排序:startyear。

我对 compareTo 的理解(为了练习,我需要使用 compareTo)是有限的,但从我读到的内容来看,它是一个可与 Collections.sort() 自动交互的可比较,我的代码目前看起来像这样:

import java.util.List;
import java.util.Arrays;
import java.util.Random;
import java.util.ArrayList;
import java.util.Collections;
public class Fysiker extends Human{

    public int startyear;
    public Fysiker(int age, String name, int startyear){
        this.age=age;
        this.name=name;
        this.startyear=startyear;
    }

    public int getYear(){
        return startyear;
    }
    public int compareTo(Fysiker o){
        int b;
        b=(this.age>o.age ? 1:this.age<o.age ? -1:0);
        if (b==0){
            b=(this.startyear>o.startyear ? 1:this.startyear<o.startyear ? -1:0);
            return b;}
            else{
            return b;}

    }
    public String toString(){
        return "åldern är:"+this.age+" "+"namnet är:"+this.name+" "+"började fysik:"+String.format("F%02d",this.startyear%100);
    }

    public Fysiker(){
        this.age=15+rand.nextInt(86);
        this.name=names.get(rand.nextInt(names.size()));
        this.startyear=2015-rand.nextInt(this.age-14);
        while (this.startyear<1932){
            this.startyear=2015-rand.nextInt(this.age-14);
    }
}
    public static void main(String[] args){
        ArrayList<Human> fysiker=new ArrayList<Human>();
        int q;


        for (q=0;q<=80;q++){
            fysiker.add(new Fysiker());
            //fysiker.add(new Human());

            //System.out.println(fysiker.get(q).toString());
        }
        int s;
        Collections.sort(fysiker);
        for (s=0;s<=fysiker.size()-1;s++){
            //fysiker.get(0).compareTo(fysiker.get(s));
            System.out.println(fysiker.get(s).toString());
            //System.out.println(fysiker.get(0));
        }
    }

}

Human 类依次类:

import java.util.List;
import java.util.Arrays;
import java.util.Random;
import java.util.ArrayList;
public class Human implements Comparable<Human>{
        public static final List<String> names = Arrays.asList("Rutger","Oscar","Aram","Noak","Hilda","Dahl");
        public Random rand=new Random();
        public String name;
        public int age;

    public Human(int age, String name){
        this.age=age;
        this.name=name;

    }
    public Human(){
        this.age=rand.nextInt(101);
        this.name=names.get(rand.nextInt(names.size()));
    }

    public String getName(){
        return this.name;
    }
    public int getAge(){
        return this.age;
    }
    public String toString(){
        return "åldern är:"+this.age+" "+"namnet är:"+this.name;
    }
    public int compareTo(Human o){
        return this.age-o.age;
}
}

我的问题是它在 startyear 之后没有排序,但如果我从 Human 类中删除 compareTo 可以修复它,但我也需要那个,我想对它们全部排序,但它修复了“不在 startyear 之后为 fysiker" 问题排序。我从这里去哪里?

【问题讨论】:

  • 你需要实现 Comparable 接口,用你自己的代码重写 compareTo() 方法,它会根据比较的结果返回负数、零或正数。您将在方法体内设置 if 条件来处理年龄相同时的情况。

标签: java class


【解决方案1】:

其实就是子类中定义的方法:

public int compareTo(Fysiker o){

不会覆盖基类中的方法:

public int compareTo(Human o){

您可以定义具有相同签名的子类以有效地覆盖:

public int compareTo(Human o){

并使用instanceof根据真实类型进行比较。
但这也不是一个好主意。 事实上,Fysiker 会知道如何比较HumanFysiker,但Human 会只知道如何比较Humans。

Comparable.compareTo() 合同规定:

实现者还必须确保关系是可传递的: ((compare(x, y)>0) && (compare(y, z)>0)) 意味着 compare(x, z)>0。

Comparable 不应尝试在类之间进行互操作,因为这可能违反传递性比较原则。

我认为在您的情况下,作为替代方案,您应该使用 Comparator 对元素进行排序。

你有两种方法。

1) 如果列表仅包含Fysiker 实例,则声明FysikerList 并创建Comparator&lt;Fysiker&gt;

List<Fysiker> fysiker = new ArrayList<Fysiker>();
...
Collections.sort(fysiker);

它限制了 List 可以接受的元素的类型,但在这种特定情况下是希望的。

2) 如果列表同时包含HumanFysiker 实例,则声明HumanList 并创建Comparator&lt;Human&gt;

List<Human> humans = new ArrayList<Human>();
...
Collections.sort(fysiker);

Comparator实现中,你应该检查实例的类型并根据:

public class ComparatorHumanAndFysiker implements Comparator<Human>{

      public int compare(Human o1, Human o2){

           if (o1 instanceof Fysiker && o2 instanceof Fysiker){
              Fysiker f1 = (Fysiker) o1;
              Fysiker f2 = (Fysiker) o2;
              // specific comparison
              return ...;
           }

            // else mixed type comparison or human comparison              
            return o1.age - o2.age;                         
        }
 } 

【讨论】:

  • 如何使用Comparator&lt;Fysiker&gt;List&lt;Human&gt; 进行排序?
  • 但是 OP 想要对包含 HumanFysiker 实例的 List 进行排序?为什么不使用Comparator&lt;Human&gt;
  • 不确定。实际上,该列表仅包含Fysiker。如果确实需要,我假设提供一个处理这两种类型的Comparator&lt;Human&gt;instanceof 是一种方法。这不是一个完美的解决方案,而是针对特定要求的解决方法。
  • 我不确定该列表是否仅包含Fysiker。阅读代码中的注释 "//fysiker.add(new Human());"... 是的 Comparatpr&lt;Human&gt;instanceof 是唯一可能的解决方案..
  • 所以建议是开始研究比较器?
【解决方案2】:

在排序过程中,仅使用compareTo(Human o) 方法。 compareTo(Fysiker o) 从未使用过,因为您没有实现 Comparable&lt;Fysiker&gt; 接口。不幸的是,通过您的具体类继承,您的 Fysiker 类将无法实现 Comparable&lt;Fysiker&gt;,因为它已经间接实现了 Comparable&lt;Human&gt; 接口,并且在 Java 中您无法使用不同的泛型类型实现相同的接口。

作为一种快速解决方法,您可以在 Fysiker 类中覆盖 compareTo(Human o),而不是定义重载的 compareTo(Fysiker o) 方法:

public int compareTo(Human o){
    int b;
    b=(this.age>o.age ? 1:this.age<o.age ? -1:0);

    if (b==0 && o instanceof Fysiker){
        b= ( this.startyear> ( (Fysiker) o ).startyear ? 1:this.startyear< ( (Fysiker)o ).startyear ? -1:0);
        return b;
    }else{
        return b;
    }

}

更新:

我认为这种方法更干净:

public int compareTo(Human o){
        int age1 = this.age;
        int age2 = o.age;

        int result = age1 - age2;
        if (result != 0) return result;

        int startyear1 = this.startyear;
        int startyear2 = (o instanceof Fysiker) ? ( (Fysiker)o ).startyear : 0;

        return startyear1 - startyear2;
    }

输出:

åldern är:0 namnet är:Oscar
åldern är:5 namnet är:Oscar
åldern är:6 namnet är:Aram
åldern är:6 namnet är:Dahl
åldern är:7 namnet är:Aram
åldern är:8 namnet är:Oscar
åldern är:10 namnet är:Oscar
åldern är:12 namnet är:Noak
åldern är:14 namnet är:Aram
åldern är:15 namnet är:Aram
åldern är:15 namnet är:Oscar
åldern är:16 namnet är:Aram
åldern är:17 namnet är:Dahl
åldern är:17 namnet är:Hilda
åldern är:18 namnet är:Noak
åldern är:18 namnet är:Noak började fysik:F2015
åldern är:18 namnet är:Oscar
åldern är:18 namnet är:Oscar började fysik:F2014
åldern är:19 namnet är:Noak
åldern är:19 namnet är:Oscar började fysik:F2013
åldern är:19 namnet är:Hilda började fysik:F2015
åldern är:19 namnet är:Noak
åldern är:20 namnet är:Hilda började fysik:F2011
åldern är:20 namnet är:Dahl
åldern är:21 namnet är:Hilda började fysik:F2015
åldern är:21 namnet är:Rutger
åldern är:21 namnet är:Dahl
åldern är:21 namnet är:Dahl började fysik:F2009
åldern är:21 namnet är:Noak började fysik:F2009
åldern är:21 namnet är:Aram började fysik:F2015
åldern är:22 namnet är:Rutger började fysik:F2011
åldern är:22 namnet är:Hilda
åldern är:22 namnet är:Aram
åldern är:22 namnet är:Oscar
åldern är:24 namnet är:Rutger började fysik:F2006
åldern är:24 namnet är:Hilda
åldern är:24 namnet är:Oscar
åldern är:26 namnet är:Hilda började fysik:F2013
åldern är:27 namnet är:Noak började fysik:F2012
åldern är:27 namnet är:Hilda började fysik:F2013
åldern är:28 namnet är:Rutger
åldern är:28 namnet är:Dahl
åldern är:28 namnet är:Oscar började fysik:F2004
åldern är:29 namnet är:Aram började fysik:F2007
åldern är:29 namnet är:Aram började fysik:F2013
åldern är:29 namnet är:Rutger började fysik:F2013
åldern är:31 namnet är:Oscar började fysik:F2009
åldern är:31 namnet är:Dahl
åldern är:31 namnet är:Oscar
åldern är:33 namnet är:Aram började fysik:F2004
åldern är:33 namnet är:Aram började fysik:F2008
åldern är:34 namnet är:Noak
åldern är:34 namnet är:Noak började fysik:F2007
åldern är:34 namnet är:Hilda
åldern är:34 namnet är:Hilda började fysik:F1999
åldern är:35 namnet är:Aram
åldern är:35 namnet är:Hilda började fysik:F2010
åldern är:36 namnet är:Noak
åldern är:36 namnet är:Oscar
åldern är:38 namnet är:Hilda började fysik:F1999
åldern är:39 namnet är:Rutger började fysik:F2013
åldern är:42 namnet är:Dahl
åldern är:43 namnet är:Oscar
åldern är:43 namnet är:Noak började fysik:F2002
åldern är:43 namnet är:Aram
åldern är:43 namnet är:Oscar
åldern är:44 namnet är:Rutger
åldern är:44 namnet är:Aram
åldern är:44 namnet är:Oscar
åldern är:44 namnet är:Dahl
åldern är:45 namnet är:Oscar
åldern är:47 namnet är:Oscar började fysik:F1986
åldern är:48 namnet är:Hilda
åldern är:50 namnet är:Dahl började fysik:F2004
åldern är:50 namnet är:Dahl började fysik:F2008
åldern är:50 namnet är:Rutger
åldern är:51 namnet är:Hilda började fysik:F2014
åldern är:52 namnet är:Aram
åldern är:54 namnet är:Noak
åldern är:56 namnet är:Noak började fysik:F2011
åldern är:56 namnet är:Aram
åldern är:56 namnet är:Dahl
åldern är:56 namnet är:Rutger började fysik:F2009
åldern är:58 namnet är:Aram
åldern är:59 namnet är:Oscar började fysik:F1982
åldern är:59 namnet är:Oscar
åldern är:60 namnet är:Aram började fysik:F1985
åldern är:60 namnet är:Hilda
åldern är:60 namnet är:Aram
åldern är:61 namnet är:Aram började fysik:F1976
åldern är:61 namnet är:Hilda började fysik:F2003
åldern är:62 namnet är:Hilda
åldern är:63 namnet är:Noak började fysik:F1989
åldern är:63 namnet är:Dahl
åldern är:63 namnet är:Oscar
åldern är:64 namnet är:Hilda började fysik:F2013
åldern är:65 namnet är:Hilda började fysik:F1998
åldern är:65 namnet är:Dahl började fysik:F1998
åldern är:67 namnet är:Rutger började fysik:F1968
åldern är:67 namnet är:Rutger började fysik:F1972
åldern är:68 namnet är:Hilda
åldern är:69 namnet är:Noak började fysik:F2007
åldern är:69 namnet är:Hilda
åldern är:69 namnet är:Noak
åldern är:70 namnet är:Rutger började fysik:F1977
åldern är:70 namnet är:Noak började fysik:F2000
åldern är:71 namnet är:Dahl började fysik:F1961
åldern är:71 namnet är:Aram började fysik:F2009
åldern är:72 namnet är:Oscar
åldern är:73 namnet är:Dahl började fysik:F1998
åldern är:75 namnet är:Noak
åldern är:75 namnet är:Hilda
åldern är:76 namnet är:Hilda
åldern är:76 namnet är:Noak började fysik:F1998
åldern är:76 namnet är:Dahl
åldern är:77 namnet är:Oscar
åldern är:77 namnet är:Aram
åldern är:78 namnet är:Rutger började fysik:F1958
åldern är:78 namnet är:Oscar
åldern är:79 namnet är:Rutger började fysik:F1958
åldern är:79 namnet är:Aram började fysik:F1960
åldern är:79 namnet är:Aram började fysik:F1967
åldern är:79 namnet är:Hilda
åldern är:80 namnet är:Oscar började fysik:F1961
åldern är:80 namnet är:Oscar började fysik:F1969
åldern är:80 namnet är:Oscar började fysik:F2007
åldern är:81 namnet är:Rutger började fysik:F1996
åldern är:81 namnet är:Oscar
åldern är:81 namnet är:Aram började fysik:F2011
åldern är:85 namnet är:Dahl
åldern är:87 namnet är:Hilda
åldern är:88 namnet är:Dahl började fysik:F1976
åldern är:88 namnet är:Rutger
åldern är:88 namnet är:Hilda började fysik:F1968
åldern är:88 namnet är:Hilda började fysik:F2003
åldern är:88 namnet är:Oscar började fysik:F2005
åldern är:88 namnet är:Oscar började fysik:F2005
åldern är:89 namnet är:Noak började fysik:F1970
åldern är:89 namnet är:Noak
åldern är:89 namnet är:Dahl
åldern är:90 namnet är:Noak började fysik:F1975
åldern är:91 namnet är:Oscar började fysik:F1984
åldern är:91 namnet är:Hilda
åldern är:91 namnet är:Dahl
åldern är:91 namnet är:Aram
åldern är:92 namnet är:Rutger
åldern är:92 namnet är:Aram började fysik:F1997
åldern är:94 namnet är:Oscar började fysik:F1936
åldern är:95 namnet är:Dahl
åldern är:95 namnet är:Rutger började fysik:F1940
åldern är:96 namnet är:Hilda började fysik:F1945
åldern är:96 namnet är:Rutger började fysik:F1962
åldern är:96 namnet är:Aram började fysik:F1994
åldern är:96 namnet är:Noak började fysik:F1997
åldern är:97 namnet är:Dahl började fysik:F1941
åldern är:97 namnet är:Oscar började fysik:F1958
åldern är:97 namnet är:Oscar började fysik:F2014
åldern är:98 namnet är:Oscar började fysik:F1973
åldern är:98 namnet är:Hilda började fysik:F2012
åldern är:99 namnet är:Noak började fysik:F1951
åldern är:100 namnet är:Noak
åldern är:100 namnet är:Dahl började fysik:F1995

【讨论】:

  • 不确定,但该解决方案似乎对我不起作用,它看起来很整洁,但不能像那样实现它,至少对我来说不是。
  • 那个解决方案,如果两个Fysiker的年龄相同,它仍然不会在Fysiker的startyear之后排序
  • 请提供示例输出,显示您希望输出的方式。例如,这对我来说似乎很好:åldern är:34 namnet är:Hilda började fysik:F1997 -> åldern är:34 namnet är:Aram började fysik:F2005 -> åldern är:34 namnet är:Hilda började fysik:F2013跨度>
  • 我的 Fysiker 的 compareTo 似乎工作得很好,因为我只手动比较一个 Fysiker 和另一个,但是如果我创建,比如说 100,它不会比较它们,请注意这只是 Fysiker I '已经创建了这次,但在某些时候我想要一个 Humen 和 Fysiker 的混合数组
  • 我添加了示例输出,其中 Human 和 Fysiker 都在同一个列表中排序。随意展示您希望它的外观。
猜你喜欢
  • 2013-09-16
  • 1970-01-01
  • 1970-01-01
  • 2013-02-15
  • 1970-01-01
  • 2019-10-13
  • 2018-10-11
  • 1970-01-01
  • 2016-07-29
相关资源
最近更新 更多