Недавно я увидел очень хорошее описание структуры коллекций в книге по J2EE, отфильтровал ее и опубликовал, чтобы поделиться ею со всеми. Фреймворк коллекций предоставляет интерфейсы и классы для управления коллекциями объектов. Ниже приводится описание каждого компонента.
Интерфейс коллекции
Коллекция — это самый простой интерфейс коллекции. Коллекция представляет собой набор объектов, то есть элементов коллекции. Некоторые коллекции допускают идентичные элементы, а другие — нет. Некоторые вроде, а другие нет. Java SDK не предоставляет классы, которые напрямую наследуются от Collection. Все классы, предоставляемые Java SDK, представляют собой «подинтерфейсы», наследуемые от Collection, такие как List и Set.
Все классы, реализующие интерфейс Collection, должны предоставлять два стандартных конструктора: конструктор без параметров для создания пустой Collection и конструктор параметров Collection для создания новой Collection. Входная коллекция содержит те же элементы. Последний конструктор позволяет пользователю копировать коллекцию.
Как перебирать каждый элемент коллекции? Независимо от фактического типа коллекции, он поддерживает метод iterator(), который возвращает итератор, который можно использовать для доступа к каждому элементу коллекции один за другим. Типичное использование выглядит следующим образом:
Скопируйте код кода следующим образом:
Итератор it = Collection.iterator(); // Получаем итератор.
в то время как (it.hasNext ()) {
Object obj = it.next(); // Получаем следующий элемент.
}
Два интерфейса, производные от интерфейса Collection, — это List и Set.
Интерфейс списка Список представляет собой упорядоченную коллекцию. Используя этот интерфейс, вы можете точно контролировать позицию вставки каждого элемента. Пользователи могут получать доступ к элементам в списке, используя индекс (положение элемента в списке, аналогичный нижнему индексу массива), который аналогичен массиву Java.
В отличие от упомянутого ниже Set, List допускает те же элементы.
В дополнение к методу iterator(), необходимому для интерфейса Collection, List также предоставляет метод listIterator(), который возвращает интерфейс ListIterator. По сравнению со стандартным интерфейсом Iterator, ListIterator имеет еще несколько методов add() и других, позволяющих добавлять дополнения. Удаление, установка элементов и перемещение вперед или назад.
Распространенными классами, реализующими интерфейс List, являются LinkedList, ArrayList, Vector и Stack.
Класс LinkedList LinkedList реализует интерфейс List и допускает нулевые элементы. Кроме того, LinkedList предоставляет дополнительные методы получения, удаления и вставки в начале или конце LinkedList. Эти операции позволяют использовать LinkedList в качестве стека, очереди или двухсторонней очереди.
Обратите внимание, что LinkedList не имеет синхронизированных методов. Если несколько потоков одновременно обращаются к списку, они должны сами реализовать синхронизацию доступа. Одним из обходных путей является создание синхронизированного списка при создании списка:
Список списка = Collections.synchronizedList(new LinkedList(...));
Класс ArrayList ArrayList реализует массивы переменного размера. Он допускает все элементы, включая null. ArrayList не синхронизирован.
Время выполнения методов size, isEmpty, get и set является постоянным. Однако стоимость метода добавления является амортизируемой константой, а добавление n элементов требует времени O(n). Другие методы имеют линейное время работы.
Каждый экземпляр ArrayList имеет емкость (Capacity), которая представляет собой размер массива, используемого для хранения элементов. Эта емкость увеличивается автоматически по мере добавления новых элементов, но алгоритм роста не определен. Если необходимо вставить большое количество элементов, можно вызвать метод обеспеченияКапасити, чтобы увеличить емкость ArrayList перед вставкой и повысить эффективность вставки.
Как и LinkedList, ArrayList также не синхронизирован.
Векторный класс Vector очень похож на ArrayList, но Vector синхронизируется. Хотя итератор, созданный вектором, имеет тот же интерфейс, что и итератор, созданный ArrayList, поскольку вектор синхронизирован, когда итератор создается и используется, другой поток изменяет состояние вектора (например, добавляя или удаляя какой-либо элемент). , ConcurrentModificationException будет выброшено при вызове метода Iterator, поэтому исключение необходимо перехватить.
Класс стека Стек наследует от Vector и реализует стек «последним пришел — первым ушел». Stack предоставляет 5 дополнительных методов, которые позволяют использовать Vector в качестве стека. Базовые методы push и pop, а также метод peek получают элемент на вершине стека, метод пустой проверяет, пуст ли стек, а метод поиска определяет положение элемента в стеке. Стек — это пустой стек после его создания.
Установить интерфейс Set — это коллекция, которая не содержит повторяющихся элементов, то есть любые два элемента e1 и e2 имеют e1.equals(e2)=false, а Set содержит не более одного нулевого элемента.
Очевидно, что конструктор Set имеет ограничение, согласно которому переданный параметр Collection не может содержать повторяющиеся элементы.
Обратите внимание: с изменяемыми объектами следует обращаться осторожно. Если изменяемый элемент в Set изменит свое состояние, вызывая Object.equals(Object)=true, это вызовет некоторые проблемы.
Интерфейс карты <BR>Обратите внимание, что карта не наследует интерфейс коллекции. Карта предоставляет ключ для сопоставления значений. Карта не может содержать один и тот же ключ, и каждый ключ может отображать только одно значение. Интерфейс карты предоставляет три вида представлений наборов. Содержимое карты можно рассматривать как набор наборов ключей, набор наборов значений или набор сопоставлений ключ-значение.
Класс хеш-таблицы Hashtable наследует интерфейс Map и реализует хеш-таблицу сопоставления ключ-значение. Любой ненулевой объект может использоваться в качестве ключа или значения.
Чтобы добавить данные, используйте put(key, value), а для удаления данных используйте get(key). Временные затраты на эти две основные операции постоянны.
Hashtable регулирует производительность с помощью двух параметров: начальной мощности и коэффициента загрузки. Обычно коэффициент загрузки по умолчанию 0,75 обеспечивает лучший баланс между временем и пространством. Увеличение коэффициента загрузки может сэкономить место, но соответствующее время поиска увеличится, что повлияет на такие операции, как получение и размещение.
Простой пример использования Hashtable: поместите 1, 2 и 3 в Hashtable, и их ключи будут «один», «два» и «три» соответственно:
Скопируйте код кода следующим образом:
Номера хэш-таблицы = новая Hashtable();
Numbers.put("один", новое целое число(1));
Numbers.put("два", новое целое число(2));
Numbers.put("три", новое целое число(3));
Чтобы получить число, например 2, используйте соответствующую клавишу:
Целое число n = (Целое)numbers.get("два");
System.out.println("два =" + n);
Поскольку объект, используемый в качестве ключа, будет определять положение соответствующего значения путем вычисления своей хеш-функции, любой объект, используемый в качестве ключа, должен реализовывать методы hashCode и Equals. Методы hashCode и Equals наследуются от корневого класса Object. Если вы используете собственный класс в качестве ключа, будьте очень осторожны, согласно определению хеш-функции, если два объекта одинаковы, то есть obj1.equals(. obj2)=true, тогда их хэш-код должен быть То же самое, но если два объекта разные, их хэш-код не обязательно будет разным. Если хеш-код двух разных объектов один и тот же, это явление называется конфликтом. Конфликт увеличит временные затраты на работу с хэш-таблицей, поэтому попробуйте. чтобы правильно его определить. Метод hashCode() может ускорить операции с хеш-таблицами.
Если у одного и того же объекта другой hashCode, операция с хеш-таблицей приведет к неожиданным результатам (ожидаемый метод get возвращает значение null). Чтобы избежать этой проблемы, вам нужно помнить только одно: переопределить метод Equals и метод hashCode одновременно. время. Не пишите только один из них.
Хэш-таблица синхронна.
Класс ХэшМап HashMap похож на Hashtable, за исключением того, что HashMap является асинхронным и допускает значение null, то есть нулевое значение и нулевой ключ. , но при обработке HashMap как коллекции (методvalues() может возвращать коллекцию), затраты времени на его подоперации итерации пропорциональны емкости HashMap. Поэтому, если производительность итеративных операций очень важна, не устанавливайте слишком высокую начальную емкость HashMap или слишком низкий коэффициент загрузки.
Класс WeakHashMap WeakHashMap — это улучшенный HashMap, который реализует «слабые ссылки» на ключи. Если на ключ больше нет внешних ссылок, ключ может быть переработан GC.
Резюме <BR>Если задействованы такие операции, как стеки и очереди, вам следует рассмотреть возможность использования List. Если вам нужно быстро вставлять и удалять элементы, вам следует использовать LinkedList. Если вам нужен быстрый произвольный доступ к элементам, вам следует использовать ArrayList.
Если программа находится в однопоточной среде или доступ осуществляется только в одном потоке, рассмотрите возможность использования асинхронных классов, которые более эффективны. Если несколько потоков могут одновременно работать с классом, следует использовать синхронизированные классы.
Обратите особое внимание на работу хеш-таблицы. Объект, используемый в качестве ключа, должен корректно переопределять методы Equals и hashCode.
Попробуйте вернуть интерфейс, а не фактический тип, например вернуть List вместо ArrayList, чтобы, если в будущем вам понадобится заменить ArrayList на LinkedList, клиентский код не нужно было менять. Это программирование для абстракции.