Encodera

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.

Как использовать битовые флаги

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

Каждому флагу дайте свой бит (1, 2, 4, 8...), объединяйте флаги через |, а проверяйте через &:

static final int READ = 1;
static final int WRITE = 1 << 1;
static final int DELETE = 1 << 2;
 
void main() {
    int perms = READ | WRITE;
 
    IO.println((perms & WRITE) != 0);
    IO.println((perms & DELETE) != 0);
}

Результат:

true
false

Установить, сбросить, переключить

|= включает бит, &= ~ выключает, ^= переключает:

static final int READ = 1;
static final int WRITE = 1 << 1;
static final int DELETE = 1 << 2;
 
void main() {
    int perms = READ;
    perms |= DELETE;
    IO.println(Integer.toBinaryString(perms));
 
    perms &= ~READ;
    IO.println(Integer.toBinaryString(perms));
 
    perms ^= WRITE;
    IO.println(Integer.toBinaryString(perms));
}

Результат:

101
100
110

Все флаги сразу

Проверить, что включены все нужные флаги, и посчитать включённые:

static final int READ = 1;
static final int WRITE = 1 << 1;
static final int DELETE = 1 << 2;
 
void main() {
    int perms = READ | WRITE;
    int required = READ | WRITE;
 
    IO.println((perms & required) == required);
    IO.println(Integer.bitCount(perms));
}

Результат:

true
2

Вместо флагов — EnumSet

В новом коде флаги удобнее хранить в EnumSet: он внутри устроен так же, но код читается проще и вывод понятнее:

enum Permission { READ, WRITE, DELETE }
 
void main() {
    EnumSet<Permission> perms = EnumSet.of(Permission.READ, Permission.WRITE);
    perms.remove(Permission.READ);
    perms.add(Permission.DELETE);
 
    IO.println(perms);
    IO.println(perms.contains(Permission.WRITE));
}

Результат:

[WRITE, DELETE]
true

Частая ошибка

Забыть скобки. У & приоритет ниже, чем у !=, поэтому выражение без скобок не компилируется:

static final int WRITE = 2;
 
void main() {
    int perms = 3;
    if (perms & WRITE != 0) {
        IO.println("can write");
    }
}

Результат:

Main.java:5: error: bad operand types for binary operator '&'

Правильно: (perms & WRITE) != 0. Ещё одна ошибка — задать флаги подряд идущими числами 1, 2, 3: у 3 два бита, и он совпадает с 1 | 2.

Функции из этого ответа

  • & | ^ ~ << >> >>> — Побитовые операторы: работают с отдельными битами целых чисел — И, ИЛИ, исключающее ИЛИ, НЕ и сдвиги.
  • EnumSet — Множество значений одного enum. Работает как набор битовых флагов, но с понятным кодом.
  • Integer.toBinaryString() — Записывает число в двоичной системе. Рядом — toHexString() и toOctalString().
  • += -= *= /= — Выполняет операцию и сразу записывает результат в ту же переменную.

Спасибо, что читаете!

Пожертвуйте сайту, мы стараемся ради вас.