Введение
Коллекции в Java
Фреймворк коллекций Java — это набор классов и интерфейсов, реализующих часто используемые структуры данных коллекций. Несмотря на название "фреймворк", он функционирует как библиотека. Фреймворк коллекций предоставляет как интерфейсы, определяющие различные типы коллекций, так и классы, реализующие эти интерфейсы.
Отличия от массивов
Коллекции и массивы схожи тем, что оба хранят ссылки на объекты и могут управляться как группа. Однако, в отличие от массивов, коллекциям не требуется задавать определенную емкость при создании экземпляра. Коллекции могут автоматически увеличиваться и уменьшаться в размере при добавлении или удалении объектов. Коллекции не могут хранить примитивные типы данных, такие как int, long или double. Вместо этого, коллекции могут хранить классы-обертки, такие как Integer, Long или Double.
Collections are generic and hence invariant, but arrays are covariant. This can be considered an advantage of generic objects such as when compared to arrays, because under circumstances, using the generic instead of an array prevents run time exceptions by instead throwing a compile time exception to inform the developer to fix the code. For example, if a developer declares an object, and assigns the object to the value returned by a new instance with a certain capacity, no compile time exception will be thrown. If the developer attempts to add a to this object, the java program will throw an On the other hand, if the developer instead declared a new instance of a as , the Java compiler will (correctly) throw a compile time exception to indicate that the code is written with incompatible and incorrect type, thus preventing any potential run time exceptions. The developer can fix the code by instantianting as an object. If the code is using Java SE7 or later versions, the developer can instatiate as an object by using the diamond operator
Collections are generic and hence reified, but arrays are not reified.
Коллекции являются обобщенными (generic) и, следовательно, инвариантными, а массивы – ковариантными. Это можно рассматривать как преимущество обобщенных объектов, например, ArrayList, по сравнению с массивами, поскольку в определенных ситуациях использование обобщенного ArrayList вместо массива предотвращает исключения во время выполнения, выбрасывая вместо этого исключение во время компиляции, чтобы уведомить разработчика об исправлении кода. Например, если разработчик объявляет объект ArrayList и присваивает ему значение, возвращаемое новым экземпляром с определенной емкостью, исключение во время компиляции выброшено не будет. Если же разработчик попытается добавить String в этот ArrayList, Java-программа выбросит ClassCastException. С другой стороны, если разработчик вместо этого объявит новый экземпляр как ArrayList<Integer>, компилятор Java (правильно) выбросит исключение во время компиляции, указывая на то, что код написан с использованием несовместимых и некорректных типов, тем самым предотвращая любые потенциальные исключения во время выполнения. Разработчик может исправить код, создав экземпляр как ArrayList<String>. Если код использует Java SE7 или более поздние версии, разработчик может создать экземпляр как ArrayList<String>, используя ромбовидный оператор (<>).
Collections are generic and hence invariant, but arrays are covariant. This can be considered an advantage of generic objects such as when compared to arrays, because under circumstances, using the generic instead of an array prevents run time exceptions by instead throwing a compile time exception to inform the developer to fix the code. For example, if a developer declares an object, and assigns the object to the value returned by a new instance with a certain capacity, no compile time exception will be thrown. If the developer attempts to add a to this object, the java program will throw an On the other hand, if the developer instead declared a new instance of a as , the Java compiler will (correctly) throw a compile time exception to indicate that the code is written with incompatible and incorrect type, thus preventing any potential run time exceptions. The developer can fix the code by instantianting as an object. If the code is using Java SE7 or later versions, the developer can instatiate as an object by using the diamond operator
Collections are generic and hence reified, but arrays are not reified.
Коллекции являются обобщенными и, следовательно, реифицированными, а массивы – нет.
Collections are generic and hence invariant, but arrays are covariant. This can be considered an advantage of generic objects such as when compared to arrays, because under circumstances, using the generic instead of an array prevents run time exceptions by instead throwing a compile time exception to inform the developer to fix the code. For example, if a developer declares an object, and assigns the object to the value returned by a new instance with a certain capacity, no compile time exception will be thrown. If the developer attempts to add a to this object, the java program will throw an On the other hand, if the developer instead declared a new instance of a as , the Java compiler will (correctly) throw a compile time exception to indicate that the code is written with incompatible and incorrect type, thus preventing any potential run time exceptions. The developer can fix the code by instantianting as an object. If the code is using Java SE7 or later versions, the developer can instatiate as an object by using the diamond operator
Collections are generic and hence reified, but arrays are not reified.
История
Реализации коллекций в версиях Java до JDK 1.2 включали небольшое количество классов структур данных, но не содержали фреймворка коллекций. Стандартными способами группировки объектов Java были массивы, классы Vector и Hashtable, которые, к сожалению, было сложно расширять и которые не реализовывали стандартный интерфейс. Для удовлетворения потребности в повторно используемых структурах данных были разработаны несколько независимых фреймворков, в том числе библиотека ObjectSpace Generic Collection Library (JGL), основной целью которой была совместимость с библиотекой стандартных шаблонов C++ (STL). Фреймворк коллекций был разработан в основном Джошуа Блохом и представлен в JDK 1.2. Он использовал множество идей и классов из пакета Collections, разработанного Дагом Ли, который впоследствии был объявлен устаревшим. Позже Даг Ли разработал пакет для работы с многопоточностью, включающий новые классы, связанные с коллекциями. Обновленная версия этих утилит для многопоточной работы была включена в JDK 5.0 в соответствии со спецификацией JSR 166.
Архитектура
Почти все коллекции в Java происходят от интерфейса Collection. Интерфейс Collection определяет основные части всех коллекций. Интерфейс имеет методы `add` и `remove` для добавления и удаления элементов из коллекции соответственно. Также он содержит метод `toArray`, который преобразует коллекцию в массив объектов, содержащихся в ней (с типом возвращаемого значения Object[]). Наконец, метод `contains` проверяет, существует ли указанный элемент в коллекции. Интерфейс Collection является под-интерфейсом Iterable, поэтому любую коллекцию можно использовать в цикле for-each. (Интерфейс Iterable предоставляет метод `iterator`, используемый в циклах for-each.) Все коллекции имеют итератор, который проходит по всем элементам коллекции. Collection является обобщенным (generic). Любая коллекция может хранить объекты любого типа. Например, любая реализация Collection содержит объекты. При использовании объектов из реализации Collection<String> не требуется приведение типов. Обратите внимание, что угловые скобки `<>` могут содержать аргумент типа, который указывает, объекты какого типа хранит коллекция.
method checks if a specified element exists in the Collection. The Collection interface is a subinterface of , so any Collection may be the target of a for each statement. (The Iterable interface provides the method used by for each statements.) All Collections have an that goes through all of the elements in the Collection. Collection is generic. Any Collection can store any For example, any implementation of contains objects. No casting is required when using the objects from an implementation of Collection<String>. Note that the angled brackets can hold a type argument that specifies which type the Collection holds.
Виды сбора
Существует несколько общих типов коллекций: очереди, отображения (maps), списки и множества. Очереди позволяют программисту добавлять элементы в определенном порядке и извлекать их в том же порядке. Примером может служить очередь ожидания. Базовые интерфейсы для очередей называются Queue. Отображения (maps) хранят ссылки на объекты с использованием ключа для доступа к значениям объекта. Примером ключа может служить удостоверение личности. Базовый интерфейс для отображений (maps) называется Map. Списки – это конечные коллекции, в которых можно хранить одно и то же значение несколько раз. Множества – это неупорядоченные коллекции, которые можно перебирать и содержать каждый элемент не более одного раза. Базовый интерфейс для множеств называется Set.
Класс вектора
Класс имеет в качестве прямого подкласса. Это пример нарушения принципа предпочтения композиции наследованию в библиотеках платформы Java, так как в информатике вектор, как правило, не является стеком. В данной ситуации композиция была бы более подходящим решением.
Класс стека
Класс Stack расширяет класс Vector с пятью операциями, позволяющими использовать Vector как стек. Стек создается с использованием конструктора. Stack предоставляет методы для помещения нового объекта в стек (метод push) и извлечения объектов из стека (метод pop). Стек возвращает объекты в соответствии с принципом "последний пришел – первый ушел" (LIFO), например, объект, который был помещен в стек последним, извлекается первым. java.util.Stack – это стандартная реализация стека, предоставляемая Java. Класс Stack представляет собой стек объектов, работающий по принципу "последний пришел – первый ушел" (LIFO). Класс Stack имеет пять дополнительных операций, позволяющих использовать Vector как стек. Предоставлены стандартные методы push и pop, а также метод peek для просмотра верхнего элемента стека, метод isEmpty для проверки, пуст ли стек, и метод search для поиска элемента в стеке и определения его расстояния от вершины. При создании стек изначально не содержит элементов.
Класс CopyOnWriteArrayList (Компьютерный файл)
The расширяет класс и не наследует от других классов. Он обеспечивает потокобезопасность без избыточной синхронизации. В некоторых случаях синхронизация необходима. Например, если метод изменяет статическое поле и должен вызываться несколькими потоками, то синхронизация обязательна, и не следует использовать средства параллельного выполнения, такие как . Однако синхронизация может приводить к снижению производительности. В ситуациях, когда синхронизация не обязательна, он является жизнеспособной и потокобезопасной альтернативой синхронизации, использующей многоядерные процессоры и обеспечивающей более высокую утилизацию ЦП.
Интерфейсы очереди
Интерфейс определяет структуру данных очереди, которая хранит элементы в порядке их добавления. Новые элементы добавляются в конец очереди, а удаляются – с начала. Это создает систему обслуживания "первым пришел – первым ушел" (FIFO). Этот интерфейс реализован в `java.util.LinkedList`, и .
Класс очереди приоритетов
Класс `java.util.PriorityQueue` реализует интерфейс `java.util.Queue`, но также изменяет его поведение. `PriorityQueue` имеет дополнительный метод. Элементы в `PriorityQueue` упорядочиваются не в порядке их добавления, а по приоритету. Приоритет определяется либо методом, реализованным в самих элементах, либо методом, указанным в конструкторе. Для поддержания сортировки класс использует структуру данных "куча".
Класс "Связанная очередь"
Класс `java.util.concurrent.ConcurrentLinkedQueue` расширяет `ConcurrentLinkedQueue` и реализует интерфейс. Класс `ConcurrentLinkedQueue` является потокобезопасной коллекцией, поскольку для любого элемента, помещенного внутрь, Java Collection Library гарантирует его безопасную публикацию, позволяя любому потоку получить этот элемент из коллекции. Объект считается безопасно опубликованным, если его состояние становится видимым для всех остальных потоков в один и тот же момент времени. Безопасная публикация обычно требует синхронизации потоков, публикующих и потребляющих данные.
Класс LinkedList
LinkedList, конечно, также реализует интерфейс List и может использоваться в качестве такового. Но он также предоставляет методы очереди. LinkedList реализует интерфейс Queue, что обеспечивает ему большую гибкость.
Класс ArrayDeque
ArrayDeque реализует интерфейс Queue на основе массива. Подобно LinkedList, ArrayDeque также реализует данный интерфейс.
Настройка интерфейсов
Интерфейс Java определяет Set. Set не может содержать дубликаты элементов. Кроме того, в Set нет заданного порядка. Следовательно, элементы нельзя найти по индексу. Set реализован классами HashSet, TreeSet и LinkedHashSet.
Настройка интерфейса
Существует несколько реализаций интерфейса Set, включая `HashSet` и его подклассы, а также финальный статический внутренний класс `EnumSet` (где `E` и `T` — формальные параметры типа).
Резюме
является скелетной реализацией интерфейса. Прямые подклассы включают , , , и .
Класс EnumSet
Класс расширяет. Класс не имеет публичных конструкторов и содержит только статические фабричные методы. Содержит статический фабричный метод. Этот метод является методом агрегации. Он принимает несколько параметров, учитывает тип параметров, затем возвращает экземпляр соответствующего типа. Начиная с 2018 года, в Java SE8 OpenJDK используется две реализации, невидимые для клиента, а именно и. Если он больше не обеспечивает прироста производительности для небольших типов перечислений, его можно удалить из библиотеки без негативного влияния на Java Collection Library. является хорошей заменой битовым полям, которые представляют собой тип множества, как описано ниже. Традиционно, когда разработчики сталкивались с элементами перечисляемого типа, которые необходимо было поместить в множество, они использовали шаблон int enum, в котором каждой константе присваивалась различная степень числа 2. Это битовое представление позволяло разработчику использовать побитовую операцию ИЛИ, чтобы объединять константы в множество, также известное как битовое поле. Такое представление битового поля позволяло разработчику выполнять эффективные операции над множествами и побитовую арифметику, такие как пересечение и объединение. Однако подход с битовыми полями имеет ряд недостатков. Битовое поле менее читаемо, чем константа int enum. Кроме того, если элементы представлены битовыми полями, невозможно выполнить итерацию по всем этим элементам. Рекомендуемой альтернативой является использование , где вместо битового поля используется int enum. Этот подход использует для представления набора значений, принадлежащих к одному и тому же типу. Поскольку реализует интерфейс и больше не требует использования побитовых операций, этот подход более типобезопасен. Кроме того, существует множество статических фабрик, позволяющих создавать объекты, например, метод метода. После появления битовое представление считается устаревшим.
of these elements. A recommended alternative approach is to use an , where an int enum is used instead of a bit field. This approach uses an to represent the set of values that belong to the same type. Since the implements the interface and no longer requires the use of bit wise operations, this approach is more type safe. Furthermore, there are many static factories that allow for object instantiation, such as the method method. After the introduction of the , the bit field representation approach is considered to be obsolete.
Класс HashSet
HashSet использует хеш-таблицу. Более конкретно, он использует её для хранения хешей и элементов и предотвращения дубликатов.
Класс LinkedHashSet
Класс `java.util.LinkedHashSet` расширяет `HashSet`, создавая двусвязный список, который связывает все элементы в порядке их добавления. Это обеспечивает предсказуемый порядок итерации по множеству.
Класс CopyOnWriteArraySet (Компьютерный файл)
является конкурентной заменой синхронизированной коллекции. Она обеспечивает повышенную конкуренцию во многих ситуациях, избавляя от необходимости выполнять синхронизацию или создавать копию объекта во время итерации, подобно тому, как является конкурентной заменой синхронизированной коллекции. С другой стороны, как и , не следует использовать, когда синхронизация необходима.
Интерфейс SortedSet
Интерфейс `java.util.SortedSet` расширяет интерфейс `java.util.Set`. В отличие от обычного `Set`, элементы в `SortedSet` отсортированы либо методом `compareTo` самого элемента, либо методом, предоставленным конструктору `SortedSet`. Первый и последний элементы `SortedSet` можно получить с помощью методов `first` и `last` соответственно, а подмножества можно создавать, указывая минимальные и максимальные значения, а также начало или конец `SortedSet`. Класс `java.util.TreeSet` реализует интерфейс `SortedSet`.
Интерфейс навигационного сета
Интерфейс расширяет интерфейс `java.util.SortedSet` и имеет несколько дополнительных методов. Методы `lower()`, `floor()`, `ceiling()`, и `higher()` находят элемент в множестве, ближайший к заданному параметру. Кроме того, предоставляется нисходящий итератор по элементам множества. Как и `SortedSet`, `java.util.TreeSet` реализует `NavigableSet`.
Класс TreeSet
java.util.TreeSet использует красно-чёрное дерево, реализованное на основе красно-чёрного дерева. Красно-чёрное дерево гарантирует отсутствие дубликатов. Кроме того, это позволяет TreeSet реализовать .
Класс ConcurrentSkipListSet
Действует как параллельная замена реализациям синхронизированного метода. Например, заменяет метод `synchronized`, обёрнутый методом `...`.
Интерфейсы карт
Карты определяются интерфейсом в Java.
Реализации интерфейса карт
Карты — это структуры данных, которые связывают ключ с элементом. Это делает карту очень гибкой. Если ключ является хэш-кодом элемента, то карта по сути представляет собой множество. Если это просто возрастающий номер, она становится списком. Примеры реализаций включают , , и .
Класс AbstractMap
является примером скелетной реализации. К непосредственным подклассам класса относятся , , , , и .
EnumMap (полное название)
extends имеет сопоставимую скорость с массивом, индексированным по порядковому номеру. Это происходит потому, что EnumMap внутренне использует массив, при этом детали реализации полностью скрыты от разработчика. Таким образом, EnumMap сочетает в себе типобезопасность Enum и преимущества производительности массива.
ХешМэп
использует хеш-таблицу. Хэши ключей используются для поиска элементов в различных ячейках. Это коллекция, основанная на хешировании.
LinkedHashMap (поиск по ссылке)
расширяется за счет создания двусвязного списка между элементами, что позволяет обращаться к ним в порядке их добавления в карту. Содержит защищенный метод removeEldestEntry, который вызывается методом put при добавлении нового ключа в карту. Карта удаляет самую старую запись, когда метод removeEldestEntry возвращает true. Метод removeEldestEntry можно переопределить.
Карта дерева
, в отличие от и , использует красно-чёрное дерево. Ключи используются как значения для узлов дерева, а узлы указывают на элементы в Map.
ConcurrentHashMap (показать)
похожа на и также является коллекцией, основанной на хэш-таблицах. Однако существует ряд различий, например, в используемой стратегии блокировки. The использует совершенно иную стратегию блокировки для обеспечения повышенной масштабируемости и параллельности. не синхронизирует каждый метод, используя один и тот же замок. Вместо этого она использует механизм, известный как разделение блокировок (lock striping). Этот механизм обеспечивает более гранулярную блокировку и позволяет добиться большей степени совместного доступа.
Класс ConcurrentSkipListMap (Смешанный переход)
Действует как одновременная замена реализациям синхронизированного. Очень похож на , поскольку заменяет объект, который был обернут методом .
Интерфейс SortedMap
Интерфейс расширяет интерфейс `java.util.Map`. Этот интерфейс определяет `Map`, отсортированную по предоставленным ключам. Используя, снова, метод `compareTo` или метод, предоставленный в конструкторе `SortedMap`, пары ключ-значение сортируются по ключам. Первый и последний ключи в `Map` могут быть получены с помощью методов `firstKey()` и `lastKey()` соответственно. Кроме того, подкарты могут быть созданы из минимального и максимального ключей с помощью метода `subMap()`. `SortedMap` реализован классом `java.util.TreeMap`.
Интерфейс навигационной карты
Интерфейс расширяет `java.util.SortedMap` различными способами. Можно вызывать методы, которые находят ключ или элемент карты, наиболее близкий к заданному ключу в любом направлении. Карта также может быть перевернута, и из нее можно получить итератор в обратном порядке. Реализован классом `java.util.TreeMap`.
Интерфейс ConcurrentMap
Интерфейс расширяет интерфейс `java.util.Map`. Этот интерфейс является потокобезопасным и был представлен в Java Collections Framework версии 1.5 языка программирования Java.
Расширения для Java collections framework
Фреймворк Java Collections расширяется библиотекой Apache Commons Collections, которая добавляет типы коллекций, такие как множество с повторениями (bag) и двунаправленное отображение (bidirectional map), а также инструменты для создания объединений и пересечений. Google выпустила собственные библиотеки коллекций в составе библиотек Guava.