Что означает <E>в коллекции <E>? - PullRequest
12 голосов
/ 29 июня 2009

Какое значение имеет <E> в коде Collection<E>?

Ответы [ 2 ]

18 голосов
/ 29 июня 2009

Это означает, что вы имеете дело с коллекцией предметов типа E. Представь, что у тебя есть чашка чая. Вместо чая он также может содержать кофе, поэтому имеет смысл описать чашку как общую сущность:

class Cup<T> { … }

теперь вы можете заполнить его кофе или чаем (или еще чем-нибудь):

Cup<Tea> cuppa = new Cup<Tea>();
Cup<Coffee> foamee = new Cup<Coffee>();

Для того, чтобы это работало, оба типа Tea и Coffee должны быть также определены в вашей программе.

Это ограничение времени компиляции для вашего кода. Возвращаясь к (довольно бесполезному) примеру кубка, коллекции (массивы, списки ...) обычно содержат элементы типа one , например, целые числа или строки. Обобщения помогут вам выразить это на Java:

Collection<String> strList = new ArrayList<String>();
strList.add("Foobar"); // Works.
strList.add(42);       // Compile error!

Заметили ошибку компиляции выше? Вы получаете это только при использовании дженериков. Следующий код также работает, но не выдает красивое сообщение об ошибке:

Collection strList = new ArrayList();
strList.add("Foobar"); // Works.
strList.add(42);       // Works now. Do we really want this?!
15 голосов
/ 29 июня 2009

Это использование дженериков. Проверьте это вступление . И затем не забудьте прочитать этот учебник .

Далее следует выдержка (которая сравнивает использование приведения с использованием дженериков):

Когда вы видите код , прочитайте его как «Типа»; декларация выше читается как «Коллекция строк c.» код с использованием дженериков яснее и безопаснее. Мы устранили небезопасные актерский состав и ряд дополнительных скобки. Что еще более важно, у нас есть переехал часть спецификации из метод из комментария к его подпись, чтобы компилятор мог проверить во время компиляции, что тип ограничения не нарушаются при запуске время. Потому что программа компилируется без предупреждения, мы можем заявить с уверенность, что это не бросит ClassCastException во время выполнения. чистый эффект от использования дженериков, особенно в больших программах, это улучшенная читаемость и надежность.

Например, интерфейс списка

public interface List<E> { 
    void add(E x);
    Iterator<E> iterator();
}

Это означает, что вы можете создать список, все содержимое которого имеет один и тот же явный тип (не только тип Object), даже если вы определили тип самостоятельно. Итак, если вы создаете класс Name, вы можете написать

List<Name> nameList = new ArrayList<>();

, а затем заполните его экземплярами Name и напрямую извлекайте из него экземпляры Name, не вызывая и не беспокоясь о нем, потому что вы всегда получите либо экземпляр Name, либо нулевой ответ, а не экземпляр другого типа.

Что еще более важно, вы не можете вставить что-либо, отличное от экземпляра Name, в такой список, потому что он потерпит неудачу во время компиляции.

nameList.add(false); //Fails!
nameList.add(new Name("John","Smith")); //Succeeds supposing Name has a 
                                        //firstName, lastName constructor
...