Как использовать битовые флаги
Короткий ответ
Каждому флагу дайте свой бит (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().
- += -= *= /= — Выполняет операцию и сразу записывает результат в ту же переменную.