К счастью, хороший ООП-язык поставляется с набором готовых контейнеров. В С++ это часть стандартной библиотеки С++, иногда называемая
С позиций проектирования, все, что вам действительно необходимо, — это контейнер, способный решить вашу задачу. Если один вид контейнера отвечает всем потребностям, нет основания использовать другие виды. Существует две причины, по которым вам приходится выбирать из имеющихся контейнеров. Во-первых, контейнеры предоставляют различные интерфейсы и возможности взаимодействия. Поведение и интерфейс стека отличаются от поведения и интерфейса очереди, которая ведет себя по-иному, чем множество или список. Один из этих контейнеров способен обеспечить более эффективное решение вашей задачи в сравнении с остальными. Во-вторых, разные контейнеры по-разному выполняют одинаковые операции. Лучший пример — это ArrayList и LinkedList. Оба представляют собой простые последовательности, которые могут иметь идентичные интерфейсы и черты поведения. Но некоторые операции значительно отличаются по времени исполнения. Скажем, время выборки произвольного элемента в ArrayList всегда остается неизменным вне зависимости от того, какой именно элемент выбирается. Однако в LinkedList невыгодно работать с произвольным доступом — чем дальше по списку находится элемент, тем большую задержку вызывает его поиск. С другой стороны, если потребуется вставить элемент в середину списка, LinkedList сделает это быстрее ArrayList. Эти и другие операции имеют разную эффективность, зависящую от внутренней структуры контейнера. На стадии планирования программы вы можете выбрать список LinkedList, а потом, в процессе оптимизации, переключиться на ArrayList. Благодаря абстрактному характеру интерфейса List такой переход потребует минимальных изменений в коде.
Параметризованные типы 35
Параметризованные типы
До выхода Java SE5 в контейнерах могли храниться только данные Object — единственного универсального типа Java. Однокорневая иерархия означает, что любой объект может рассматриваться как Object, поэтому контейнер с элементами Object подойдет для хранения любых объектов3.
При работе с таким контейнером вы просто помещаете в него ссылки на объекты, а позднее извлекаете их. Но если контейнер способен хранить только Object, то при помещении в него ссылки на другой объект происходит его преобразование к Object, то есть утрата его «индивидуальности». При выборке вы получаете ссылку на Object, а не ссылку на тип, который был помещен в контейнер. Как же преобразовать ее к конкретному типу объекта, помещенного в контейнер?
Задача решается тем же преобразованием типов, но на этот раз тип изменяется не по восходящей (от частного к общему), а по нисходящей (от общего к частному) линии. Данный способ называется
Впрочем, опасность не столь уж велика — при нисходящем преобразовании к неверному типу произойдет ошибка времени исполнения, называемая
Нисходящее преобразование и проверки типа во время исполнения требуют дополнительного времени и лишних усилий от программиста. А может быть, можно каким-то образом создать контейнер, знающий тип хранимых объектов, и таким образом устраняющий необходимость преобразования типов и потенциальные ошибки?