Что такое битовые сдвиги и где они применяются
Что проверяют
Держите ли вы в голове двоичное представление чисел и понимаете ли, зачем это мобильному разработчику. В Android сдвиги встречаются постоянно: флаги интентов, упаковка цвета, режимы измерения вьюх, маски в бинарных протоколах.
Как отвечать
Сдвиг влево дописывает нули справа, сдвиг вправо убирает младшие биты. В Kotlin это инфиксные shl, shr и ushr, где shr сохраняет знаковый разряд, а ushr дописывает слева нули.
Практика, ради которой вопрос и задают:
const val FLAG_SYNC = 1 shl 0
const val FLAG_CACHE = 1 shl 1
var flags = 0
flags = flags or FLAG_CACHE
val cached = flags and FLAG_CACHE != 0
val alpha = color ushr 24 and 0xFFТак набор независимых признаков умещается в одно целое, а распаковка цветовых компонент сводится к сдвигу и маске. Тот же приём даёт упаковку пары целых в длинное число и компактные ключи кэша.
Про производительность отвечайте аккуратно: на современных процессорах и с JIT замена умножения на константу сдвигом ничего не выигрывает, компилятор делает это сам. Сдвиги пишут там, где по смыслу работают с битами, и читаемость важнее мнимой экономии.
Где спотыкаются
Продают сдвиг как оптимизацию арифметики и заодно уравнивают сдвиг вправо с делением на два. Для отрицательных это разные операции: сдвиг округляет вниз, деление к нулю, и минус семь даёт минус четыре против минус трёх.
Забывают, что счётчик сдвига берётся по младшим разрядам: для целого значим остаток от деления на тридцать два, поэтому сдвиг на тридцать два возвращает исходное число, а не ноль.
Распаковывают байт из отрицательного числа знаковым сдвигом и без маски. Старшие разряды приезжают единицами, и вместо компоненты цвета получается отрицательное значение.