Обобщения в Java: часть 1 - Нижние пределы

ОГЛАВЛЕНИЕ

Нижние пределы

Рассмотрим последний пример. Допустим, надо скопировать элементы из одной коллекции в другую. Ниже приведен код первой попытки сделать это:

public static <T> void copy(Collection<T> from, Collection<T> to) {…}

Попытаемся использовать данный метод:

ArrayList<Dog> dogList1 = new ArrayList<Dog>();
ArrayList<Dog> dogList2 = new ArrayList<Dog>();
//…
copy(dogList1, dogList2);

В этом коде копируются Dog из одного Dog ArrayList в другой. Поскольку Dog является Animal, Dog может находиться в Dog ArrayList и в Animal ArrayList, не так ли? Следующий код копирует из Dog ArrayList в Animal ArrayList.

ArrayList<Animal> animalList = new ArrayList<Animal>();
copy(dogList1,  animalList);

Однако при компиляции этого кода выдается ошибка:

Error:  
line (36) <T>copy(java.util.Collection<T>,java.util.Collection<T>)
in com.agiledeveloper.Test cannot be applied
to (java.util.ArrayList<com.agiledeveloper.Dog>,
java.util.ArrayList<com.agiledeveloper.Animal>)

Как заставить его работать? Здесь помогают нижние пределы. Второй аргумент Copy должен иметь тип T или любой тип, являющийся базовым типом T. Код выглядит так:

public static <T> void copy(Collection<T> from, Collection<? super T> to)

Здесь сказано, что принимаемый второй коллекцией тип является типом T или его супертипом.

Заключение

На примерах была показана мощь обобщений в Java. Однако с использованием обобщений в Java есть проблемы, которые будут рассмотрены в части II данной статьи. В части II будут разобраны некоторые ограничения обобщений, реализация обобщений в Java, эффект стирания типа, изменения в библиотеке классов Java ради обеспечения обобщений, проблемы преобразования необобщенного кода в обобщенный код, и, наконец, некоторые из подводных камней или недостатков обобщений.

В части I были рассмотрены принципы обобщений в Java и их применение. Обобщения обеспечивают безопасность типов. Обобщения реализованы так, чтобы обеспечить обратную совместимость с необобщенным кодом. Они проще шаблонов в C++ и не вызывают раздувания кода при компиляции. В части II разбираются проблемы применения обобщений.