是&,|,^位运算符还是逻辑运算符?

时间:2012-07-22 05:36:19

标签: java operators

首先,我了解到&|^是按位运算符,现在有人将它们称为&&||的逻辑运算符,我完全糊涂了 - 同一个运营商有两个名字?已有逻辑运算符&&||,那么为什么要使用&|^

4 个答案:

答案 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) )

即使变量ab都是整数。此...

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 &本质上是一个逻辑运算符(非短路运算符),它不关心它的操作数,它将照常开展业务(应用逻辑运算)即使两个操作数都是整数(例如掩蔽成语)。您只能通过应用括号来强制它成为按位运算。 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