> Что такое битовые сдвиги и где они применяются (Android)

Уровень: junior · Роль: mobile · Категория: Технические вопросы

Компании: Иннотех

Стек: Android

> Пример ответа

Короткий ответ

Битовые сдвиги - это операции, которые перемещают биты числа влево или вправо. В Java есть три оператора: << (сдвиг влево), >> (сдвиг вправо с сохранением знака) и >>> (логический сдвиг вправо без знака). Сдвиг влево эквивалентен умножению на степень двойки, сдвиг вправо - целочисленному делению. Применяются для быстрых вычислений, работы с флагами, битовыми масками, в криптографии, сжатии и низкоуровневых операциях.

Подробное объяснение

Битовый сдвиг - это операция над целочисленными типами (int, long, byte, short, char), которая перемещает каждый бит числа на заданное количество позиций. Освободившиеся позиции заполняются нулями (для << и >>>) или значением знакового бита (для >>).

Основные операторы в Java:

  • a << n - сдвиг влево на n позиций. Каждый бит перемещается в старший разряд, младшие биты заполняются нулями. Эквивалентно a * 2^n (при отсутствии переполнения).
  • a >> n - арифметический сдвиг вправо. Старшие биты заполняются значением знакового бита (0 для положительных, 1 для отрицательных). Эквивалентно a / 2^n с округлением вниз.
  • a >>> n - логический сдвиг вправо. Старшие биты всегда заполняются нулями, независимо от знака.

Важные особенности:

  • Для int сдвиг выполняется по модулю 32 (n & 0x1F), для long - по модулю 64.
  • Сдвиг на отрицательное число или число больше разрядности не приводит к ошибке - берётся младшие 5 (или 6) бит.
  • Приоритет операторов сдвига ниже, чем у арифметических, но выше, чем у сравнения.

На практике

В Android-разработке битовые сдвиги встречаются в нескольких типичных местах:

  1. Работа с флагами и битовыми масками - например, в View для хранения системных флагов (VISIBLE, GONE), в PackageManager для флагов установки, в Intent для флагов запуска.
  2. Оптимизация вычислений - умножение и деление на степень двойки через сдвиг быстрее, чем через арифметические операции (хотя современные компиляторы делают это автоматически).
  3. Работа с цветом - в Android цвет хранится как int (ARGB), и для извлечения компонентов используются сдвиги: (color >> 16) & 0xFF для красного канала.
  4. Сериализация и парсинг бинарных данных - например, при работе с ByteBuffer, протоколами или файловыми форматами.
  5. Хеширование - в HashMap используется (h = key.hashCode()) ^ (h >>> 16) для улучшения распределения.
  6. Анимации и графические трансформации - в Matrix, Rect и других геометрических классах иногда используются сдвиги для быстрых вычислений.

Пример кода

JAVA
// Извлечение компонентов цвета ARGB
int color = 0xAABBCCDD;
int alpha = (color >>> 24) & 0xFF;
int red = (color >>> 16) & 0xFF;
int green = (color >>> 8) & 0xFF;
int blue = color & 0xFF;
// Упаковка обратно
int packed = (alpha << 24) | (red << 16) | (green << 8) | blue;
// Умножение и деление на степень двойки
int value = 10;
int multiplied = value << 3; // 10 * 8 = 80
int divided = value >> 2; // 10 / 4 = 2 (целочисленное)
// Проверка установленного бита
int flags = 0b1010;
boolean isSecondBitSet = (flags & (1 << 1)) != 0; // true
// Логический сдвиг для беззнаковых значений
int negative = -1;
int unsigned = negative >>> 1; // 2147483647

Как отвечать на собеседовании

Начни с определения и трёх операторов. Скажи, что сдвиг влево - это умножение на степень двойки, арифметический сдвиг вправо - деление с округлением вниз. Упомяни разницу между >> и >>> - это ключевой момент для junior. Приведи один-два примера из Android: извлечение цвета или работа с флагами. Если спросят про производительность - скажи, что сдвиг быстрее умножения, но в Java компилятор сам оптимизирует умножение на степень двойки, поэтому явный сдвиг нужен скорее для читаемости или при работе с битовыми масками.

Что проверяет интервьюер

Интервьюер проверяет:

  • Понимание двоичного представления чисел и побитовых операций в целом.
  • Знание разницы между арифметическим и логическим сдвигом вправо.
  • Умение применять сдвиги на практике - например, извлечение байтов из int.
  • Понимание особенностей Java: сдвиг по модулю разрядности, поведение для отрицательных чисел.
  • Способность объяснить, зачем это нужно в реальной разработке, а не только в теории.

Типичные ошибки

  • Путать >> и >>> - не помнить, что >> сохраняет знак, а >>> всегда заполняет нулями.
  • Забывать про приоритет операторов: a & b << c интерпретируется как a & (b << c), а не (a & b) << c.
  • Использовать сдвиг для byte или short без приведения - результат всегда int, и это может привести к неожиданному поведению.
  • Сдвигать на количество бит, превышающее разрядность типа, не учитывая модуль 32/64.
  • Думать, что сдвиг вправо для отрицательных чисел - это деление с округлением к нулю. На самом деле это округление вниз (к отрицательной бесконечности).
  • Использовать сдвиг для оптимизации там, где это не нужно - современный JIT и так заменяет умножение на степень двойки сдвигом.

> ГОТОВЫ К СЛЕДУЮЩЕМУ СОБЕСЕДОВАНИЮ?

Запустите тренировочную сессию с ИИ и получите детальную обратную связь, чтобы увереннее проходить реальные интервью