簡體   English   中英

為什么通過XOR交換整數變量不能在一行中工作?

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

我想使用XOR運算符在java中交換兩個整數變量的值。

這是我的代碼:

int i = 24;
int j = 17;

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

System.out.println("i : " + i + "\t j : " + j);

它會正常工作,但以下等效代碼不起作用:

int i = 24;
int j = 17;

i ^= j ^= i ^= j;

System.out.println("i : " + i + "\t j : " + j);

輸出是這樣的:

i : 0    j : 24

第一個變量為零! Java有什么問題?

根據Java規范 (Java 7規范), 第15.26.2節 (第529頁)。

形式E1 op= E2的復合賦值表達式等效於E1 = (T) ((E1) op (E2)) ,其中TE1的類型,除了E1僅被評估一次。

根據第15.7節評估訂單 (頁423)( 強調我的):

15.7評估訂單

Java編程語言保證運算符的操作數似乎以特定的評估順序進行評估,即從左到右。

15.7.1首先評估左手操作數

在評估右側操作數的任何部分之前,似乎完全評估了二元運算符的左側操作數。

如果運算符是復合賦值運算符(第15.26.2節),則對左側操作數的計算包括記住左側操作數表示的變量並獲取並保存該變量的值以用於隱含的二進制操作。

如果對二元運算符的左側操作數的求值突然完成,則右側操作數的任何部分似乎都沒有被評估。

第15.26.2節 (第529頁)中詳細介紹:

如果左側操作數表達式不是數組訪問表達式,則:

•首先,評估左側操作數以生成變量。 [修剪]

•否則,保存左側操作數的值,然后計算右側操作數。 [修剪]

•否則,左側變量的保存值和右側操作數的值用於執行復合賦值運算符指示的二進制運算。 [修剪]

•否則,二進制運算的結果將轉換為左側變量的類型,經過值集轉換(第5.113節)到相應的標准值集(不是擴展指數值集),並且轉換結果存儲在變量中。

文檔中的一個示例

例15.26.2-2。 在評估右手側之前保存復合指派左側的值

  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]); } } 

所以問題中的表達式被重寫並分組為:

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

評估左手操作數:

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

由於i的值未按預期“更新”,因此當將24交換為j時,將導致i的值為0。

通過在一個語句中編寫交換全部,您依賴於內部i ^= j表達式相對於外部i ^= (...)表達式的副作用。

從Java規范(15.26 Assignment Operators):

有12個賦值運算符; 所有這些都是語法上的右關聯(他們從右到左分組)。 因此,a = b = c表示a =(b = c),它將c的值賦給b,然后將b的值賦給a。

[...]

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

您可能想要考慮代碼的可讀性。 也許最好將代碼放在一個名為swap()的方法中,或者通過使用temp變量進行實際交換:

int temp = i;
i = j;
j = temp;

最左邊的i在被改變之前被評估。

你可以這樣做:

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

哪個稍微不那么緊湊但有效。

怎么樣:i ^ = j ^(j = j ^ i ^ j);

與@nhahtdh相比,這是一個更短的解決方案。 我知道這是一個老問題,但只是想在Stackoverflow上記錄它:P

i = i ^ j ^ (j = i)

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM