Інтерфейси. Особливості використання в поєднанні з класами. Переваги застосування інтерфейсів. Ключові слова interface, implements. Приклади

Інтерфейси. Особливості використання в поєднанні з класами. Переваги застосування інтерфейсів. Ключові слова interface, implements. Приклади


Перед вивченням даної теми рекомендується ознайомитись з темою:


Зміст



1. Для чого використовуються інтерфейси? Переваги застосування інтерфейсів

Інтерфейси використовуються для створення повністю абстрактних класів які взагалі не містять реалізації. Інтерфейси не містять реалізації. Таким чином, інтерфейси призначені для опису того, що має бути реалізовано класами, які реалізують ці інтерфейси. Іншими словами, інтерфейси вказують класам які їх реалізують, що має бути реалізовано але не як це має бути реалізовано. Інтерфейси описують форму, але не реалізацію.

В інтерфейсі вказуються імена методів, списки аргументів та типи значень, що повертаються, але не тіла (реалізації) цих методів.

Використання інтерфейсів дає наступні взаємозв’язані переваги:

  • інтерфейс фактично визначає “протокол” взаємодії між класами;
  • поєднання інтерфейсів і класів дозволяє чітко відділити оголошення загальнодоступних методів від їх реалізації;
  • інтерфейси ізолюють визначення одного чи декількох методів від ієрархії успадкування. В результаті класи, які не зв’язані між собою ієрархічно, можуть реалізувати один і той же інтерфейс;
  • будь-який метод, що використовує інтерфейс, знає тільки про те, які методи інтерфейсу викликаються і не більше. Реалізація методів здійснюється в класах, які реалізують цей інтерфейс і залишається прихованою;
  • поєднання можливостей інтерфейсів і класів є ефективним у випадку реалізації різноманітних шаблонів проектування (patterns).
  • інтерфейси дозволяють частково реалізувати так звану “множинну спадковість”, яка була реалізована в надпотужному C++ (хоча, ця парадигма приводила до плутанини та виникненню численних “логічних помилок” в програмуванні, які важко було виявити).

 

2. Загальна форма оголошення інтерфейсу. Ключове слово interface

Загальна форма оголошення інтерфейсу має такий вигляд:

access_modifier interface Name {
    return_type method_name1(parameters1);
    return_type method_name2(parameters2);

    // ...

    type var_name1 = value1;
    type var_name2 = value2;

    // ...

    return_type method_nameN(parametersN);
    type var_nameN = valueN;
}

тут

  • interface – ключове слово, що визначає, що оголошуваний елемент мови Java є інтерфейсом;
  • access_modifier – один з модифікаторів доступу public або abstract;
  • Name – ім’я інтерфейсу;
  • return_type – деякий тип, що повертає метод з іменем method_name1, method_name2, …, method_nameN;
  • parameters1, parameters2, …, parametersN – параметри методів method_name1, method_name2, …, method_nameN;
  • type – тип змінної, що оголошена в інтерфейсі;
  • var_name1, var_name2, var_nameN – імена змінних, які оголошені в інтерфейсі. Будь-яка змінна, що оголошена в інтерфейсі оголошується з модифікаторами final та static. Ця змінна повинна бути ініціалізована. В класі, що реалізує інтерфейс не можна змінити значення змінної.

 

3. Яка загальна форма реалізації інтерфейсу в класі? Ключове слово implements

Якщо інтерфейс є визначений, то його можна реалізувати в класі. Загальна форма реалізації інтерфейсу в класі має вигляд:

class SomeClass implements SomeInterface {
    // реалізація методів інтерфейсу та інших методів класу
    // ...
}

тут SomeClass – ім’я класу, що реалізує інтерфейс SomeInterface.

 

4. Що потрібно обов’язково виконати (реалізувати) в класі, який реалізує заданий інтерфейс?

Якщо клас реалізує інтерфейс, то для даного класу встановлюються наступні зобов’язання:

  • клас обов’язково повинен містити реалізацію методів, оголошених в цьому інтерфейсі;
  • сигнатура методів інтерфейсу повинна співпадати з сигнатурою цих же методів, реалізованих у класі;
  • методи, що реалізують елементи інтерфейсу, обов’язково мають бути оголошені в класі як public;
  • у класі заборонено змінювати значення змінних, оголошених в інтерфейсі.

 

5. Приклади оголошення інтерфейсів та класів, які їх реалізують

Приклад 1. У прикладі демонструється:

  • оголошення методів в інтерфейсі;
  • оголошення змінної в інтерфейсі;
  • реалізація інтерфейсу в класі;
  • використання посилання на інтерфейс для доступу до методів.

Нехай в межах пакету у файлі IMathFunctions.java оголошено інтерфейс з іменем IMathFunctions як показано нижче

// інтерфейс, що містить оголошення математичних функцій
public interface IMathFunctions {
    double pi=3.1415926535; // змінна, число Пі
    int Power(int x, int y); // x в степені y
    double AbsComplex(double real, double imag); // модуль комплексного числа
}

В інтерфейсі вказуються наступні оголошення:

  • змінна pi, яка визначає число Пі. Ця змінна неявно оголошена як final та static. Якщо деякий клас реалізує цей інтерфейс, то змінювати значення цієї змінної не можна;
  • математична функція Power(), яка призначена для піднесення числа до степеня;
  • математична функція AbsComplex(), яка повертає модуль комплексного числа.

Після оголошення інтерфейсу оголошується клас, який повинен реалізувати методи цього інтерфейсу. У нашому випадку оголошується клас MathFunctions

// клас, що реалізує інтерфейс IMathFuncitons
public class MathFunctions implements IMathFunctions {
    // Реалізація методів інтерфейсу IMathFunctions
    // 1. Модуль комплексного числа
    public double AbsComplex(double real, double imag) {
        double abs;
        abs = Math.sqrt(real*real+imag*imag);
        return abs;
    }

    // 2. Піднесення до степеня цілочисельних значень
    public int Power(int x, int y) {
        int p, i;
        p = 1;
        for (i=1; i<=y; i++)
            p=p*x;
        return p;
    }

    // Внутрішні методи класу
    // Визначення довжини кола
    public double Circumference(double radius) {
        return 2*pi*radius; // використовується змінна pi з інтерфейсу
    }
}

Використання інтерфейсу в класі може бути, наприклад, таким

// використання інтерфейсу
IMathFunctions mf = new MathFunctions(); // оголосити екземпляр класу MathFunctions
//IMathFunctions mf2 = new IMathFunctions(); помилка - заборонено оголошувати екземпляр інтерфейсу

// виклик інтерфейсних методів через екземпляр mf
int d;
double x;
d = mf.Power(3, 4);   // d = 81
x = mf.AbsComplex(2, 3); // x = 3.605551275463989

double pi;
pi = mf.pi; // pi = 3.1415926535

У вищенаведеному коді спочатку оголошується посилання mf на інтерфейс IMathFunctions. Потім для цього посилання mf створюється екземпляр класу MathFuncions. Така реалізація працює, оскільки клас MathFunctions реалізує (implements) інтерфейс IMathFunctions. З допомогою посилання mf можна викликати методи інтерфейсу.

Приклад 2. У прикладі демонструється використання інтерфейсу IStrings, що оголошує методи обробки рядка:

  • метод GetNSymbols(), який підраховує кількість символів в рядку;
  • метод ConvertOdd(), який повертає новий рядок, що складається з символів, що лежать на непарних позиціях.

Клас ProcessStrings реалізує інтерфейс IStrings.

Реалізація інтерфейсу міститься у файлі IStrings.java і має наступний вигляд:

public interface IStrings {
    // підраховує кількість заданих символів у рядку
    int GetNSymbols(char c, String s);

    // утворює новий рядок, який складається з символів рядка s,
    // що лежать на непарних позиціях: 1, 3, 5, ...
    String ConvertOdd(String s);
}

Реалізація класу описується в файлі ProcessStrings.java і має наступний вигляд

// клас, що реалізує інтерфейс IStrings
public class ProcessStrings implements IStrings {
    // реалізація методів, що оголошені в інтерфейсі
    // обчислити кількість символів у рядку s, має бути public-метод
    public int GetNSymbols(char c, String s) {
        int i;
        int k = 0;
        for (i=0; i<s.length(); i++)
            if (c==s.charAt(i))
                k++;
        return k;
    }

    // утворює новий рядок, який складається з символів рядка s,
    // що лежать на непарних позиціях: 1, 3, 5, ...
    public String ConvertOdd(String s) {
        String s2="";
        int i;
        for (i=0; i<s.length(); i++) {
            if (i%2==1) // якщо непарна позиція
                s2=s2+s.charAt(i);
        }
        return s2;
    }

    public static void main(String[] args) {
        // демонстрація роботи з інтерфейсом IStrings
        IStrings obj = new ProcessStrings();
        String s1 = "bestprog.net";
        String s2;
        int k;

        s2 = obj.ConvertOdd(s1); // s2 = "etrgnt"
        k = obj.GetNSymbols('t', s1); // k = 2
        System.out.println("s2 = " + s2);
        System.out.println("k = " + k);
    }
}

Як видно з коду, в класі ProcessStrings містяться реалізації методів GetNSymbols() та ConvertOdd(). Статична функція main() класу ProcessStrings є точкою входу в програму. У результаті виконання функції main(), буде виведено наступний результат:

s2 = etrgnt
k = 2

 

6. Чи можна створити екземпляр (об’єкт) інтерфейсу?

Оскільки, інтерфейс містить тільки оголошення без реалізації, то створити екземпляр інтерфейсу заборонено. Однак, можна оголошувати посилання на інтерфейс. У цьому випадку при виділенні пам’яті оператором new має бути вказаний конструктор класу, що реалізує даний інтерфейс.

 

7. У скількох класах може бути реалізований інтерфейс?

Інтерфейс може бути реалізований в будь-якій кількості класів. Наприклад, у коді нижче два різні класи з іменами SomeClass1, SomeClass2 реалізують один інтерфейс SomeInterface.

// деякий інтерфейс
interface SomeInterface {
    // ...
    void method1(int d);
    double method2(double x);
}

// клас, який реалізує інтерфейс
class SomeClass1 implements SomeInterface {
    // ...
    void method1(int d) {
        // реалізація методу
        // ...
    }

    double method2(double x) {
        // реалізація методу
        // ...
    }
}

// інший клас, що реалізує інтерфейс
class SomeClass2 implements SomeInterface {
    // ...
    void method1(int d) {
        // реалізація методу
        // ...
    }

    double method2(double x) {
        // реалізація методу
        // ...
    }
}

 

8. Скільки інтерфейсів може реалізувати один клас?

Клас може реалізувати будь-яку кількість інтерфейсів. У цьому випадку імена інтерфейсів розділяються комою. Наприклад, у наступному коді

class ClassName implements Interface1, Interface2, Interface3 {
    // ...
}

клас з іменем ClassName реалізує інтерфейси з іменами Interface1, Interface2, Interface3.

 

9. Який тип доступу обов’язково повинні мати методи, оголошені в інтерфейсі?

Методи, що оголошені в інтерфейсі повинні бути загальнодоступними, тобто повинні мати тип доступу public.

 

10. Який тип доступу за замовчуванням мають методи, що оголошені в інтерфейсі?

Якщо не вказано тип доступу в оголошенні методу, то ці методи мають тип доступу public. Наприклад, у нижченаведеному коді

interface SomeInterface {
    public void method1(int d);
    int method2(int x, int y);
}

обидва методи method1() та method2() мають тип доступу public.

 

11. Як викликати методи класу з допомогою посилань на інтерфейси?

Послідовність кроків наступна (див. приклад з п. 5):

  1. Оголосити посилання на інтерфейс
  2. Виділити пам’ять для посилання, вказавши конструктор класу, що реалізує даний інтерфейс.
  3. Викликати методи чи змінні, оголошені в інтерфейсі.

Наприклад. Нехай задано інтерфейс з іменем I та клас з іменем C. В інтерфейсі I оголошується метод

interface I {
    void method();
    int d = 5;
}

class C implements I {
    // ...
    // реалізація методу інтерфейсу I
    public void method() {
        // ...
    }
}

Використання методу method з врахуванням інтерфейсу I може бути наступним:

I obj; // 1. Оголосити посилання
obj = new C(); // 2. Створити екземпляр, використовуючи конструктор класу
obj.method(); // 3. Викликати інтерфейсний метод
int t = obj.d; // 3. Викликати інтерфейсну змінну

 

12. Вимоги до оголошення змінних в інтерфейсах

В інтерфейсі можна оголошувати змінну. Будь-яка змінна, що оголошена в інтерфейсі неявно оголошується з модифікаторами final та static. Ця змінна повинна бути ініціалізована. В класі, що реалізує інтерфейс не можна змінити значення змінної.

 

13. В яких випадках можна застосовувати специфікатор доступу public в оголошенні інтерфейсу?

Специфікатор доступу public можна застосовувати перед іменем інтерфейсу тільки у випадку, якщо інтерфейс визначений у файлі, який має те саме ім’я. Якщо ім’я інтерфейсу не співпадає з іменем файлу, то специфікатор public не можна використовувати в оголошенні інтерфейсу.

Наприклад. Задано файл з іменем IMyInterface.java. У цьому файлі можна оголосити public-інтерфейс з таким іменем

public interface MyInterface {
    // ...
}

 

14. Як додати оголошення інтерфейсу в Java Eclipse?

В системах, що реалізують програмування мовою Java, додавання інтерфейсів в проект реалізовано з допомогою спеціальних команд.

Щоб додати інтерфейс в деякий проект у системі програмування Java Eclipse потрібно виконати такі кроки.

1. Активувати проект, в який потрібно додати інтерфейс (рис. 1).

Java Eclipse проект активація

Рис. 1. Активування проекту з іменем Project15 в Java Eclipse

2. Викликати команду створення інтерфейсу

File->New->Interface

Java Eclipse. Команда додавання інтерфейсу до проекту

Рис. 2. Команда додавання інтерфейсу до проекту

У результаті відкриється вікно “New Java Interface” (рисунок 3).

3. У вікні “New Java Project” потрібно виконати такі дії (див. рисунок 3):

  • у полі “Source folder:” потрібно перевірити ім’я папки з проектом. У нашому випадку ім’я папки з проектом “Project15/src”. За бажанням можна встановити іншу папку;
  • у полі “Name:” потрібно задати ім’я інтерфейсу, наприклад, MyInterface.

Java Eclipse Вікно "New Java Interface"

Рис. 3. Вікно “New Java Interface”. Встановлення проекту Project15 та імені інтерфейсу MyInterface

4. Після вибору кнопки Finish інтерфейс з іменем MyInterface буде додано до проекту Project15 як показано на рисунку 4.

Java Eclipse вікно Package Explorer

Рис. 4. Відображення інтерфейсу у вікні Package Explorer та вікні MyInterface.java

Для інтерфейсу створюється окремий файл MyInterface.java. Як видно, ім’я файлу інтерфейсу та ім’я інтерфейсу співпадають. Також інтерфейс оголошено як public для того, щоб він був доступний з інших файлів, пакетів.

 


Зв’язані теми