首先,我了解到&
,|
,^
是按位运算符,现在有人将它们称为&&
,||
的逻辑运算符,我完全糊涂了 - 同一个运营商有两个名字?已有逻辑运算符&&
,||
,那么为什么要使用&
,|
,^
?
答案 0 :(得分:20)
Java运算符&
,|
和^
是按位运算符或逻辑运算符...取决于操作数的类型。如果操作数是整数,则运算符是按位的。如果它们是布尔值,则运算符是合乎逻辑的。
这不仅仅是我说的。 JLS也以这种方式描述了这些运算符;见JLS 15.22。
(这就像+
意思是添加或字符串连接...取决于操作数的类型。或者就像“玫瑰”意味着花或淋浴附件。或“猫”这意味着毛茸茸的动物或UNIX命令。在不同的上下文中,单词意味着不同的东西。对于编程语言中使用的符号也是如此。)
已有逻辑运算符
&&
,||
,为何使用&
,|
,^
?
在前两个的情况下,这是因为运算符在何时/是否被评估操作数方面具有不同的语义。在不同的情况下需要两种不同的语义; e.g。
boolean res = str != null && str.isEmpty();
与
boolean res = foo() & bar(); // ... if I >>need<< to call both methods.
^
运算符没有等效短路,因为它只是没有意义。
答案 1 :(得分:3)
拥有语言参考是一回事,正确解释它是另一回事。
我们需要正确解释事情。
即使Java记录&
既符合逻辑又符合逻辑,我们可以提出一个论点&
从远古以来就没有失去过它的逻辑运算符的mojo,因为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中的编译错误:if(a == 1&amp; b)
或者这类问题:
为什么下面没有编译,我在JLS中读到
&
是一个按位 当两个操作数都是整数时的操作。 a和b都是 整数,但它让我想到了为什么下面的按位运算是a Java中的编译错误:if(a == 1&amp; b)
事实上,如果已经存在类似于上述问题的现有stackoverflow问题,我会不会感到惊讶,这些问题询问如何在Java中使用这种掩蔽习惯。
为了使语言的逻辑运算解释成为按位,我们必须这样做(在所有语言,C,Java,C#,PHP等):
if ( a == (1 & b) )
所以回答这个问题,并不是因为JLS定义了这样的东西,这是因为Java(以及受C启发的其他语言)的&
运算符用于所有意图和目的仍然是一个逻辑运算符,它保留了C的语法和语义。 这是自C以来的方式,自远古时代以来,就在我出生之前。
事情本来就不是偶然发生的,JLS 15.22并非偶然发生,它周围有着深刻的历史。
在另一个并行的Universe中,&&
没有引入该语言,我们仍然会使用&
进行逻辑操作,甚至可能会在今天提出问题:
是真的,我们可以使用逻辑运算符
&
进行按位运算吗?
&
不关心,如果它的操作数是否为整数,是否为布尔值。它仍然是一个逻辑运营商,一个非短路运营商。事实上,强制它成为Java中的按位运算符(甚至在C中)的唯一方法是在其周围加上括号。即。
if ( a == (1 & b) )
考虑一下,如果没有将&&
引入C语言(以及任何复制其语法和语义的语言),任何人都可以现在问:
如何使用
&
进行按位运算?
&
本质上是一个逻辑运算符(非短路运算符),它不关心它的操作数,它将照常开展业务(应用逻辑运算)即使两个操作数都是整数(例如掩蔽成语)。您只能通过应用括号来强制它成为按位运算。 Java延续了C传统如果Java的&
实际上是一个按位操作,如果它的操作数(下面的示例代码中的整数1和整数变量b
)都是整数,那么这应该编译:
int b = 7;
int a = 1;
if (a == 1 & b) ...
答案 2 :(得分:1)
他们(&
和|
)很久以前用于两个目的,逻辑运算符和按位运算符。如果您要查看新生儿C(之后的Java语言),&
和|
被用作逻辑运算符。
但是,由于在同一语句中消除逻辑运算中的按位运算非常混乱,因此它促使Dennis Ritchie为逻辑运算符创建一个单独的运算符(&&
和||
)。
在此处查看新生儿C 部分:http://cm.bell-labs.com/who/dmr/chist.html
您仍然可以将按位运算符用作逻辑运算符,其保留的运算符优先级就是证据。读出按位运算符的前世的历史作为Neonatal C上的逻辑运算符
关于证据,我写了一篇关于比较逻辑运算符和按位运算符的博客文章。如果您尝试在实际程序中对比它们,那么所谓的按位运算符仍然是逻辑运算符将是不言而喻的:http://www.anicehumble.com/2012/05/operator-precedence-101.html
我还在What is the point of the logical operators in C?
上回答了与您的问题相关的问题所以这是真的,按位运算符也是逻辑运算符,虽然是短路逻辑运算符的非短路版本。
关于
已经有逻辑运算符&amp;&amp;,||,那么为什么要使用&amp ;, |,^?
可以轻松回答XOR,它就像一个单选按钮,只允许一个,下面的代码返回false。对于下面人为的代码示例的道歉,认为同时饮用啤酒和牛奶的信念是debunked already; - )
String areYouDiabetic = "Yes";
String areYouEatingCarbohydrate = "Yes";
boolean isAllowed = areYouDiabetic == "Yes" ^ areYouEatingCarbohydrate == "Yes";
System.out.println("Allowed: " + isAllowed);
没有与XOR位运算符等效的短路,因为需要对表达式的两边进行求值。
为什么需要使用&
和|
按位运算符作为逻辑运算符,坦率地说,你很难找到使用按位运算符的需要(又称非短路逻辑运算符) operator)作为逻辑运算符。逻辑运算可以是非短路的(通过使用按位运算符,也就是非短路逻辑运算符),如果你想实现一些副作用并使你的代码紧凑(主观),例如:
while ( !password.isValid() & (attempts++ < MAX_ATTEMPTS) ) {
// re-prompt
}
以上内容可以重写如下(删除括号),并且仍然具有与前面代码完全相同的解释。
while ( !password.isValid() & attempts++ < MAX_ATTEMPTS ) {
// re-prompt
}
删除括号但它仍然产生与带括号的括号相同的解释,可以使&
的逻辑运算符痕迹更明显。冒险听起来多余,但我必须强调,没有表达的表达不会被解释为:
while ( ( !password.isValid() & attempts++ ) < MAX_ATTEMPTS ) {
// re-prompt
}
总结一下,使用&
运算符(通常称为按位运算符,但实际上是按位和逻辑(非短路))用于非短路逻辑运算来实现效果是聪明的(主观的),但不鼓励,它只是一行储蓄效应以换取可读性。
此处采购的示例:Reason for the exsistance of non-short-circuit logical operators
答案 3 :(得分:0)
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&lt;&lt; 8是0x0200所以我将是0xFFFB
解决方案:
int i = (b1 & 0xFF) | (b2<<8 & 0xFF00);
System.out.println(i); // This prints 763 which is 0x2FB