在一次采访中,我的面试官问我:
如果在以下代码中将 && 替换为 & 会出现什么问题:
String a=null; if (a!=null && a.length()>10) {...}
&&
是逻辑 AND 运算符(执行短路行为,这意味着仅在需要时才评估第二个操作数)
&
是按位与运算符(按位 & 运算符执行按位与运算)。
因为没有短路行为,你会得到NullPointerException
.
ANullPointerException
将被抛出,因为使用时没有短路&
,这意味着即使左侧操作数的结果是 ,也始终false
评估右侧操作数。使用时,仅当左侧操作数为 时才&&
计算右侧操作数。true
第15.22.2 节。布尔逻辑运算符 &、^ 和 | 和15.23。Java 语言规范中的条件与运算符 &&描述了这种行为。
知道了 :
这里的单个 & 符号将导致NullPointerException
. 因为 && 是逻辑 AND 运算符,并且仅在需要时才评估第二个操作数。
当您使用&&时,如果第一个表达式为假,它不会评估第二个表达式。 &另一方面,无论如何都会评估这两个表达式。
在您的情况下,如果您将'&&'替换为&它会抛出NullPointedException
&
并且&&
在表达式评估中具有不同的优先级,并且在不()
包围相邻表达式的情况下,在某些情况下您可能会得到一些“惊喜”。特别是,&&
在优先级中相当晚,因此您通常不需要()
它,除非您将混合逻辑表达式的结果组合在一起。但&
足够早让你措手不及。
&&
是短路的,这意味着如果第一个表达式为假,则根本不计算第二个表达式。 &
不会短路。在上面的例子中,这意味着用&&
第二个表达式不会抛出 NullPointerException——这通常是&&
.
与 Java 以外的类 C 语言相关:一旦您克服了上述两个陷阱,接下来就是操作实际做什么的问题。如果被评估的两个表达式都产生“布尔”结果,那么这些值将提升为 0x00 或 0x01,并且&
and&&
运算符将产生基本相同的答案。但是,如果其中一个表达式不是布尔值,那么您最终可能会将 0x01 和 0x02 进行与运算,例如,并产生 0x00,即使&&
运算符的计算结果为真。(对于 Java 来说并不是一个特别的问题,因为它不允许 非布尔操作数&&
,也不允许混合布尔/整数操作数&
。)