简体   繁体   中英

Using collections.sort() with compareTo, not sorting

So currently I'm working on an assignment where I have to two classes, one is named Fysiker and the other Human. Fysiker is simply an extension of the Human class. Human has two attributes: name and age while Fysiker has three: name, age and startyear. I have created an array which takes both Human and Fysiker, and I want to sort it by age first, but if two fysiker have the same age, I want it to sort by my third attribute: the startyear.

My understanding of the compareTo (I need to use compareTo, for the sake of the exercise) is limited, but from what I've read it's a comparable which interacts automatically with the Collections.sort(), my code currently looks like this:

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));
        }
    }

}

the Human class in turn:

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;
}
}

My issue is that it does not sort after the startyear, but I can fix it if I remove compareTo from my Human class, but I need that one as well, I want to sort them all, but it fixes the "not sorting after startyear for the fysiker"-problem. Where do I go from here ?

In fact the method defined in the subclass :

public int compareTo(Fysiker o){

doesn't override the method in the base class :

public int compareTo(Human o){

You could define the subclass with the same signature to override effectively :

public int compareTo(Human o){

and using instanceof to make the comparison according to the real type.
But it would be not a good idea either. Indeed, Fysiker would know how to compare Human and Fysiker but Human would know how to compare only Human s.

The Comparable.compareTo() contract states that :

The implementor must also ensure that the relation is transitive: ((compare(x, y)>0) && (compare(y, z)>0)) implies compare(x, z)>0.

Comparable should not try to be interoperable between classes as it may violate the transitivity comparison principle.

I think that in your case, as alternative, you should use a Comparator to sort elements.

You have two ways.

1) If the list contains only Fysiker instances, declare a List of Fysiker and create a Comparator<Fysiker> :

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

It limits the type of the elements that the List may accept but it is wished in this specific case.

2) If the list contains both Human and Fysiker instances, declare a List of Human and create a Comparator<Human> :

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

In the Comparator implementation, you should check the type of the instances and compare them according to :

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;                         
        }
 } 

During the sort, only the compareTo(Human o) method is used. The compareTo(Fysiker o) is never used since you are not implementing Comparable<Fysiker> interface. Unfortunately with your concrete class inheritance your Fysiker class wont be able to implement Comparable<Fysiker> because it already indirectly implements Comparable<Human> interface and in Java you cant implement same interface with different generic types.

As a quick workaround you can override compareTo(Human o) in your Fysiker class instead of defining an overloaded compareTo(Fysiker o) method:

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;
    }

}

Update:

I think this approach is much cleaner:

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;
    }

Output:

å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

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM