Spec-Zone .ru
спецификации, руководства, описания, API
|
Когда Вы вынимаете элемент из a Collection
, следует бросить это к типу элемента, который сохранен в наборе. Помимо того, чтобы быть неудобным, это опасно. Компилятор не проверяет, что Ваш бросок является тем же самым как типом набора, таким образом, бросок может перестать работать во время выполнения.
Обобщения обеспечивают способ для Вас передать тип набора к компилятору, так, чтобы это могло быть проверено. Как только компилятор знает тип элемента набора, компилятор может проверить, что последовательно использовали набор и можно вставить корректное, набирает значения, вынимаемые из набора.
Вот простой пример, взятый из существующего учебного руководства по Наборам:
// Removes 4-letter words from c. Elements must be strings static void expurgate(Collection c) { for (Iterator i = c.iterator(); i.hasNext(); ) if (((String) i.next()).length() == 4) i.remove(); }
Вот тот же самый пример, измененный, чтобы использовать обобщения:
// Removes the 4-letter words from c static void expurgate(Collection<String> c) { for (Iterator<String> i = c.iterator(); i.hasNext(); ) if (i.next().length() == 4) i.remove(); }
Когда Вы видите код <Type>
, считайте это как" Type
"; объявление выше чтений как"Collection
из String c
." Код, используя обобщения является более четким и более безопасным. Мы устранили опасный бросок и много дополнительных круглых скобок. Что еще более важно мы переместили часть спецификации метода от комментария до его подписи, таким образом, компилятор может проверить во время компиляции, что ограничения типа не нарушаются во время выполнения. Поскольку программа компилирует без предупреждений, мы можем утвердить с уверенностью, что это не будет бросать a ClassCastException
во время выполнения. Результирующий эффект использования обобщений, особенно в больших программах, является улучшенной удобочитаемостью и устойчивостью.
Перефразировать Спецификацию Обобщений Лид Джилэд Брэча, когда мы объявляем c
иметь тип Collection<String>
, это говорит нам что-то о переменной c
это сохраняется везде, где и всякий раз, когда это используется, и компилятор гарантирует это (принятие, что программа компилирует без предупреждений). Бросок, с другой стороны, говорит нам что-то, что программист думает, истина в единственной точке в коде, и проверки VM, прав ли программист только во время выполнения.
В то время как основное использование обобщений является наборами, есть много другого использования. "Классы держателя," такой как WeakReference
и ThreadLocal
, все был generified, то есть, они были retrofitted, чтобы использовать обобщения. Более удивительно, class Class
был generified. Литералы класса теперь функционируют как маркеры типа, обеспечивая и время выполнения и информацию о типе времени компиляции. Это включает стилю статических фабрик, иллюстрируемых getAnnotation
метод в новом AnnotatedElement
интерфейс:
<T extends Annotation> T getAnnotation(Class<T> annotationType);Это - универсальный метод. Это выводит значение своего параметра типа
T
от его параметра, и возвратов соответствующий экземпляр T
, как иллюстрировано следующим отрывком: Author a = Othello.class.getAnnotation(Author.class);До обобщений необходимо бы бросить результат к
Author
. Также у Вас не было бы никакого способа осуществить проверку компилятора что фактический параметр, представленный подкласс Annotation
. Обобщения реализуются стиранием типа: универсальная информация о типе присутствует только во время компиляции, после которого она стирается компилятором. Основное преимущество этого подхода состоит в том, что он обеспечивает полную функциональную совместимость между универсальным кодом и кодом наследства, который использует непараметризованные типы (которые технически известны как необработанные типы). Основные недостатки - то, что информация о типе параметра не доступна во время выполнения, и что автоматически сгенерированные броски могут перестать работать, взаимодействуя с плохо ведомым себя кодом наследства. Есть, однако, способ достигнуть гарантируемый безопасность типов времени выполнения для универсальных наборов, взаимодействуя с плохо ведомым себя кодом наследства.
java.util.Collections
class был снабжен оборудованием с классами обертки, которые обеспечивают гарантируемую безопасность типов времени выполнения. Они подобны в структуре синхронизируемым и неподдающимся изменению оберткам. Эти "проверенные обертки набора" очень полезны для отладки. Предположите, что у Вас есть ряд строк, s
, в который некоторый код наследства загадочно вставляет целое число. Без обертки Вы не будете узнавать о проблеме, пока Вы не считаете проблемный элемент из набора, и автоматически сгенерированный бросок к String
сбои. В этой точке это должно слишком поздно определить источник проблемы. Если, однако, Вы заменяете объявление:
Set<String> s = new HashSet<String>();с этим объявлением:
Set<String> s = Collections.checkedSet(new HashSet<String>(), String.class);набор бросит a
ClassCastException
в точке, где код наследства пытается вставить целое число. Получающаяся трассировка стека позволит Вам диагностировать и восстанавливать проблему. Следует использовать обобщения всюду, Вы можете. Дополнительное усилие в коде generifying хорошо стоит усилений в ясности и безопасности типов. Это прямо, чтобы пользоваться универсальной библиотекой, но это требует некоторой экспертизе записать универсальную библиотеку, или к generify существующая библиотека. Есть один протест: Вы не можете использовать обобщения (или любые другие функции Тайгера), если Вы намереваетесь развернуть скомпилированный код на пред5.0 виртуальных машинах.
Если Вы знакомы с C++ 's шаблонный механизм, Вы могли бы думать, что обобщения подобны, но подобие является поверхностным. Обобщения не генерируют новый class для каждой специализации, и при этом они не разрешают "шаблонное метапрограммирование."
Есть намного больше, чтобы узнать об обобщениях. См.