русс | укр

Языки программирования

ПаскальСиАссемблерJavaMatlabPhpHtmlJavaScriptCSSC#DelphiТурбо Пролог

Компьютерные сетиСистемное программное обеспечениеИнформационные технологииПрограммирование

Все о программировании


Linux Unix Алгоритмические языки Аналоговые и гибридные вычислительные устройства Архитектура микроконтроллеров Введение в разработку распределенных информационных систем Введение в численные методы Дискретная математика Информационное обслуживание пользователей Информация и моделирование в управлении производством Компьютерная графика Математическое и компьютерное моделирование Моделирование Нейрокомпьютеры Проектирование программ диагностики компьютерных систем и сетей Проектирование системных программ Системы счисления Теория статистики Теория оптимизации Уроки AutoCAD 3D Уроки базы данных Access Уроки Orcad Цифровые автоматы Шпаргалки по компьютеру Шпаргалки по программированию Экспертные системы Элементы теории информации

Перегрузка


Дата добавления: 2015-06-12; просмотров: 550; Нарушение авторских прав


Следующий пример не компилируется, хотя на первый взгляд выглядит вполне разумно:

//: generics/UseList.java

// {CompileTimeError} (He компилируется)

import java.util.*;

 

public class UseList<W,T> {

void f(List<T> v) {}

void f(List<W> v) {}

}

Перегрузка метода создает идентичную сигнатуру типа вследствие стирания. В таких случаях следует определять методы с различающимися именами:

//: generics/UseList2.java

import java.util.*;

 

public class UseList2<W,T> {

void f1(List<T> v) {}

void f2(List<W> v) {}

}

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

 

Резюме

Мне довелось работать с шаблонами C++ с момента их появления. Скорее всего, приведенный далее аргумент я выдвигал в спорах чаще, чем большинство моих единомышленников. Лишь недавно я задумался над тем, насколько в действительности справедлив этот аргумент, — сколько раз проблема, которую я сейчас опишу, проникала в рабочий код?

Аргумент такой: одним из самых логичных мест для использования механизма параметризации являются контейнерные классы: List, Set, Map и т. д. До выхода Java SE5 объект, помещаемый в контейнер, преобразовывался в Object, и информация типа терялась. Если же вы хотели снова извлечь объект из контейнера, его приходилось преобразовывать к нужному типу. Я пояснял происходящее на примере List с элементами Cat (разновидность этого примера с Apple и Orange приведена в начале главы 11). Без параметризованной версии контейнера из Java SE5 вы помещаете и извлекаете из контейнера Object, поэтому в List с элементами Cat легко поместить объект Dog.

Однако версии Java, существовавшие до появления параметризации, не допускали злоупотреблений объектами, помещаемыми в контейнер. Если вы помещали Dog в контейнер Cat, а затем пытались интерпретировать все элементы контейнера как Cat, то при извлечении ссылки на Dog и ее преобразовании к Cat происходило преобразование RuntimeException. Проблема обнаруживалась, пусть и на стадии выполнения, а не во время компиляции.



В предыдущих изданиях книги я писал: «Это не просто мелкая неприятность, а потенциальный источник трудноуловимых ошибок. Если одна часть (или несколько частей) программы вставляет объекты в контейнер, а в другой части программы обнаруживается, что в контейнер был помещен недопустимый объект, вам придется искать, где именно была выполнена неверная операция вставки».

Но позже я задумался над этим аргументом, и у меня появились сомнения. Во-первых, насколько часто это происходит? Не помню, чтобы такая ошибка встретилась в моей программе. Когда я спрашивал людей на конференциях, мне тоже не удалось найти никого, с кем бы это случилось. В другой книге использовался пример списка с именем files, содержащего объекты String, — в этом примере казалось абсолютно логичным добавить в список объект типа File, так что объекту, вероятно, стоило присвоить имя fileNames. Какую бы проверку типов ни обеспечивал язык Java, программист все равно может написать малопонятную программу — а плохо написанная программа, даже если она компилируется, все равно остается плохо написанной. Вероятно, нормальный разработчик присвоит контейнеру понятное имя вроде cats, которое послужит предупреждением для программиста, пытающегося занести в контейнер другой объект, отличный от Cat. Но, даже если это и произойдет, как долго такая ошибка останется скрытой? Здравый смысл подсказывает, что исключение произойдет вскоре после начала тестирования с реальными данными.

Один автор даже предположил, что такая ошибка может «оставаться скрытой несколько лет». Но я что-то не помню потока сообщений от людей, у которых возникали проблемы с поиском ошибок «Dog в списке Cat», или хотя бы с их частым появлением. Так неужели такая заметная и довольно сложная возможность, как параметризация, была включена в Java из-за проблем такого рода? Я считаю, что побудительной причиной для включения параметризации в язык (не обязательно конкретной реализации ее в Java!) является выразительность, а не создание типизованных контейнеров. Типизованные контейнеры — всего лишь побочный эффект возможности создания универсального кода. Таким образом, хотя аргумент «Dog в списке Cat» часто используется для оправдания параметризации, этот аргумент спорен.

Из-за того, что параметризация была «встроена» в Java (а не проектировалась как составная часть языка с самого начала), некоторые контейнеры получились не такими мощными, как хотелось бы. Для примера взгляните на Map, особенно на методы containsKey(Object key) и get(Object key). Если бы эти классы проектировались в расчете на параметризацию, в этих методах вместо Object использовались бы параметризованные типы; тем самым обеспечивались бы необходимые проверки стадии компиляции. Скажем, в аналогичных контейнерахC++ тип ключа всегда проверяется во время компиляции.

Бесспорно, введение любого механизма параметризации в более позднюю версию языка, получившего широкое распространение, — крайне хлопотная затея. В C++ шаблоны были включены в исходную ISO-версию языка, так что они фактически всегда являлись его составной частью. В Java параметризация была введена лишь спустя 10 лет после выхода первой версии. Этот факт породил немало проблем с миграцией кода, а также оказал значительное влияние на архитектуру. В результате программисты страдают из-за близорукости, проявленной проектировщиками языка при создании версии 1.0. Конечно, при создании исходной версии они знали о шаблонах C++ и даже рассматривали возможность включения их в язык, но по тем или иным причинам решили этого не делать (скорее всего, просто торопились). В результате пострадал как язык, так и работающие на нем программисты. Только время покажет, как подход к параметризации в Java отразится на самом языке.


 



<== предыдущая лекция | следующая лекция ==>
Преобразования типов и предупреждения | Глава 15 МАССИВЫ


Карта сайта Карта сайта укр


Уроки php mysql Программирование

Онлайн система счисления Калькулятор онлайн обычный Инженерный калькулятор онлайн Замена русских букв на английские для вебмастеров Замена русских букв на английские

Аппаратное и программное обеспечение Графика и компьютерная сфера Интегрированная геоинформационная система Интернет Компьютер Комплектующие компьютера Лекции Методы и средства измерений неэлектрических величин Обслуживание компьютерных и периферийных устройств Операционные системы Параллельное программирование Проектирование электронных средств Периферийные устройства Полезные ресурсы для программистов Программы для программистов Статьи для программистов Cтруктура и организация данных


 


Не нашли то, что искали? Google вам в помощь!

 
 

© life-prog.ru При использовании материалов прямая ссылка на сайт обязательна.

Генерация страницы за: 0.61 сек.