Шаг 40.
Язык программирования Java.
Интерфейсы

На этом шаге мы рассмотрим интерфейсы

Интерфейс в Java не является классом. Он представляет собой множество требований, предъявляемых к классу, который должен соответствовать интерфейсу. Как правило, один разработчик, собирающийся воспользоваться трудами другого разработчика для решения конкретной задачи, заявляет: “Если ваш класс будет соответствовать определенному интерфейсу, я смогу решить свою задачу”. Обратимся к конкретному примеру. Метод sort() из класса Array позволяет упорядочить массив объектов при одном условии: объекты должны принадлежать классам, реализующим интерфейс Comparable.

Вот как выглядит этот интерфейс:

public interface Comparable {
    int compareTo(Object other);
}

Это означает, что любой класс, реализующий интерфейс Comparable, должен иметь метод compareTo(), получающий параметр типа Object и возвращающий целое значение.

Все методы интерфейса автоматически считаются открытыми, поэтому, объявляя метод в интерфейсе, указывать модификатор доступа public необязательно. Существует неявное требование: метод compareTo() должен способным сравнивать два объекта возвращать признак того, что один из них больше другого. В таком случае этот метод должен возвращать отрицательное числовое значение, если объект x меньше объекта y, нулевое значение - если они равны, в противном случае - положительное числовое значение.

Интерфейс Comparable имеет единственный метод. В общем случае количество методов может быть больше одного. Также, с помощью интерфейсов можно объявлять константы. Но важнее другое: интерфейсы не могут реализовывать в виде объектов. Ведь у интерфейсов нет ни полей, ни тела методов - все это содержится в классах, реализующих соответствующие интерфейсы. Таким образом, интерфейс можно воспринимать как абстрактный класс, лишенный всяких полей экземпляра. Но у этих двух понятий имеется существенное отличие, которое будет подробнее проанализировано позднее.

Допустим теперь, что требуется воспользоваться методом sort() из класса Array для сортировки объектов типа Employee. В этом случае класс Employee должен реализовывать интерфейс Comparable.

Для того чтобы класс реализовывал интерфейс, нужно выполнить два действия:

  1. Объявить, что класс реализует интерфейс.
  2. Определить в классе все методы, указанные в интерфейсе.

Для того чтобы объявить, что класс реализует интерфейс, служит ключевое слово implements:

class Employee implements Comparable {
    ...
}

Разумеется, теперь нужно реализовать метод compareTo(), например, для сравнения зарплаты сотрудников. Ниже приведен код, реализующий метод compareTo() в классе Employee.

public int compareTo(Object otherObject) {
    Employee other = (Employee) otherObject;
    return Double.compare(this.salary, other.salary);
}

В приведенном выше фрагменте кода применяется статический метод Double.compare(), возвращающий отрицательное числовое значение, если первый его аргумент меньше второго; нулевое значение, если аргументы равны, иначе - положительное числовое значение.

Заметим, что хоть и все методы интерфейса автоматически являются открытыми, но при реализации интерфейса модификатор доступа public должен быть указан. В противном случае компилятор предположит, что область действия этого метода ограничивается пакетом, хотя по умолчанию она не выходит за пределы класса, а в итоге он выдаст предупреждение о попытке ослабить права доступа.

Начиная с Java SE 5.0, можно принять более изящное решение, реализовав интерфейс Comparable. Такая запись означает применение обобщенного программирования. Эту тему мы рассмотрим позднее.

Перепишем в более короткую форму реализацию метода compareTo():

class Employee implements Comparable {
    public int compareTo(Object otherObject) {
        Employee other = (Employee) otherObject;
        return Double.compare(this.salary, other.salary);
    }
    ...
}

Как видите, теперь тип Object не приходится приводить к требуемому типу.

Теперь вам должно быть ясно, что для сортировки объектов достаточно реализовать в классе метод compareTo(). И такой подход вполне оправдан. Ведь должен же существовать какой-то способ воспользоваться методом sort() для сравнения объектов. Но почему нельзя в классе Employee просто предусмотреть метод compareTo(), не реализуя интерфейс Comparable?

Дело в том, что Java - строго типизированный язык программирования. При вызове какого-нибудь метода компилятор должен убедиться, что этот метод действительно существует. В теле метода sort() могут находиться операторы, аналогичные следующим:

if (a[i].compareTo(a[j]) > 0) {
    /*переставить объекты a[i] и a[j]*/
    ...
}

Компилятору должно быть известно, что у объекта a[i] действительно имеется метод compareTo(). Если переменная a содержит массив объектов, реализующих интерфейс Comparable, то существование такого метода гарантируется, поскольку каждый класс, реализующий данный интерфейс, по определению должен предоставлять метод compareTo().

На следующем шаге мы приведем пример использования интерфейсов

Предыдущий шаг Содержание Следующий шаг