Что означает оператор ‹‹= в Java?

Не могли бы вы объяснить этот фрагмент кода из конструктор HashMap, в частности, строка

емкость ‹‹= 1:

// Find a power of 2 >= initialCapacity
198         int capacity = 1;
199         while (capacity < initialCapacity)
200             capacity <<= 1;

person Geek    schedule 22.08.2012    source источник


Ответы (4)


Это эквивалентно capacity = capacity << 1;.
Эта операция сдвигает биты емкости на одну позицию влево, что эквивалентно умножению на 2.

Конкретный код, который вы разместили, находит наименьшую степень числа 2, которая больше, чем initialCapacity.

Так что если initialCapacity равно 27, например, capacity будет 32 (2^5) после цикла.

person assylias    schedule 22.08.2012
comment
Хотя и не совсем эквивалентно. Могут применяться различные правила приоритета. - person Romain; 22.08.2012
comment
@assylias, но почему степень 2? если мы возьмем метод деления для хэширования и возьмем мод степени 2 (скажем, 2 ^ w), мы даже не будем учитывать правое большинство w битов, я думаю... - person Geek; 22.08.2012
comment
@Geek Вы были бы правы, за исключением того, что HashMap также использует метод перехеширования под названием hash(int), который вычисляет h ^= (h >>> 20) ^ (h >>> 12); return h ^ (h >>> 7) ^ (h >>> 4);;) - person Peter Lawrey; 22.08.2012
comment
@StephenC HashMap всегда использует степень 2 для своей емкости. - person Peter Lawrey; 22.08.2012
comment
@StephenC, что вы подразумеваете под мощностью 2 бита, это ПРИМЕР. . Судя по коду, HashMap ВСЕГДА будет иметь мощность 2, поскольку его емкость не зависит от коэффициента загрузки. - person Geek; 22.08.2012
comment
@PeterLawrey, что происходит в этом причудливом методе? Я слаб в битовых манипуляциях.... - person Geek; 22.08.2012
comment
@Geek метод находит наименьшую степень числа 2, которая больше, чем initialCapacity. Таким образом, если initialCapacity = 27, например, емкость будет равна 32 (2 ^ 5) после этого цикла. - person assylias; 22.08.2012
comment
@assylias Теперь я вижу, что он делает, но опять же, почему они используют этот подход степени двойки, который кажется мне противоречащим интуиции ... Как это двойное хеширование решает проблему учета всех битов. - person Geek; 22.08.2012
comment
@Geek Проще говоря, метод хеширования вытягивает биты из 20-го и 12-го, а затем из 7-го и 4-го для комбинированного эффекта извлечения битов из 4, 7, 12, 16, 19, 20, 24 и 27-го бит. то есть смешивает их все. В случае размера по умолчанию, 16, старший бит игнорируется, но для размера 32+ используются все биты. - person Peter Lawrey; 22.08.2012
comment
@Geek Логика заключается в том, что перефразирование и битовая маска выполняются быстрее, чем использование % и обработка знака (который включает ветку) - person Peter Lawrey; 22.08.2012
comment
@PeterLawrey спасибо за это объяснение. Теперь я вижу интуицию для перехода на подход 2^w. - person Geek; 22.08.2012
comment
@Geek Я подозреваю, что основным преимуществом является предотвращение промахов предсказания ветвления. ;) - person Peter Lawrey; 22.08.2012
comment
@Peter, ветка легко удаляется hash&Integer.MAX_VALUE. mod - это просто дорогостоящая операция (например, в 30 раз дороже, чем побитовое И, и использует дополнительный регистр ЦП - также облагает налогом). Последний - побитовый, а Integer.MAX_VALUE всегда должен применяться для хеш-индекса в массиве, причем верхний бит зарезервирован для «состояния». Я не знаю ни одной хеш-таблицы в Java, которая использует 32 бита предоставленного hashCode() - person bestsss; 25.08.2012
comment
@Geek, основная причина в том, что мод довольно дорогой по сравнению с побитовым и. - person bestsss; 25.08.2012
comment
@Peter, использование мода оправдано для таблицы размером с простое число, поскольку оно уменьшает коллизии. Уменьшение столкновений улучшается за счет того самого битового скремблирования, которое вы объясняете. Коллизии в java.util.HashMap довольно дороги, поскольку они приводят к промаху кеша... открытая адресная таблица обычно лучше с таблицей размера pow2, а коллизии дешевле. В целом, как я уже неоднократно заявлял, java.util.HashMap сильно ударяет - person bestsss; 25.08.2012

Точно так же, как var += 1 примерно эквивалентен var = var + 1, то, что вы видите здесь (var <<= 1), примерно эквивалентно var = var << 1, что означает «установить var как результат 1-позиционного двоичного сдвига влево var».

В этом очень конкретном случае это на самом деле немного (во время выполнения) более быстрый способ выражения capacity *= 2 (поскольку побитовый сдвиг влево на 1 позицию эквивалентен умножению на 2).

person Romain    schedule 22.08.2012

Это эквивалентно

capacity = capacity << 1;

который сдвигает биты в capacity на одну позицию влево (т.е. 00011011 становится 00110110).

person Kuba Wyrostek    schedule 22.08.2012

каждый раз, когда это выходит из цикла, значение «емкости» увеличивается на 2 на более высокую степень.

как изначально это 1 т.е. 2^0; операция (емкость ‹‹= 1) в первый раз делает ее 2^1, затем 2^2 и так далее. Может быть, вы хотели бы увидеть больше на http://www.tutorialspoint.com/java/java_basic_operators.htm

person Nitish Pareek    schedule 22.08.2012