# V6056. Implementation of 'compareTo' overloads the method from a base class. Possibly, an override was intended.

Анализатор выявил случай, когда метод 'compareTo' перегружает одноименный метод родительского класса, который реализует интерфейс 'Comparable<T>'. Скорее всего, перегрузка метода родительского класса не то, что подразумевалось разработчиком.

Рассмотрим пример класса, который вместо переопределения метода осуществляет перегрузку:

    public class Human implements Comparable<Human>
    {
      private String mName;
      private int mAge;
      ....
      Human(String name, int age)
      {
        mName = name;
        mAge = age;
      }
      ....
      public int compareTo(Human human)
      {
        int result = this.mName.compareTo(human.mName);
        if (result == 0)
        {
          result = Integer.compare(this.mAge, human.mAge);
        }
        return result;
      }
    }

    public class Employee extends Human
    {
      int mSalary;
      ....
      public Employee(String name, int age, int salary) {
        super(name, age);
        mSalary = salary;
      }
      ....
      public int compareTo(Employee employee)
      {
        return Integer.compare(this.mSalary, employee.mSalary);
      }
    }

Итак, у нас есть два класса: базовый 'Human' и дочерний 'Employee'. 'Human' реализует интерфейс 'Comparable<Human>' и определяет метод 'compareTo'. Далее дочерний класс 'Employee' расширяет базовый класс и перегружает метод 'compareTo'. Результат метода сравнения таков:

- отрицательное число - если текущий объект меньше сравниваемого;
- 0 - если объекты равны;
- положительное число - если текущий объект больше сравниваемого;

Из этого может выйти следующий эффект:

1) Если мы представим объекты 'Employee' через ссылку на базовый класс, то вызвав метод 'compareTo' мы не достигнем нужного сравнения объектов:

    Human emp1 = new Employee("Andrew", 25, 33000);
    Human emp2 = new Employee("Madeline", 29, 31000);
    System.out.println(emp1.compareTo(emp2));

На экран будет выведено -12, и получается, что объект emp1 логически меньше emp2. Ведь это не так. Скорее всего, программистом подразумевалось, что эти объекты будут сравниваться на основе поля 'mSalary', и в таком случае, результат был бы противоположным. Это произошло из-за того, что программист перегрузил метод сравнения, а не переопределил. И когда произошел вызов метода, то вызвался метод из класса 'Human'.

2) Известно, что списки элементов, которые реализуют интерфейс 'Comparable<T>', могут автоматически быть отсортированы с помощью 'Collections.sort'/'Arrays.sort', а также такие элементы могут быть использованы в качестве ключей отсортированных коллекций, без явного указания компоратора. И в случае такой перегрузки сортировка будет осуществляться не так, как задумывалась, судя по реализации сравнения в дочернем классе. Опасность в том, что в таких случаях происходит неявный вызов метода сравнения, и сразу ошибку можно не найти.

Выполним следующий код:

    List<Human> listEmployees = new ArrayList<>();
    listEmployees.add(new Employee("Andrew", 25, 33000));
    listEmployees.add(new Employee("Madeline", 29, 31000));
    listEmployees.add(new Employee("Hailey", 45, 55000));
    System.out.println("Before: ");
    listEmployees.forEach(System.out::println);
    Collections.sort(listEmployees);
    System.out.println("After: ");
    listEmployees.forEach(System.out::println);

На экран будет выведен следующий текст:

    Before:
    Name: Andrew; Age: 25; Salary: 33000
    Name: Madeline; Age: 29; Salary: 31000
    Name: Hailey; Age: 45; Salary: 55000
    After:
    Name: Andrew; Age: 25; Salary: 33000
    Name: Hailey; Age: 45; Salary: 55000
    Name: Madeline; Age: 29; Salary: 31000

Как видно из вывода, сортировка была осуществлена не по полю 'mSalary'. И все происходит по той же самой причине.

Решение этой проблемы сводится к тому, что метод сравнения должен быть переопределен, а не перегружен. Например:

    public class Employee extends Human
    {
      ....
      public int compareTo(Human employee)
      {
        if (employee instanceof Employee)
        {
          return Integer.compare(this.mSalary,
                                 ((Employee)employee).mSalary);
        }

        return -1;
      }
      ....
    }

И тогда будет все работать так, как задумывалось изначально.

В первом случае вывод будет 1 (emp1 логически больше emp2).

Во втором случае вывод будет следующим:

    Name: Andrew; Age: 25; Salary: 33000
    Name: Madeline; Age: 29; Salary: 31000
    Name: Hailey; Age: 45; Salary: 55000
    After:
    Name: Madeline; Age: 29; Salary: 31000
    Name: Andrew; Age: 25; Salary: 33000
    Name: Hailey; Age: 45; Salary: 55000