Подтвердить что ты не робот

Почему создание HashMap происходит быстрее, чем создание объекта []?

Я попытался создать свою собственную карту, чтобы повысить производительность для специальной среды, и я понял кое-что довольно интересное: создание new Hashmap<Integer,String>(2000) выполняется быстрее, чем new Object[2000] - независимо от того, в каком порядке я выполняю эти команды. Это довольно запутанно для меня, особенно. потому что конструктор Hashmap содержит table = new Entry[capacity], согласно this. Что-то не так с моим testbench?

public static void test(int amm){ //amm=1_000_000
    Map<Integer,String> m1 = null;
    Object[] arr = null;

    long time = System.nanoTime();
    for(int i = 0; i < amm; i++){
        m1 = new HashMap<Integer, String>(2000);
    }
    System.out.println("m1: " + (System.nanoTime() - time)); //m1: 70_455_065

    time = System.nanoTime();
    for(int i = 0; i < amm; i++){
        arr = new Object[2000];
    }
    System.out.println("arr: " + (System.nanoTime() - time)); //arr: 1_322_473_803
}

Мне бы хотелось увидеть результаты тестирования на другом компьютере. Я не знаю, почему создание HashMap в 10 раз быстрее, чем создание Object[].

4b9b3361

Ответ 1

Если вы посмотрите на реализацию HashMap, конструктор выглядит так:

public HashMap(int initialCapacity, float loadFactor) {
    if (initialCapacity < 0)
        throw new IllegalArgumentException("Illegal initial capacity: " +
                                           initialCapacity);
    if (initialCapacity > MAXIMUM_CAPACITY)
        initialCapacity = MAXIMUM_CAPACITY;
    if (loadFactor <= 0 || Float.isNaN(loadFactor))
        throw new IllegalArgumentException("Illegal load factor: " +
                                           loadFactor);

    this.loadFactor = loadFactor;
    threshold = initialCapacity;
    init();
}

И init() выглядит следующим образом:

/**
 * Initialization hook for subclasses. This method is called
 * in all constructors and pseudo-constructors (clone, readObject)
 * after HashMap has been initialized but before any entries have
 * been inserted.  (In the absence of this method, readObject would
 * require explicit knowledge of subclasses.)
 */
void init() {
}

Итак, initialCapacity фактически не используется для создания массива. Где он используется? Посмотрите на метод put().

public V put(K key, V value) {
    if (table == EMPTY_TABLE) {
        inflateTable(threshold);
    }
    // hidden
} 

При выполнении put массив фактически создается. Я не показывал inflateTable(), но он выполняет некоторую математику и инициализирует массив.

Ответ 2

Пустой объект HashMap намного меньше массива ссылок 2000 Object. Несмотря на то, что вы передаете 2000 в параметр initialCapacity конструктора HashMap, он фактически не создает 2000 пространств для объектов.