is
和instanceof
的运算符优先级会导致一些必要但繁琐的括号。例如,你需要写成if (!(bar instanceof Foo))
而不是if (!bar instanceof Foo)
。那么为什么语言团队决定把
!
的优先级放在is/instanceof之上呢?尽管在C#中你可以重载operator!
,这会在某些情况下导致不同的结果,但这些情况似乎非常罕见(而且在任何情况下都不直观),而检查某个东西是否不是某种类型或其子类型的情况则更加常见。is
和instanceof
的运算符优先级会导致一些必要但繁琐的括号。例如,你需要写成if (!(bar instanceof Foo))
而不是if (!bar instanceof Foo)
。!
的优先级放在is/instanceof之上呢?尽管在C#中你可以重载operator!
,这会在某些情况下导致不同的结果,但这些情况似乎非常罕见(而且在任何情况下都不直观),而检查某个东西是否不是某种类型或其子类型的情况则更加常见。instanceof
是一种关系运算符,它与其他关系运算符具有相同的优先级。RelationalExpression:
ShiftExpression
RelationalExpression < ShiftExpression
RelationalExpression > ShiftExpression
RelationalExpression <= ShiftExpression
RelationalExpression >= ShiftExpression
RelationalExpression instanceof ReferenceType
从这个角度来看,那两行文本应该遵循相同的结构:
if (!(a instanceof b))
if (!(a < b))
以下是我对此事的看法,没有权威来源。
instanceof
是一个非常大的操作符。大多数操作符最多有两个字符。此外,instanceof
必须在变量和它之间加上空格。因为这两点独特之处,当你看到像 !bar instanceof Foo
这样的表达式时,instanceof
看起来自然地将 !bar
和 Foo
分开,许多人会觉得如果 !bar
不是子表达式很出乎意料。
类似的思路也可以应用于 is
,另一个论据是遵循 Java 已经做过的事情。
阴谋论:
C# 设计师们不希望你使用 is
操作符。过多使用该操作符常常暗示着糟糕的面向对象设计。如果你发现自己经常使用这个操作符,那么很可能是因为你的类层次结构有问题,需要更重度依赖虚方法和模式。Java 的设计师甚至更进一步:他们将操作符命名为instanceof
,以使你每次使用时都感到不悦。
实际上这并非不可能。在.NET中,有许多情况下,语言和库设计者会使一些功能难以使用。一些例子: .NET 中的字符编码(应始终使用Unicode),Pascal 中的goto
(应避免使用)等。有时是由于糟糕的设计造成的(如.NET中的WPF),但有时也是故意的。
if(a instanceof Foo || a instanceof Bar)
,而不带括号。我想在Java 2左右发生了一些变化。我不知道为什么他们没有将其放在更高的优先级上(例如高于逻辑非)。也许是因为它会干扰类型转换运算符,从而破坏兼容性?if( (x&(FLAG1|FLAG2)) != 0) …
。instanceof
是一个二元运算符。
!
是一个一元运算符。
如果instanceof
比!
的优先级更高,那么会造成非常混乱的情况。
在Python中,我们有**
和-
这两个运算符也存在类似的混乱问题。
-1 ** 2 == -(1 ** 2) # true
我不知道你怎么看,但在Python中这看起来很荒谬,所以我很高兴他们没有在Java中做同样的事情。
另一个Python示例是:
False is (not None) # false
并且
False is not None # true
!b instanceof SomeType
这样的表达式(读作:“否定b
,然后检查结果值是否为类型SomeType
”)并没有多大意义:
从逻辑上讲,b
必须是某种布尔对象(以便!
起作用),即使您否定了它的值,它仍将是一个布尔值,并且与之前相同类型,那么为什么要首先对其进行取反呢?
(实际上,您甚至不能这样做:b
不能是boolean
,因为instanceof
需要它是真正的Object
,但是,如果b
是Boolean
,!b
仍将求值为原始的boolean
,因此instanceof
不起作用。)
因此,我们可以说!b instanceof SomeType
在Java中根本没有语义意义。那么我们可以将其重新赋予“检查b
是否不是类型SomeType
”的含义-难道不是吗?
instanceof
:instanceof
比一元运算符 !
更高的优先级,解析将变得复杂。你可能需要检查一下。!b instanceof SomeType
的意思是“检查 b
是否不是类型 SomeType
”,这可能仍然会欺骗新手程序员认为 !
作用于 b
,而实际上它是否定 instanceof
的结果,所以最好将 !b instanceof SomeType
留在本质上未定义。因为通过编写if (!bar instanceof Foo)
它否定了bar然后查找instanceof。因为这是最左边的语句,我不认为instanceof甚至有优先级。
然后if (!(bar instanceof Foo))
它使instanceof成为首要考虑,并否定整个事情。
如果您需要否定bar然后检查实例,则执行((!bar) instanceof Foo)
5 +(2 * 3)
才能获得正确结果11,而不是21 - 这正是因为正确选择了运算符优先级(“正确”显然只适用于整数特定领域)。同样的方法也可以在这里使用 - 或者不行?这就是问题所在。 - Voooperator!
在 C# 中可以任意重载,但是这并不常用,所以为什么要选择这样的顺序呢?声称优先级属于数学运算符是错误的,所有运算符都必须被定义,instanceof
也不例外。同样适用于强制类型转换、对象访问(.
)或数组成员访问——所有这些在语言规范中都有明确定义的优先级。左结合性仅适用于相同优先级的情况,即使在这种情况下也只有在声明时才适用!例如,赋值优先级级别被定义为右结合。 - Vooinstanceof
这个单词与基本运算符如+
或++
相比非常长。当你阅读条件时,你就会分心,至少我是这样的。5+6
那样与其他操作数连接起来。我相信他们决定说:好吧,优先级较低,因此每个人都必须提供括号以确保发生了什么
因为C编程语言犯了错误,而Java盲目地跟随了C。
在C中,!和~具有相同的优先级。实际上,在C中并不重要,因为人们会写a<b而不是!(a>=b)。
但是,Java没有notinstanceof运算符。
你可能还会问为什么/* /* */ */不能正确嵌套。或者为什么Java从0开始计数。或者为什么需要void关键字。或者为什么Java使用可怕的{{}{}}表示法而不是endif(或fi)。这都是C遗留问题。
也许有充分的理由。C程序员会认为所有这些东西都是正确的方法,因为这是他们习惯的方式。而Java的第一项任务是被注意到和使用,不像许多其他已被遗忘的小型编程语言。
感谢Java没有空终止字符串。