X

Логическое и побитовое "И"

Очень часто, молодых специалистов легко завести в тупик, спросив чем отличаются два условия:
if (a&&b){}
и if (a&b){}. Сегодня я расскажу в чем отличие.

Для начала нам необходимо знать, что:

&& = это логическое "И"
& = это битовое "И"

Давайте посмотрим что нам говорит Wikipedia:

В компьютерных языках используется два основных варианта конъюнкции: логическое "И" и побитовое (поразрядное) "И". Например, в языках C/C++ логическое "И" обозначается символом "&&", а побитовое — символом "&". В терминологии, используемой в C#, операцию "&" принято называть логическим "И", а операцию "&&" - условным "И", поскольку значения операндов являются условиями для продолжения вычисления. В языках Pascal/Delphi оба вида конъюнкции обозначается с использованием ключевого слова "and", а результат действия определяется типом операндов. Если операнды имеют логический тип (например, Boolean) — выполняется логическая операция, если целочисленный (например, Byte) — поразрядная.

Если Вы все поняли, можете дальше не читать. Для тех же, кто в цитате увидел, просто набор букв, я объясню проще:

  • При использовании && происходит логическое сравнение, двух результатов,
    например: false && true = false
  • При использовании & происходит побитовое сравнение, двух результатов,
    например: 001 & 101 = 001

Это в свою очередь нам дает такой результат:

  • При использовании &&, в случае, если результат равен false, дальнейшая проверка не выполняется.
    Пример: (false && a() && b()). Методы a() и b() не будут вызваны, т.к. на первом месте стоит false и это означает что все выражение будет false.
  • При использовании &, в любом случае будут выполнены все проверки, т.к. побитовый сдвиг "надо делать с цифрами", а на этапе выполнения выражения, мы не можем предсказать результат.
    Пример: (false & a() & b()) . Методы a() и b() будут вызваны.

 

Давайте теперь проверим:

public class Main {

 private static int counter=0;

 public static void main(String[] args) {

  if (test() && test());

  System.out.println("------------");
  counter=0;

  if (test() & test());

 }

 public static boolean test()
 {
  counter++;
  System.out.println("Test run. Iteration: "+counter);
  return false;
 }

}

Результат выполнения:

Test run. Iteration: 1
------------
Test run. Iteration: 1
Test run. Iteration: 2

 

Итак, в первом случае я использую логическое "и" (&&) и мы видим что метод test() выполняется только один раз (тот что слева от &&), т.к. он возвращает false, то компилятор оптимизирует вычисления и второй вызов test() не делает.
Во втором случае, мы используем побитовое "и" (&), соответственно для вычисления результата компилятору необходимо знать оба результата, поэтому метод тест вызывается дважды (тот что слева от & и тот что справа).

Вопросы для собеседования:

  • Чему будет равно выражение: ( false ) && ( false & true && true & false & false && true )
    Ответ: результат будет false, т.к. слева у нас false, и дальше оператор логического "и" (&&), а это значит что выражение во вторых скобках компилятор не будет считать.
  • Чему будет равно выражение: if ( 1 & 1 && 1 ){}
    Ответ: Ничему. Произойдет ошибка компиляции. Тут допущено три ошибки:
    а) if должен на вход получать boolean значение, а у нас int;
    б) операция && (логическое "и") может быть выполнена только с boolean значениями;
    в) операция & (побитовое "и") может быть выполнена только с цифрами.
Категории: Java Java labs

Комментарии (2)

  • if ( 1 & 1 && 1 ){}
    Ответ: Ничему. Произойдет ошибка компиляции.

    На заметку:
    В СИ оператор if спокойно кушает int
    А в целом статья справедлива и для СИ.

    • Как бы да. Если это вопрос для собеседования, то я бы из такой конторы сам убежал.