为什么Java和C#中有逻辑运算符和位运算符之分?

10

像Java和C#这样的语言具有按位和逻辑运算符。

逻辑运算符仅与布尔操作数有意义,而按位运算符也可以使用整数类型。由于C没有布尔类型并将所有非零整数视为true,因此在这里存在逻辑和按位运算符是有意义的。然而,像Java或C#这样的语言具有布尔类型,因此编译器可以根据类型上下文自动使用正确的运算符。

那么,在这些语言中同时拥有逻辑和按位运算符是否有一些具体原因?还是仅出于熟悉性的考虑而包含它们?

(我知道您可以在Java和C#中的布尔上下文中使用“按位”运算符来规避短路行为,但我从未需要过这种行为,因此我认为它可能是一个基本上不被使用的特殊情况)


例如:请参见https://dev59.com/gmgu5IYBdhLWcg3wUljt - assylias
6个回答

7

1) 这些语言中是否有同时拥有逻辑运算符和位运算符的具体原因吗?

是的:

  • 我们有布尔运算符来进行布尔逻辑(在布尔值上)。
  • 我们有位运算符来进行位逻辑(在整数值上)。

2) 我知道您可以在Java和C#中使用“位”运算符来规避短路,

就C#而言,这完全不正确。
例如,C#有两个布尔AND运算符:&(完整)和&&(短路),但它不允许对布尔值进行位运算。

因此,逻辑和位运算符之间实际上没有“重叠”或冗余。 两者不适用于相同类型。


1
此外,C# 中的运算符 ^(异或)对整数类型(如 intlong)进行了重载,其中它是一个按位运算符,但也有一个重载用于 bool,在这种情况下它是一个逻辑运算符。因此,认为(至少在 C# 中)当符号不是双倍时(不是 &&||),那么这就是一个按位操作是错误的。这取决于使用哪个重载。唯一一个由于某种原因在按位和逻辑上具有不同符号的运算符是否定运算符(分别为 ~i!b)。 - Jeppe Stig Nielsen

3
晚回答了,但我会试着解决你的问题。
你说得对。而且最容易表达你的观点的方法是提到其他类型化语言(如Visual Basic)具有可以作用于布尔和整数表达式的逻辑运算符。
VB Or 运算符: http://msdn.microsoft.com/en-us/library/06s37a7f.aspx VB 位运算示例:http://visualbasic.about.com/od/usingvbnet/a/bitops01_2.htm 这在很大程度上是一种语言设计决策。Java和C#不必是它们现在的样子,它们只是它们现在的样子。为了让人感到熟悉,Java和C#确实从C语言中继承了很多语法。其他语言却没有这样做,同样可以很好地工作。
一个像这样的设计决策会产生后果。短路评估是其中之一。禁止混合类型(这可能会让人们感到困惑)是另一个后果。我已经喜欢它了,但也许我只是盯着Java看太久了。
Visual Basic添加了AndAlso和OrElse作为执行短路评估的方法。与基本的其他逻辑运算符不同,这些仅适用于布尔值。
VB OrElse:http://msdn.microsoft.com/en-us/library/ea1sssb2.aspx 短路描述:http://support.microsoft.com/kb/817250 这种区别并不是因为强类型使得在语言中只有一个逻辑运算符集合不可能。而是因为他们想要短路评估,并且他们想要一种清晰的方式向读者表明正在发生的事情。
除了短路之外,C和C++拥有不同类型的逻辑运算符的另一个原因是允许任何非零数字被重新解释为TRUE,而零被重新解释为FALSE。为此,它们需要告诉自己如何进行解释的运算符。Java拒绝了这个重新解释的想法,并在你试图使用它的逻辑运算符进行操作时向你抛出错误。如果没有短路评估,唯一剩下的原因就是他们希望在执行不同的操作时运算符看起来不同。

所以,是的,如果Java和C#语言设计者不关心这些问题,他们可以为位运算和布尔逻辑使用一组逻辑运算符,并根据操作数类型确定要执行哪种操作,就像其他一些语言所做的那样。只是他们没有这样做。


3

在C#中,使用布尔值

  • &&是一个短路逻辑运算符
  • &是一个非短路逻辑运算符

在位运算中,&只是从C/C++中继承的语法,但实际上它们是非常不同的。如果必须要用,最好使用一个完全不同的符号以避免任何混淆。但是现在已经没有太多选择了,除非您想使用&&&或|||,但那有点难看。


2

我来翻译一下Java相关的内容。

  • 逻辑运算符用于布尔类型,位运算符用于整型。它们不能混用。
  • 为什么不把它们简化成一个运算符,比如"&"或者"|"呢?因为Java被设计成友好的C/C++用户,所以它沿用了它们的语法。现在这些运算符由于向后兼容性的原因无法简化。

2
正如您已经所说,&&&|||同理)之间存在一些差异,因此您需要两组布尔运算符。除此之外,您可能需要按位运算符,最好选择&|等,因为您不必避免任何混淆。
为什么要使事情复杂,并使用两个字符的版本?

一个运算符是否短路与它执行位运算有些无关。可以定义一个短路位and运算符,它将评估第一个参数,并且如果非零,则评估第二个参数并计算参数的按位与(否则评估为零)。 - supercat

1

编译器无法仅通过参数推断出正确的运算符。选择哪个运算符是一个业务决策。这与惰性计算有关。例如:

public boolean a() {
  doStuffA();
  return false;
}

public boolean b() {
  doStuffB();
  return true;
}

现在: a() & b() 将执行 doStuffB(),而 a() && b() 不会执行。

正如我在问题中所述,您描述的情况并不经常发生。此外,我认为很多程序员看到代码“a()&b()”可能会错误地认为它是一个错误,并将其“更正”为&&运算符,因此先调用方法,稍后再使用逻辑&&可能会更清晰地表达原始程序员的意图。 - Askaga

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接