Hao Han Lim
Hao Han Lim

Reputation: 31

With the example from w3schools how do the interfaces Comparable and Comparator work and what is their difference?

Once again I was plainly scrolling thru w3schools Java basics when I saw this on the advanced sorting page:

public class Main { 
  public static void main(String[] args) { 
    // Create a list of cars
    ArrayList<Car> myCars = new ArrayList<Car>();    
    myCars.add(new Car("BMW", "X5", 1999));
    myCars.add(new Car("Honda", "Accord", 2006));
    myCars.add(new Car("Ford", "Mustang", 1970));

    // Sort the cars
    Collections.sort(myCars);

Class Car's code:

class Car implements Comparable {
  public String brand;
  public String model;
  public int year;
  
  public Car(String b, String m, int y) {
    brand = b;
    model = m;
    year = y;
  }
  
  // Decide how this object compares to other objects
  public int compareTo(Object obj) {
    Car other = (Car)obj;
    if(year < other.year) return -1; // This object is smaller than the other one
    if(year > other.year) return 1;  // This object is larger than the other one
    return 0; // Both objects are the same

So as we can see class Car implements Comparable, which compares one object to another. And in the main code when we added an array to store cars, we wrote here that the array stores the object of class car. And in Collections.sort() we only have one parameter - myCars, the array storing car objects.

We see a different behaviour for comparator:

public class Main {
  public static void main(String[] args) {
    ArrayList<Integer> myNumbers = new ArrayList<Integer>();
    myNumbers.add(33);
    myNumbers.add(15);
    myNumbers.add(20);
    myNumbers.add(34);
    myNumbers.add(8);
    myNumbers.add(12);

    Comparator myComparator = new SortEvenFirst();
    Collections.sort(myNumbers, myComparator);

    for (int i : myNumbers) {
      System.out.println(i);

the class SortEvenFirst():

class SortEvenFirst implements Comparator {
  public int compare(Object obj1, Object obj2) {
    // Make sure the objects are integers
    Integer a = (Integer)obj1;
    Integer b = (Integer)obj2;
    
    // Check each number to see if it is even
    // A number is even if the remainder when dividing by 2 is 0
    boolean aIsEven = (a % 2) == 0;
    boolean bIsEven = (b % 2) == 0;
    
    if (aIsEven == bIsEven) {
    
      // If both numbers are even or both are odd then use normal sorting rules
      if (a < b) return -1;
      if (a > b) return 1;
      return 0;
      
    } else {
    
      // If a is even then it goes first, otherwise b goes first
      if (aIsEven) {
        return -1;
      } else {
        return 1;
      }
    }
  }
}

So this has quite a different behavior for comparator: class SortEvenFirst() implements comparator BUT for the array it stores wrapper class Integer NOT the SortEvenFirst() Class. And we can see this further down the line in the main code we have to manually create a new variable for the SortEvenFirst() class and it is the additional parameter to Collections.sort()

From my understanding in the Comparable example it was somewhat convenient that they could include both information of the Cars object and also the method compareTo(). But I am still confused since I am still new to the concept of Comparable and Comparator (I dont even know the difference between the both of them)

So can someone explain if the code is written differently due to the circumstances itself or another reason, as well as how did the code automatically execute the method 'compareTo()' and 'compare()' without calling the function itself? I really need to know how these concepts work in this code and an in-depth explanation for a newbie would be helpful. Thanks!

Upvotes: -5

Views: 60

Answers (1)

Geba
Geba

Reputation: 1122

Here you can read about Comparable and Comparator When should a class be Comparable and/or Comparator?

Regarding your question/example:

class SortEvenFirst() implements comparator BUT for the array it stores wrapper class Integer NOT the SortEvenFirst()

SortEvenFirst is a class for comparing Integers, not comparing SortEvenFirst's instances

Comparable example it was somewhat convenient that they could include both information of the Cars object and also the method compareTo()

Sometimes you want to sort a list of object of the same type using different logic.
And then Comparator helps, because you can have multiple implementations of Comparator for a single class.
Using your example, in different places in your app you may need to sort cars by year, by brand + model alphabetically or by a new field (e.g. price)

public class Main {

    public static void main(String[] args) {
        ArrayList<Car> myCars = new ArrayList<>();
        myCars.add(new Car("BMW","X5", 1999));
        myCars.add(new Car("Honda", "Accord", 2006));
        myCars.add(new Car("Ford", "Mustang", 1970));

        System.out.println("Sorted by compareTo (actually by year)");
        Collections.sort(myCars);
        System.out.println(myCars);

        System.out.println("Sorted by year");
        Collections.sort(myCars, new CarYearComparator());
        System.out.println(myCars);

        System.out.println("Sorted by brand + model alphabetically");
        Collections.sort(myCars, new CarBrandAndModelComparator());
        System.out.println(myCars);
    }
}

class Car implements Comparable<Car> {
    public String brand;
    public String model;
    public int year;

    public Car(String b, String m, int y) {
        brand = b;
        model = m;
        year = y;
    }

    public int compareTo(Car other) {
        if (year < other.year) return -1;
        if (year > other.year) return 1;
        return 0;
    }

    @Override
    public String toString() {
        return brand + " " + model + " " + year;
    }
}

class CarYearComparator implements Comparator<Car> {
    @Override
    public int compare(Car c1, Car c2) {
        return Integer.compare(c1.year, c2.year);
    }
}

class CarBrandAndModelComparator implements Comparator<Car> {
    @Override
    public int compare(Car c1, Car c2) {
        return (c1.brand + c1.model).compareTo(c2.brand + c2.model);
    }
}

how did the code automatically execute the method 'compareTo()' and 'compare()' without calling the function itself?

If you do not pass Comparator, then sort expects to receive implementation of Comparable and then sort calls compareTo.
If you pass Comparator, then sort calls compare of the passed Comparator.

Upvotes: 0

Related Questions