— Привіт! Давай продовжимо лекцію про Generic’и. Готовий слухати?
— Ага.
— Тоді починаємо.
Факт перший. У методів класу також можуть бути свої типи-параметри.
— Так, я знаю.
— Ні, я маю на увазі саме свої типи-параметри:
class Calculator
{
T add(T a, T b); //додати
T sub(T a, T b); //відняти
T mul(T a, T b); //помножити
T div(T a, T b); //поділити
}
Це типи-параметри саме методу (або методів). У класі параметрів немає. Можна навіть оголосити статичними методами і викликати їх без використання об'єкта.
— Зрозуміло. Сенс типів-параметрів у методах такий самий, як і в класах?
— Ага. Але і є дещо нове.
Як ти вже знаєш, в описі типу можна використовувати wildcard. Тоді уяви собі ситуацію:
public void doSomething(List<? extends MyClass> list)
{
for(MyClass object : list)
{
System.out.println(object.getState()); //тут все працює чудово
}
}
А ось що станеться, якщо ми захочемо додати до колекції новий елемент:
public void doSomething(List<? extends MyClass> list)
{
list.add(new MyClass()); //помилка!
}
Справа в тому, що в загальному випадку метод doSomething можна передати List з типом елементів не MyClass, а будь-який із спадкоємців MyClass. А до такого списку заносити об'єкти MyClass вже не можна!
— Ага. І що ж робити?
— Нічого. Конкретно в цій ситуації нічого не зробиш. Але це дало розробникам Java привід для роздумів. І вони вигадали нове ключове слово – super.
Його використання виглядає практично так само:
List<? super MyClass> list
Але між extends і super є істотна відмінність.
«? extends T» означає, що клас має бути спадкоємцем T.
«? super T» означає, що клас має бути предком T.
— Вау. А де це використовується?
— «? super T» використовується, коли метод збирається додавати до колекції об'єкт типу T. Тоді це може бути колекція типу T або будь-якого типу предка T.
— Ага. Посилання на об'єкт типу T можна присвоїти будь-якому батьківському типу для T.
— Чесно кажучи, цей підхід використовується не дуже часто. Тим паче він має і зворотний бік. Приклад:
public void doSomething(List<? super MyClass> list)
{
for(MyClass object : list) //помилка!
{
System.out.println(object.getState());
}
}
public void doSomething(List<? super MyClass> list)
{
list.add(new MyClass()); //тут все працює чудово
}
Тепер не працює перший приклад.
Оскільки колекція list може бути навіть List<Object> (Object самий верхній батько MyClass), фактично ми пишемо такий код, який писати не можна:
List<Object> list;
for(MyClass object : list) //помилка!
{
System.out.println(object.getState());
}
— Зрозуміло. Дякую за цікаву лекцію.
— Будь ласка.
ПЕРЕЙДІТЬ В ПОВНУ ВЕРСІЮ