[英]Are the &, |, ^ bitwise operators or logical operators?
首先,我了解到&
, |
, ^
是按位運算符,現在有人用&&
, ||
它們稱為邏輯運算符。 ,我完全感到困惑-同一操作員有兩個名字嗎? 已經有邏輯運算符&&
, ||
,為什么要使用&
, |
, ^
?
Java運算符&
, |
和^
分別是按位運算符或邏輯運算符...取決於操作數的類型。 如果操作數是整數,則運算符是按位的。 如果它們是布爾值,則運算符是邏輯的。
這不僅是我說的。 JLS也以這種方式描述了這些運算符。 參見JLS 15.22 。
(這就像+
一樣,表示加法運算或字符串串聯...取決於操作數的類型。或者就像“玫瑰”表示花朵或淋浴附件。或“貓”表示毛茸茸的動物或動物。 UNIX命令。單詞在不同的上下文中具有不同的含義。編程語言中使用的符號也是如此。)
已經有邏輯運算符
&&
,||
,為什么使用&
,|
,^
?
就前兩個而言,這是因為運算符在何時/是否對運算數求值方面具有不同的語義。 在不同情況下需要兩種不同的語義。 例如
boolean res = str != null && str.isEmpty();
與
boolean res = foo() & bar(); // ... if I >>need<< to call both methods.
^
運算符沒有短路等效項,因為擁有一個短路符根本沒有意義。
擁有語言參考是一回事,正確地解釋它是另一回事。
我們需要正確地解釋事物。
即使Java記錄了&
既是按位又是邏輯的,我們仍可以提出這樣的論據,即&
自從遠古時代以來就並沒有喪失其邏輯操作者的魔力,因為C。也就是說, &
首先是一個固有的邏輯運算符(盡管那是一個非短路的)
&
詞法上+邏輯上分析為邏輯運算。
為了證明這一點,從C到現在,這兩行的行為都相同(Java,C#,PHP等)
if (a == 1 && b)
if (a == 1 & b)
也就是說,編譯器將這些解釋為:
if ( (a == 1) && (b) )
if ( (a == 1) & (b) )
即使變量a
和b
都是整數。 這個...
if (a == 1 & b)
...仍然會解釋為:
if ( (a == 1) & (b) )
因此,這將在不便於整數/布爾對偶的語言(例如Java和C#)上產生編譯錯誤。
if (a == 1 & b)
實際上,在上面的編譯錯誤中,我們甚至可以提出一個論點,即&
沒有失去其邏輯(非短路)操作mojo,並且可以得出結論,Java繼承了C的傳統,使得&
仍然是邏輯操作。 因此,我們可以說是另一回事了,即可以將&
用作按位運算(通過應用括號):
if ( a == (1 & b) )
因此,在另一個並行世界中,我們可能會問,如何使&
表達式成為位掩碼操作。
如何進行以下編譯,我在JLS中讀取了
&
是按位操作。 a和b都是整數,但是我無法理解為什么以下按位運算是Java中的編譯錯誤:如果(a == 1&b)
還是這樣的問題:
為什么下面的代碼不能編譯,我在JLS中讀到
&
是兩個操作數均為整數時的按位運算。 a和b都是整數,但是我無法理解為什么以下按位運算是Java中的編譯錯誤:如果(a == 1&b)
實際上,如果已經存在與上述問題類似的現有的stackoverflow問題,我會對此感到驚訝,這些問題詢問了如何在Java中執行該掩蓋習慣。
為了使該語言的邏輯運算解釋按位進行,我們必須這樣做(在所有語言,C,Java,C#,PHP等上):
if ( a == (1 & b) )
因此,回答這個問題並不是因為JLS定義了這種方式,而是因為Java(以及其他受C啟發的語言)的&
運算符出於所有意圖,並且仍然是邏輯運算符,它保留了C的語法和語義。 這是因為C語言的方式 ,自遠古以來,因為之前我甚至出生。
事情並非偶然發生,JLS 15.22並非偶然發生,它有着悠久的歷史。
在另一個並行世界中,沒有將&&
引入語言,我們仍將使用&
進行邏輯運算,今天甚至可能會問一個問題:
是真的,我們可以使用邏輯運算符
&
進行按位運算嗎?
&
不在乎其操作數是否為整數,是否為布爾值。 它仍然是一個邏輯運算符 ,一個非短路運算符 。 實際上,迫使它成為Java(甚至C語言)中按位運算符的唯一方法是在其周圍加上括號。 即
if ( a == (1 & b) )
考慮一下,如果&&
沒有引入C語言(以及任何復制其語法和語義的語言),那么現在任何人都可以問:
如何使用
&
進行按位運算?
&
本質上是一個邏輯運算符(非短路運算符),它並不關心其操作數,即使兩個操作數都將照常進行操作(應用邏輯運算)是整數(例如,掩碼成語)。 您只能通過應用括號將其強制變為按位運算。 Java延續了C的傳統 如果Java的&
確實是按位運算,並且其操作數(下面的示例代碼中的整數1和整數變量b
)都是整數,則應編譯為:
int b = 7;
int a = 1;
if (a == 1 & b) ...
它們( &
和|
)很久以前就用於兩個目的,即邏輯運算符和按位運算符。 如果您要檢查新生兒C(語言是Java的后繼方式), &
和|
被用作邏輯運算符。
但是,由於在同一條語句中將按位運算與邏輯運算區別開來非常令人困惑,因此它提示Dennis Ritchie為邏輯運算符創建一個單獨的運算符( &&
和||
)。
在此處檢查新生兒C部分: http : //cm.bell-labs.com/who/dmr/chist.html
您仍然可以將按位運算符用作邏輯運算符 ,其保留的運算符優先級就是證明。 讀出按位運算符的前世歷史,作為新生兒C上的邏輯運算符
關於證據,我在博客文章中比較了邏輯運算符和按位運算符。 不言而喻的是,如果您嘗試在實際程序中進行對比,那么所謂的按位運算符仍然是邏輯運算符: http : //www.anicehumble.com/2012/05/operator-precedence-101.html
我還回答了一個與您有關C中邏輯運算符的意義是什么的問題。
因此,按位運算符也是邏輯運算符,盡管短路邏輯運算符的非短路版本也是如此。
關於
已經有邏輯運算符&&,||,那么為什么要使用&,|,^?
XOR很容易回答,就像一個單選按鈕,只允許一個,下面的代碼返回false。 對於下面人為設計的代碼示例表示歉意,認為同時喝啤酒和牛奶都是不好的信念已經被揭穿了 ;-)
String areYouDiabetic = "Yes";
String areYouEatingCarbohydrate = "Yes";
boolean isAllowed = areYouDiabetic == "Yes" ^ areYouEatingCarbohydrate == "Yes";
System.out.println("Allowed: " + isAllowed);
沒有等效於XOR按位運算符的短路,因為需要對表達式的兩端進行求值。
關於為什么需要使用&
和|
按位運算符作為邏輯運算符,坦率地說,您將很難找到使用按位運算符(也稱為非短路邏輯運算符)作為邏輯運算符的需要。 如果您想獲得一些副作用並使代碼緊湊(主觀的),則邏輯操作可以是非短路的(通過使用按位運算符,也稱為非短路邏輯運算符),例如:
while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) {
// re-prompt
}
上面的代碼可以重寫為以下代碼(刪除括號),但其解釋仍與前面的代碼完全相同。
while ( !password.isValid() & attempts++ < MAX_ATTEMPTS ) {
// re-prompt
}
除去括號后,它仍然產生與括號中相同的解釋,可以使&
的邏輯運算符痕跡更加明顯。 為了冒聽起來多余的風險,但我必須強調,未加括號的表達式不能解釋為:
while ( ( !password.isValid() & attempts++ ) < MAX_ATTEMPTS ) {
// re-prompt
}
綜上所述,使用&
運算符(通常更廣為人知的是按位運算符,但是實際上兼具按位和邏輯(非短路))來實現副作用的非短路邏輯很聰明(主觀),但不鼓勵這樣做,它只是節省一行代碼以換取可讀性。
源自以下示例: 存在非短路邏輯運算符的原因
Java類型字節已簽名,這對於按位運算符可能是個問題。 當負數字節擴展為int或long時,將符號位復制到所有更高的位以保留解釋后的值。 例如:
byte b1=(byte)0xFB; // that is -5
byte b2=2;
int i = b1 | b2<<8;
System.out.println((int)b1); // This prints -5
System.out.println(i); // This prints -5
原因:(int)b1內部為0xFFFB,b2 << 8為0x0200,所以我將為0xFFFB
解:
int i = (b1 & 0xFF) | (b2<<8 & 0xFF00);
System.out.println(i); // This prints 763 which is 0x2FB
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.