Упорядочение элементов в Java HashSet - PullRequest
4 голосов
/ 19 февраля 2012

Почему второй и третий наборы сохраняют порядок:

Integer[] j = new Integer[]{3,4,5,6,7,8,9};
LinkedHashSet<Integer> i = new LinkedHashSet<Integer>();
Collections.addAll(i,j);
System.out.println(i); 

HashSet<Integer> hi = new HashSet<Integer>(i);
System.out.println(hi); 

LinkedHashSet<Integer> o = new LinkedHashSet<Integer>(hi);
System.out.println(o); 

Вот вывод, который я получаю:

3,4,5,6,7,8,9
3,4,5,6,7,8,9
3,4,5,6,7,8,9

Ответы [ 2 ]

12 голосов
/ 19 февраля 2012

Второй (просто с использованием HashSet) является лишь совпадением.Из JavaDocs :

Этот класс реализует интерфейс Set, поддерживаемый хеш-таблицей (фактически, экземпляром HashMap).Это не дает никаких гарантий относительно порядка итераций множества; в частности, это не гарантирует, что заказ будет оставаться постоянным в течение времени .Этот класс допускает нулевой элемент.

Третий (LinkedHashSet) - это , предназначенный , подобный этому:

Хеш-таблица и связанныйреализация списка интерфейса Set с предсказуемым порядком итераций.Эта реализация отличается от HashSet тем, что поддерживает двусвязный список, проходящий через все его записи.Этот связанный список определяет порядок итераций, который является порядком, в котором элементы были вставлены в набор (порядок вставки).Обратите внимание, что порядок вставки не изменяется, если элемент повторно вставляется в набор.(Элемент e повторно вставляется в набор s, если s.add (e) вызывается, когда s.contains (e) возвращает true непосредственно перед вызовом.)

2 голосов
/ 26 января 2016

@ Ответ Бехранга хорош, но, чтобы быть более конкретным, единственная причина, по которой HashSet выглядит в том же порядке, что и LinkedHashSet, заключается в том, что integer.hashCode() само по себе является целочисленным значением, поэтому числа происходят быть в порядке во внутреннем хранилище HashSet. Это очень специфичная для реализации и, как говорит @Behrang, действительно совпадение.

Например, если вы используете new HashSet<>(4), который устанавливает начальное количество сегментов равным 4 (вместо 16), то вы могли бы получить следующий вывод:

HashSet<Integer> hi = new HashSet<Integer>(4);
...
[3, 4, 5, 6, 7, 8, 9]
[8, 9, 3, 4, 5, 6, 7]
[8, 9, 3, 4, 5, 6, 7]

Если вы застряли в значениях> = 16, вы можете получить что-то вроде этого:

Integer[] j = new Integer[] { 3, 4, 5, 6, 7, 8, 9, 16 };
...
[3, 4, 5, 6, 7, 8, 9, 16]
[16, 3, 4, 5, 6, 7, 8, 9]
[16, 3, 4, 5, 6, 7, 8, 9]
...