— Привет! Я продолжу лекцию Элли про 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());
}
— Ясно. Спасибо за интересную лекцию.
— Пожалуйста.
ПЕРЕЙДИТЕ В ПОЛНУЮ ВЕРСИЮ