Забезпечення типової безпеки з допомогою узагальнень. Узагальнені інтерфейси. Приклади
Зміст
- 1. Типова безпека. Забезпечення типової безпеки з допомогою узагальнень. Приклад
- 2. Узагальнений інтерфейс. Особливості використання
- 3. Приклад оголошення та використання узагальненого інтерфейсу з одним параметром типу
- 4. Простий приклад оголошення узагальненого інтерфейсу та його використання в узагальненому класі, який використовує 3 параметри типу T1, T2, T3
- Зв’язані теми
Пошук на інших ресурсах:
1. Типова безпека. Забезпечення типової безпеки з допомогою узагальнень. Приклад
Основна перевага узагальнень – забезпечення типової безпеки. Якщо у програмі використовуються узагальнення і міститься некоректний код приведення типів (наприклад, приведення рядка в число), то компілятор фіксує помилки на етапі компіляції а не на етапі виконання. Якщо помилка знайдена на етапі компіляції, то це є краще ніж визначення помилки на етапі виконання. Генерування помилки на етапі виконання є неприпустимим.
У мові Java суперкласом для всіх класів є клас Object. Це дає можливість оголошувати посилання на тип Object і використовувати їх для приведення до будь-якого типу. Однак, такий підхід не забезпечує типової безпеки, у результаті чого помилки будуть компілюватись і виникати на етапі виконання, а це є неприпустимо.
Приклад. У прикладі показані наступні переваги застосування узагальнень порівняно з використанням посилання на тип Object:
- при використанні узагальнень для базових типів (int, double, float та інших) не потрібно виконувати явне приведення типу. При використанні посилання на тип Object явне приведення є обов’язковим;
- при використанні узагальнень забезпечується типова безпека (помилки несумісного присвоєння визначаються на етапі компіляції). При використанні посилання на тип Object типова безпека не забезпечується (помилки несумісного присвоєння визначаються на етапі виконання).
Задано два класи:
- клас ClassObject – використовує посилання на тип Object. Оскільки тип Object є базовим для всіх типів (класів), то це посилання можна привести до будь-якого іншого типу;
- узагальнений клас ClassGen<T>, який використовує параметризований тип T.
// Клас, що використовує посилання на тип Object class ClassObject { // Деяке значення - має тип Object private Object value; // Конструктор ClassObject(Object _value) { value = _value; } // Методи доступу Object GetValue() { return value; } void SetValue(Object _value) { value = _value; } } // Узагальнений клас - забезпечує типову безпеку, // помилка виникає на етапі компіляції, а не на етапі виконання. class ClassGen<T> { private T value; // Конструктор public ClassGen(T value) { this.value = value; } // Методи доступу public T GetValue() { return value; } void SetValue(T value) { this.value = value; } }
У третьому класі Test реалізовано два статичні методи Test_ClassObject() та TestClassGen(). У цих методах навмисно виконується помилкова операція присвоєння числу objInt рядка objString
objInt = objString;
тут
- objInt – об’єкт типу Integer (число);
- objString – об’єкт типу String (рядок).
У методі Test_ClassGen() ця помилкова операція виявляється на етапі компіляції. Тобто, виконання програми не відбудеться, поки ця помилка не буде виправлена. У цьому випадку спрацьовує механізм типової безпеки.
У методі Test_ClassObject() помилка виявляється на етапі виконання (етап компіляції не визначає помилку). Тобто механізм типової безпеки не спрацьовує. А це є недопустимо.
public class Test { // Метод, що тестує клас, в якому оголошується посилання типу Object public static void Test_ClassObject() { // Створити екземпляр типу Integer і присвоїти змінній типу int його значення ClassObject objInt = new ClassObject(25); int vInt = (Integer)objInt.GetValue(); // тут потрібне явне приведення типів // Створити екземпляр типу String ClassObject objString = new ClassObject("Hello"); String vString = (String)objString.GetValue(); // тут також потрібне явне приведення типів // Присвоїти змінній типу Integer значення змінної типу String objInt = objString; // тут компілятор помилки не видає - це є неправильно (???) int value = (Integer)objInt.GetValue(); // помилка на етапі виконання!!! } // Клас, що використовує механізм узагальнень public static void Test_ClassGen() { // Створити екземпляр типу Integer ClassGen<Integer> objInt = new ClassGen<Integer>(25); int vInt = objInt.GetValue(); // тут не потрібне явне приведення типів // Створити екземпляр типу String ClassGen<String> objString = new ClassGen<String>("Hello"); String vString = objString.GetValue(); // тут також не потрібне явне приведення типів // Присвоїти типу Integer значення типу String objInt = objString; // помилка на етапі компіляції - спрацьовує типова безпека } public static void main(String[] args) { // Виклик методів тестування Test_ClassObject(); Test_ClassGen(); } }
⇑
2. Узагальнений інтерфейс. Особливості використання
У мові Java допускається оголошувати інтерфейс, який використовує один або декілька узагальнених типів. Загальна форма оголошення узагальненого інтерфейсу з іменем InterfaceName, який використовує тип T, наступна:
interface InterfaceName<T> {
...
}
Загальна форма узагальненого інтерфейсу, який використовує декілька узагальнених типів, наступна:
interface InterfaceName<T1, T2, ..., TN> {
...
}
тут
- InterfaceName – ім’я узагальненого інтерфейсу, який використовує типи T1, T2, …, TN.
⇑
3. Приклад оголошення та використання узагальненого інтерфейсу з одним параметром типу
У прикладі оголошується один узагальнений інтерфейс IValue<T> та узагальнений клас Value<T>. Інтерфейс та клас отримують параметром тип T. В інтерфейсі оголошується метод Show(), який у класі реалізується. Клас містить внутрішню змінну value.
У класі GenInterface реалізовано дві статичні функції, які демонструють використання інтерфейсу IValue<T> та класу Value<T>.
// Інтерфейс, що використовує один параметр типу T interface IValue<T> { // Методи доступу до величини T GetValue(); void SetValue(T value); // Метод Show() - виводить інформацію про величину void Show(); } // Узагальнений клас, що реалізує інтерфейс IValue<T> class Value<T> implements IValue<T> { // Внутрішні змінні класу T value; // Конструктор public Value(T _value) { value = _value; } // Реалізація методів інтерфейсу public T GetValue() { return value; } public void SetValue(T value) { this.value = value; } // Реалізація методу Show() інтерфейсу public void Show() { System.out.println("value = " + value); } } public class GenInterface { // Метод, що отримує посилання на інтерфейс IValue public static void ShowValue(IValue ref) { ref.Show(); } public static void main(String[] args) { // 1. Оголосити посилання на інтерфейс IValue<T> IValue<Double> refV; // 2. Створити екземпляр класу Value<T> Value<Double> obj = new Value<Double>(5.88); // 3. Перевірка методу GetValue() класу Value<T> double t = obj.GetValue(); System.out.println("t = " + t); // t = 5.88 // 4. Перевірка методу SetValue() obj.SetValue(7.777); t = obj.GetValue(); System.out.println("t = " + t); // t = 7.777 // 5. Перевірка методу Show() obj.Show(); // value = 7.777 // 6. Виклик статичного методу ShowValue() з параметром посилання на інтерфейс refV refV = obj; // Присвоїти посиланню адресу екземпляру класу Value<T> ShowValue(refV); // value = 7.777 // 7. Виклик статичного методу ShowValue() з параметром екземпляру obj ShowValue(obj); // value = 7.777 } }
Результат виконання програми
t = 5.88 t = 7.777 value = 7.777 value = 7.777 value = 7.777
⇑
4. Простий приклад оголошення узагальненого інтерфейсу та його використання в узагальненому класі, який використовує 3 параметри типу T1, T2, T3
Даний приклад є демонстрацією оголошення та використання узагальнених інтерфейсів у мові Java.
У прикладі продемонстровано використання узагальненого інтерфейсу з іменем MyInterface. Інтерфейс оголошує методи, що оперують трьома типами T1, T2, T3. Також оголошується клас MyClass<T1, T2, T3>, що реалізує інтерфейс MyInterface<T1, T2, T3>. У класі оголошуються три внутрішні змінні, які мають відповідно типи T1, T2, T3.
// Інтерфейс, який використовує 3 узагальнених типи interface MyInterface<T1, T2, T3> { // В інтерфейсі вказуються методи, які використовують типи T1, T2, T3 // Повернути значення змінних типів T1, T2, T3 T1 GetT1(); T2 GetT2(); T3 GetT3(); // Встановити значення змінних типів T1, T2, T3 void SetT1(T1 obj); void SetT2(T2 obj); void SetT3(T3 obj); // Метод виведення значень змінних void Print(String text); } // Клас, який реалізує інтерфейс MyInterface<T1, T2, T3>. // В оголошенні класу обов'язково потрібно вказувати імена типів T1, T2, T3. class MyClass<T1, T2, T3> implements MyInterface<T1, T2, T3> { // Внутрішні змінні класу T1 var1; T2 var2; T3 var3; // Конструктор класу public MyClass(T1 var1, T2 var2, T3 var3) { this.var1 = var1; this.var2 = var2; this.var3 = var3; } // Методи, які оголошені в інтерфейсі MyInterface<T1, T2, T3> public T1 GetT1() { return var1; } public T2 GetT2() { return var2; } public T3 GetT3() { return var3; } public void SetT1(T1 var1) { this.var1 = var1; } public void SetT2(T2 v2) { var2 = v2; } public void SetT3(T3 v3) { this.var3 = v3; } public void Print(String comment) { System.out.println(comment); System.out.println("var1 = " + var1); System.out.println("var2 = " + var2); System.out.println("var3 = " + var3); } } public class GenInterface { public static void main(String[] args) { // Демонстрація використання узагальненого інтерфейсу MyInterface<T1, T2, T3> // 1. Оголосити посилання на інтерфейс, який використовує типи Integer, Character та Long MyInterface<Integer, Character, Long> ref; // 2. Оголосити екземпляр класу MyClass, який обробляє типи Integer, Character, Long MyClass<Integer, Character, Long> obj = new MyClass<Integer, Character, Long>(25, 'z', 3223232332L); // 3. Отримати значення типу Integer (int) - метод GetT1() int vInt = obj.GetT1(); System.out.println("vInt = " + vInt); // 4. Отримати значення типу Character (char) - метод GetT2() char vChar1 = obj.GetT2(); Character vChar2 = obj.GetT2(); // так теж можна System.out.println("vChar1 = " + vChar1); System.out.println("vChar2 = " + vChar2); // 5. Отримати значення типу Long (long) - метод GetT3() long vLong; vLong = obj.GetT3(); System.out.println("vLong = " + vLong); // 6. Вивести усі внутрішні змінні - метод Print() obj.Print("-----------------"); } }
Результат виконання програми
vInt = 25 vChar1 = z vChar2 = z vLong = 3223232332 ----------------- var1 = 25 var2 = z var3 = 3223232332
⇑
Зв’язані теми
- Узагальнення. Параметризовані типи. Узагальнені класи, інтерфейси, методи
- Обмежені типи. Метасимвольні аргументи. Приклади
⇑