【问题标题】:Reason for precedence of instanceof/isinstanceof/is 优先的原因
【发布时间】:2013-08-23 00:21:37
【问题描述】:

在 C#/Java 中,isinstanceof 的运算符优先级导致了一些丑陋的必要括号。例如,您必须写if (!(bar instanceof Foo)),而不是写if (!bar instanceof Foo)

那么为什么语言团队决定 ! 的运算符优先级高于 is/instanceof?诚然,在 C# 中,您可以覆盖 operator!,这在某些情况下会导致不同的结果,但这些情况似乎非常罕见(并且在任何情况下都不直观),而检查某物是否不是类型或子类型的情况更有可能发生的事情。

【问题讨论】:

  • 这不应该在programmers.stackexchange.com结束吗?
  • @Adrian Imo 更适合这里,我在程序员的描述中看不到任何关于语言理论的内容。

标签: c# java language-theory


【解决方案1】:

在 Java 中,instanceofrelational operators 之一,并且与其他 instanceof 具有相同的优先级:

RelationalExpression:
    ShiftExpression
    RelationalExpression < ShiftExpression
    RelationalExpression > ShiftExpression
    RelationalExpression <= ShiftExpression
    RelationalExpression >= ShiftExpression
    RelationalExpression instanceof ReferenceType

从这个角度来看,这两行应该遵循相同的结构是有道理的:

if (!(a instanceof b))
if (!(a < b))

【讨论】:

  • 当然,但这只是技术原因,即它是如何实现的(实际上我觉得很奇怪你将实例扔到关系运算符中),但不是他们为什么把它放在那里。
  • RelationExpression 是唯一对 instanceof (IMO) 有意义的类别。另一种选择是创建一个特定的类别。
【解决方案2】:

阴谋论:

C# 设计者不希望你使用is 运算符。这个操作符的使用通常是糟糕的 OOP 设计的味道。如果您发现自己经常使用它,这可能意味着您的类层次结构错误,您需要更多地依赖虚拟方法和模式。 Java 设计者走得更远:他们将操作符命名为 instanceof,让您每次使用时都会感到畏缩。

这实际上不太可能。在很多情况下,语言和库设计者会使某些功能不方便使用。一些例子:.NET 中的字符编码(你应该总是使用 Unicode),Pascal 中的goto(你应该避免它)等等。有时它是由糟糕的设计引起的(比如 .NET 中的 WPF),但有时它是故意的。

【讨论】:

  • 这实际上是一个很好的理由,我同意这并不牵强。 Java 和 C# 都竭尽全力将程序员推向特定的编程风格,避免使用这种运算符当然很合适。
【解决方案3】:

以下是我对此事的看法,没有权威来源。

instanceof 是一个非常大的运算符。大多数运算符最多为两个字符。此外,instanceof 和变量之间必须有空格。因为这两个独特的东西,当你看像!bar instanceof Foo这样的表达式时,instanceof似乎很自然地将!barFoo分开,如果!bar不是一个子,很多人会感到惊讶。表达。

类似的思路也可以应用于is,只是遵循 Java 已经做过的附加论点。

【讨论】:

    【解决方案4】:

    我认为这只是历史性的。如果我在 Java 的最初版本中没记错的话,你甚至不能在没有括号的情况下编写 if(a instanceof Foo || a instanceof Bar)。我认为 Java 2 发生了变化。我不知道他们为什么不把它放在更高的优先级上(例如,高于逻辑非)。也许是因为它会干扰类型转换运算符,从而破坏兼容性?

    C# 似乎刚刚使用了与 Java 相同的优先级。

    我仍然认为将按位和/或的优先级与逻辑和/或保持在同一级别也是错误的。不得不写像if( (x&amp;(FLAG1|FLAG2)) != 0) … 这样的东西很烦人。

    【讨论】:

      【解决方案5】:

      instanceof 是二元运算符。 ! 是一元运算符。

      instanceof! 绑定得更紧密会非常混乱
      混淆的一个典型例子是 Python 中的 **-,我们有:

      -1 ** 2 == -(1 ** 2)  # true
      

      我不了解你,但这对我来说在 Python 中看起来很荒谬,所以我很高兴他们没有在 Java 中做同样的事情。

      另一个 Python 示例是:

      False is (not None)   # false
      

      False is not None     # true
      

      我认为这同样令人困惑,这一次是因为 isis not 是不同的运算符。

      【讨论】:

        【解决方案6】:

        因为通过写if (!bar instanceof Foo) 它会否定条形然后查找instanceof。因为这是最左边的语句,我认为 instanceof 甚至没有优先级

        然后if (!(bar instanceof Foo)) 首先使它成为instanceof,然后否定整个事情。

        如果你需要否定 bar 然后检查实例然后做((!bar) instanceof Foo)

        【讨论】:

        • 是的,我了解运算符优先级如何工作的基础知识。问题是为什么以这种方式选择运算符优先级。显然,您不必编写 5 + (2 * 3) 来获得 11 而不是 21 的正确结果 - 正是因为正确选择了运算符优先级(“正确”显然仅适用于整数的特定域)。在这里也可以做同样的事情——或者不做?就是这个问题。
        • 否定一个对象是什么意思?
        • 否定一个对象只有在它有一个隐式可转换的布尔值时才有效,我会想到。
        • 是的,我也注意到了,但我猜作者对技术人员比实际逻辑更感兴趣
        • @Jeff operator! 在 C# 中可以任意重载,但是是的,这就是重点——几乎没有用处,所以为什么选择这样的命令。优先权属于数学运算符的说法是错误的,必须定义 所有 运算符,instanceof 也不例外。强制转换、对象访问 (.) 或数组成员访问也是如此——所有这些都在语言规范中明确定义了优先级。左关联性仅适用于相同级别的优先级,即使如此,也仅在已声明的情况下才适用!例如,分配优先级定义为右结合。
        【解决方案7】:
        1. +++ 等基本运算符相比,instanceof 是一个非常长的单词。当你阅读状态时,你只是失去了注意力,至少我是这样。
        2. 它被空格包围,可以提高可读性,但另一方面,您无法将它连接与其他操作数,例如喜欢5+6 可以。

        我相信这些人决定说:好吧,降低优先级,所以每个人都必须提供括号来确定发生了什么

        【讨论】:

          【解决方案8】:

          显然,像!b instanceof SomeType 这样的表达式(阅读:“否定b,然后检查结果值是否为SomeType 类型”)在Java 中没有多大意义:

          从逻辑上讲,b 必须是某种布尔对象(这样! 才能工作),即使你否定它的值,它仍然是一个布尔值,与以前的类型相同,所以为什么要打扰一开始就否定它?

          (实际上,你甚至不能这样做:b 不能是 boolean,因为 instanceof 要求它是真正的 Object,但话又说回来,如果 bBoolean!b 仍会评估为原始 boolean,因此 instanceof 不起作用。)

          因此我们可以说!b instanceof SomeType 在Java 中根本没有语义意义。所以我们可以将其含义重新分配为“检查b 是否不是SomeType 类型”——不是吗?

          鉴于这可能已经在语义上进行了更改,但仍未完成,这让我得出这样的结论,即这并不是故意的,但有一个更务实的理由来为instanceof 使用较低的优先级:

          在我的脑海中,我怀疑如果你给 instanceof 比一元运算符 ! 更高的优先级,解析会变得复杂。你可能想检查一下。

          另一方面,如果!b instanceof SomeType 的意思是“检查b 是否不是SomeType 类型”,这仍然会诱使新手程序员认为!b 上运行,而实际上它是否定instanceof 的结果,因此让!b instanceof SomeType 基本上未定义就不会那么模棱两可了。

          【讨论】:

            【解决方案9】:

            因为C编程语言弄错了,Java一味的跟着C。

            在 C 中,!和 ~ 的优先级相同。在实践中,它实际上在 C 中并不重要,因为有人写道 a=b)。

            但是没有notinstanceof操作符。

            您可能还会问为什么 /* /* */ */ 没有正确嵌套。或者为什么 Java 从 0 开始计数。或者为什么需要一个 void 关键字。或者为什么 Java 使用可怕的 {{}{}} 符号而不是 endif(或 fi)。这都是 C 的遗产。

            也许有充分的理由。 C 程序员会争辩说所有这些都是正确的方法,因为这是他们习惯的。 Java 的首要任务是引起人们的注意和使用,这与许多其他早已被遗忘的小编程语言不同。

            感谢 Java 没有以 null 结尾的字符串。

            【讨论】:

              猜你喜欢
              • 2011-09-16
              • 1970-01-01
              • 1970-01-01
              • 1970-01-01
              • 2019-10-24
              • 1970-01-01
              • 2013-04-02
              • 2020-05-23
              • 2020-08-10
              相关资源
              最近更新 更多