Операторы двойного структурного равенства: if (a == b == c)

Я написал код по ошибке сегодня и был удивлен, когда Eclipse не кричал на меня, на этот раз. Код имел двойное использование оператора структурного равенства (==), аналогичного приведенному ниже с структурой if(a==b==c).

public class tripleEqual {
    public static void main(String[] args) {
        boolean[] a = { true, false };
        boolean[] b = { true, false };
        boolean[] c = { true, false };

        for (int aDex = 0; aDex < 2; aDex++) {
            for (int bDex = 0; bDex < 2; bDex++) {
                for (int cDex = 0; cDex < 2; cDex++) {
                    if (a[aDex] == b[bDex] == c[cDex]) {
                        System.out.printf("Got a==b==c with %d %d %d\n", aDex, bDex, cDex);
                    }
                }
            }
        }

    }
}

Вывод

Got a==b==c with 0 0 0
Got a==b==c with 0 1 1
Got a==b==c with 1 0 1
Got a==b==c with 1 1 0

Играя, я замечаю, что я не могу сделать if(a==b==c) с любым типом, но boolean. Отсюда следует, что булево выражение

( A'. B'. C') + ( A'. B . C ) + ( A . B'. C ) + ( A . B . C') 

что упрощается до (A=B).'C + (A<>B).C.

Таким образом, игнорирование побочного эффекта if(a==b==c) равно if(a==b && !c) || (a!=b && c)).

Может ли кто-нибудь объяснить, как синтаксис if(a==b==c) предполагает, что?

Изменить 1:

Я нашел, где мое замешательство было после того, как многие люди объяснили левую ассоциативность. Обычно я пишу '1' для true и '0' для false, но моя свернутая таблица истинности/вывода в вышеприведенном тесте, у меня было "0" для true и "1" для false. Отрицание выражения ( A'. B'. C') + ( A'. B . C ) + ( A . B'. C ) + ( A . B . C') равно (A=B)=C!

Ответы

Ответ 1

Играя, я замечаю, что не могу делать, если (a == b == c) с любым типом, но булевым.

Вы не можете сделать это с любым типом, но boolean, потому что эта цепочка сравнения будет оцениваться с левой стороны вправо. Первое сравнение будет упрощено до значения true или false, которое нужно сравнить с третьим значением в цепочке (и результат этой проверки будет сравниваться с четвертым значением и т.д. До конца цепочки). Что касается примитивных значений, вы можете сравнивать только примитивы одного типа (например, boolean и boolean будут работать, а double и boolean - нет) - поэтому вы можете делать это только с помощью booleans, потому что == возвращает значение того же типа, что и все значения в цепочке.
Здесь существует опасность: результат всей этой цепи сравнения не равен true, когда все значения, которые вы предоставили, true. Вы можете увидеть его со второго выхода: true == false == false raises true, что является правильным результатом, если вы оцениваете его слева направо (как это происходит во время выполнения программы), но может показаться неправильным, если вы считаете, что эту цепочку сравнения нужно оценивать сразу. Правильный способ сделать это - два выполнения двух явных сравнений:

if (a == b && b == c) {
    // do something
}

Ответ 2

Оператор == лево-ассоциативный, поэтому a == b == c интерпретируется как (a == b) == c. Итак, a == b возвращает bool, который затем сравнивается с c.

Это побочный эффект парсера, который редко бывает полезен на практике. Как вы заметили, похоже, что он делает одно, а делает что-то совсем другое (так что даже если он делает то, что вы хотите, он не рекомендуется). Некоторые языки фактически делают оператор == неассоциативным, поэтому a == b == c является синтаксической ошибкой.