Недавно я изучал Java, и у меня есть вопрос.
Я узнал, что HashMap
и Hashtable
не сохраняют порядок вставки или порядок, основанный на ключе. Но я столкнулся с ситуацией, когда этого не происходит.
import java.util.HashMap;
import java.util.Hashtable;
public class Main {
public static void main(String[] args) {
Hashtable<Integer, Integer> hashtableInt = new Hashtable<>();
Hashtable<String, Integer> hashtableStr = new Hashtable<>();
HashMap<Integer, Integer> hashMapInt = new HashMap<>();
HashMap<String, Integer> hashMapStr = new HashMap<>();
for (int i = 0; i < 25; i++) {
hashtableInt.put(i, i);
hashtableStr.put(String.valueOf(i), i);
hashMapInt.put(i, i);
hashMapStr.put(String.valueOf(i), i);
}
System.out.println("Hashtable with Integer keys : ");
for (int key : hashtableInt.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashtable with String keys : ");
for (String key : hashtableStr.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashMap with Integer keys : ");
for (int key : hashMapInt.keySet()) System.out.print(key + " ");
System.out.println("\n\nHashMap with String keys : ");
for (String key : hashMapStr.keySet()) System.out.print(key + " ");
}
}
Hashtable with Integer keys :
24 23 22 21 20 19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 3 2 1 0
Hashtable with String keys :
19 18 17 16 15 14 13 12 11 10 9 8 7 6 5 4 24 3 23 2 22 1 21 0 20
HashMap with Integer keys :
0 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
HashMap with String keys :
22 23 24 10 11 12 13 14 15 16 17 18 19 0 1 2 3 4 5 6 7 8 9 20 21 %
В приведенном выше выводе хеши, использующие ключи Integer
, имеют определенный порядок. Только хеши, принимающие String
в качестве ключа, не имеют порядка. Кроме того, порядок клавиш между Hashtable
и HashMap
с клавишами Integer
различен.
Итак, что я хочу знать, так это...
Почему Hashtable().keySet()
и HashMap().keySet()
имеют порядок? Обычно хеши и наборы не имеют определенного порядка. Почему это? Я что-то пропустил?
Почему Hashtable().keySet()
и HashMap().keySet()
имеют противоположный порядок? В конце концов, эти два будут хешем, но что-то внутри работает по-другому?
Если ожидается, что keySet()
будет иметь порядок, то почему Hashtable().keySet()
и HashMap().keySet()
имеют неправильный порядок?
Спасибо вам всем.
Я отладил метод put()
и посмотрел, как он работает, но для меня это слишком сложно.
Также учтите, что для такого рода неупорядоченных коллекций (в данном случае Set
) определенный порядок не гарантируется (из документации Set: «Порядок итерации элементов набора не указан и может быть изменен.»). Это не означает, что гарантировано, что порядок не будет поддерживаться. Просто на порядок нельзя полагаться.
попробуйте заполнить карту более крупными числами, например 500 - 525
...
На порядок полагаться нельзя. Хотя на самом деле это происходит не случайно, можно определенно считать это случайностью. Java просто предоставляет вам элементы в том порядке, в котором они хранятся.
Если вам нужен Map
с указанным порядком встречи. См. также SequencedMap для этого.
Это связано с тем, как структуры хэш-данных хранят данные. Они основаны на распределении данных по нескольким сегментам (обычно сегментов больше, чем точек данных).
Чтобы решить, какая точка данных попадает в какую корзину, он вызывает метод hashCode
объекта, а затем использует операции с модулем для распределения ее по корзинам. В случае Integer
это возвращает вам исходный номер.
Таким образом, если у вас есть 10 сегментов и вы храните в них числа 1,2,3,4,5,5,6, число 1 перейдет в сегмент 1, а число 2 — в сегмент 2 и т. д. Однако, если вы, например, если номера разбросаны больше (или начинаются с другого номера), это больше не будет работать.
Например, если мы сохраним числа 10
, 20
и 30
в HashMap
, порядок больше не будет работать:
HashMap<Integer, Integer> hashMapInt = new HashMap<>();
hashMapInt.put(10, 10);
hashMapInt.put(20, 20);
hashMapInt.put(30, 30);
for (int key : hashMapInt.keySet()) System.out.print(key + " ");
В моей системе этот код приводит к выводу 20 10 30
.
При хранении элементов в виде String
с каждым элементом связано больше данных, а метод hashCode объединяет разные символы/байты, поэтому два String
, представляющие последовательные числа, имеют более разбросанные хеши.
Порядок элементов в HashMap
или Hashtable
не указан и может даже различаться в разных JVM.
Две вещи. Во-первых, вам не следует использовать HashTable — это устаревшая коллекция, которая не используется современными программами Java.
Во-вторых, никогда не пишите программное обеспечение, которое ожидает определенного порядка ключей в HashMap. Если вам нужен порядок, отсортируйте ключи. Но полагаться на порядок из любого хеш-контейнера — это верный путь к появлению ошибок в программном обеспечении, поскольку этот порядок должен быть изменен, не затрагивая ваш код.
Просто верьте, что HashMap знает, что делает.
«Идеальный порядок» в хеш-таблице — это всего лишь случайность и зависит как от того, как хеш-таблица хранит ключи в своей внутренней структуре данных, так и от способа расчета хэш-кода для каждого типа ключа. Для получения дополнительной информации я предлагаю вам изучить методы hashCode() для строк и целых чисел, а также способ реализации хэш-таблиц в целом.