Why swapping integer variable by XOR doesn't work in a single line?

后端 未结 5 2072
逝去的感伤
逝去的感伤 2020-12-16 17:59

I want to swap the value of two integer variables in java using the XOR operator.

This is my code:

int i = 24;
int j = 17;

i ^= j;
j ^= i;
i ^= j;

         


        
相关标签:
5条回答
  • 2020-12-16 18:25

    The left-most i is being evaluated before it's changed.

    You can instead do:

    j ^= (i ^= j);
    i ^= j;
    

    Which is slightly less compact but works.

    0 讨论(0)
  • 2020-12-16 18:27

    Here is a little shorter solution compared to @nhahtdh . I know it's an old question but just wanted to document it on Stackoverflow :P

    i = i ^ j ^ (j = i)

    0 讨论(0)
  • 2020-12-16 18:30

    How about doing: i ^= j ^ (j = j ^ i ^ j);

    0 讨论(0)
  • 2020-12-16 18:33

    By writing your swap all in one statement, you are relying on side effects of the inner i ^= j expression relative to the outer i ^= (...) expression.

    From the Java specificiation (15.26 Assignment Operators):

    There are 12 assignment operators; all are syntactically right-associative (they group right-to-left). Thus, a=b=c means a=(b=c), which assigns the value of c to b and then assigns the value of b to a.

    [...]

    AssignmentOperator: one of = *= /= %= += -= <<= >>= >>>= &= ^= |=

    You might want to consider the readability of the code. Perhaps it's best to e.g. put the code in a method called swap(), or do the actual swapping through the use of a temp variable:

    int temp = i;
    i = j;
    j = temp;
    
    0 讨论(0)
  • 2020-12-16 18:38

    According to Java specification (Java 7 specification), Section 15.26.2 (page 529).

    A compound assignment expression of the form E1 op= E2 is equivalent to E1 = (T) ((E1) op (E2)), where T is the type of E1, except that E1 is evaluated only once.

    According to Section 15.7 Evaluation Order (Page 423) (emphasis mine):

    15.7 Evaluation Order

    The Java programming language guarantees that the operands of operators appear to be evaluated in a specific evaluation order, namely, from left to right.

    15.7.1 Evaluate Left-Hand Operand First

    The left-hand operand of a binary operator appears to be fully evaluated before any part of the right-hand operand is evaluated.

    If the operator is a compound-assignment operator (§15.26.2), then evaluation of the left-hand operand includes both remembering the variable that the left-hand operand denotes and fetching and saving that variable's value for use in the implied binary operation.

    If evaluation of the left-hand operand of a binary operator completes abruptly, no part of the right-hand operand appears to have been evaluated.

    Described in more details in Section 15.26.2 (page 529):

    If the left-hand operand expression is not an array access expression, then:

    • First, the left-hand operand is evaluated to produce a variable. [trimmed]

    • Otherwise, the value of the left-hand operand is saved and then the right-hand operand is evaluated. [trimmed]

    • Otherwise, the saved value of the left-hand variable and the value of the right-hand operand are used to perform the binary operation indicated by the compound assignment operator. [trimmed]

    • Otherwise, the result of the binary operation is converted to the type of the left- hand variable, subjected to value set conversion (§5.1.13) to the appropriate standard value set (not an extended-exponent value set), and the result of the conversion is stored into the variable.

    An example in the documentation

    Example 15.26.2-2. Value Of Left-Hand Side Of Compound Assignment Is Saved Before Evaluation Of Right-Hand Side

      class Test {
          public static void main(String[] args) {
              int k = 1;
              int[] a = { 1 };
              k += (k = 4) * (k + 2);
              a[0] += (a[0] = 4) * (a[0] + 2);
              System.out.println("k==" + k + " and a[0]==" + a[0]);
          }
      }
    

    So the expression in the question is re-written and grouped as:

    i = i ^ (j = j ^ (i = i ^ j));
    

    Left-hand operands are evaluated:

    i = 24 ^ (j = 17 ^ (i = 24 ^ 17));
        **
    

    Since the value of i is not "updated" as expected, it will cause the value of i to get 0 when 24 is swapped to j.

    0 讨论(0)
提交回复
热议问题