Ці два приклади еквівалентні, і насправді будуть складені в один і той же байт-код.
Є два способи, що додавання обмеженого родового типу до методу, як у першому прикладі, зробить що завгодно.
Передача параметра типу іншому типу
Ці два підписи методу виявляються однаковими в байтовому коді, але компілятор застосовує безпеку типу:
public static <T extends Animal> void addAnimals(Collection<T> animals)
public static void addAnimals(Collection<Animal> animals)
У першому випадку допускається лише Collection
(або підтип) Animal
У другому випадку допускається Collection
(або підтип) із загальним типом Animal
або підтипом.
Наприклад, у першому методі дозволено наступне, але не другому:
List<Cat> cats = new ArrayList<Cat>();
cats.add(new Cat());
addAnimals(cats);
Причина полягає в тому, що другий дозволяє проводити колекції тварин, тоді як перший дозволяє збирати будь-який об'єкт, який можна віднести до тварин (тобто підтипи). Зауважте, що якби у цьому списку був список тварин, у яких трапилася кішка, будь-який метод прийняв би це: проблема полягає в загальній специфікації колекції, а не в тому, що вона насправді містить.
Повернення об'єктів
Інший раз, коли це важливо, це повернення об'єктів. Припустимо, існував такий метод:
public static <T extends Animal> T feed(T animal) {
animal.eat();
return animal;
}
Ви зможете зробити з ним наступне:
Cat c1 = new Cat();
Cat c2 = feed(c1);
Хоча це надуманий приклад, є випадки, коли це має сенс. Без дженерики метод повинен був би повернутися, Animal
і вам потрібно буде додати кастинг типів, щоб він працював (саме це компілятор додає до байтового коду все-таки поза кадром).
addAnimals(List<Animal>)
та додати Список котів!