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

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

Java运算符&|^是按位运算符或逻辑运算符…取决于操作数的类型。 如果操作数是整数,则运算符是按位的。 如果他们是布尔,那么运营商是合乎逻辑的。

这不仅仅是我这样说的。 JLS也以这种方式描述了这些运算符; 见JLS 15.22 。

(这就像+意思是添加或字符串连接…取决于操作数的类型。或者就像“玫瑰”意味着花或淋浴附件。或“猫”意味着毛茸茸的动物或UNIX命令。单词在不同的上下文中表示不同的东西。对于编程语言中使用的符号也是如此。)


已有逻辑运算符&&|| ,为什么要使用&|^

在前两个的情况下,这是因为运算符在何时/是否被评估操作数方面具有不同的语义。 在不同的情况下需要两种不同的语义; 例如

  boolean res = str != null && str.isEmpty(); 

  boolean res = foo() & bar(); // ... if I >>need<< to call both methods. 

^运算符没有等效的短路,因为它只是没有意义。

拥有语言参考是一回事,正确地解释它是另一回事。

我们需要正确地解释事物。

即使Java记录了&且既有点又有逻辑性,我们可以做出一个论证,并且自从远古以来就真的没有失去它的逻辑运算符性mojo,因为C.这就是,首先是,并且本质上是逻辑的运营商(虽然是非短路运营商)

&作为逻辑操作以词法+逻辑方式解析。

为了certificate这一点,这两行都表现相同,从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&b)

或者这类问题:

为什么以下没有编译,我在JLS中读到,当它的两个操作数都是整数时,它是一个按位运算。 a和b都是整数,但是我不知道为什么以下按位运算是Java中的编译错误:

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