Java 运算符易混点:、||、、| 与位运算到底差在哪
2026/6/3 18:24:15 网站建设 项目流程

Java 运算符易混点:&&、||、&、| 与位运算到底差在哪

    • 一、先问一句:你在判断条件,还是在处理二进制位?
    • 二、`&&` 和 `||`:短路的意义是“右边可能不执行”
    • 三、`&` 和 `|` 放在 boolean 上:能用,但不短路
    • 四、`&`、`|`、`^`、`~` 放在整数上:逐位计算
      • 1. 按位与 `&`
      • 2. 按位或 `|`
      • 3. 按位异或 `^`
      • 4. 按位取反 `~`
    • 五、移位运算:移动的是二进制位
    • 六、优先级:能加括号就别考验读者
    • 七、实战判断口诀

🎬 博主名称:超级苦力怕

🔥 个人专栏:《基本功修炼大全》

🚀 每一次思考都是突破的前奏,每一次复盘都是精进的开始!


文章元信息:

  • 适合读者:Java 初学者、正在复习运算符和条件判断的后端入门读者
  • 前置知识:Java 基本语法、boolean 表达式、整数二进制表示的基本概念

如果你经常把 && 和 &、|| 和 | 记混,这篇从“条件判断”和“二进制位处理”两个场景切开讲,顺着示例看会轻松很多。

一、先问一句:你在判断条件,还是在处理二进制位?

&&||&|长得太像,所以最容易被混在一起记。真正的分界不是“一个符号还是两个符号”,而是你现在想做什么:

  • 如果是在ifwhile里组合条件,通常要的是短路逻辑&&||
  • 如果是在 boolean 表达式里强制两边都执行,才会用非短路布尔运算&|^
  • 如果操作的是整数、标志位、掩码、哈希、权限位,才是在做按位运算&|^~<<>>>>>

同一个符号在不同操作数类型下,含义会变:

运算符操作数类型含义是否短路
&&boolean短路逻辑与是,左边为false时右边不执行
||boolean短路逻辑或是,左边为true时右边不执行
&boolean非短路逻辑与否,两边都会执行
|boolean非短路逻辑或否,两边都会执行
^boolean逻辑异或否,两边都会执行
&整数类型按位与不属于短路逻辑
|整数类型按位或不属于短路逻辑
^整数类型按位异或不属于短路逻辑
~整数类型按位取反不属于短路逻辑

这里的“整数类型”包括byteshortcharintlong。其中byteshortchar参与位运算时会先提升成int


二、&&||:短路的意义是“右边可能不执行”

&&是短路逻辑与:左边已经是false时,整个表达式一定是false,右边不会再算。

示例代码(Java):短路与避免空指针

Strings=null;System.out.println(s!=null&&s.length()>0);// false

这段代码不会抛空指针异常,因为s != null已经是falses.length()根本不会执行。

||是短路逻辑或:左边已经是true时,整个表达式一定是true,右边不会再算。

示例代码(Java):短路或跳过右侧判断

intscore=95;if(score>=90||score==100){System.out.println("excellent");}

这里score >= 90已经为true,后面的score == 100不需要再判断。短路不是语法小优化,而是很多保护性写法成立的原因。

常见写法:

示例代码(Java):常见保护性判断

if(user!=null&&user.isActive()){// 先防 null,再访问对象方法}if(list==null||list.isEmpty()){// list 为 null 时,不会继续调用 isEmpty()}

判断条件时,默认选择&&||。这不是因为它们“更高级”,而是它们更符合条件判断的预期:前面的条件已经能决定结果时,后面的条件就不应该再制造副作用或异常。


三、&|放在 boolean 上:能用,但不短路

&|不只属于位运算。它们也可以作用在 boolean 上:

示例代码(Java):boolean 上的非短路运算

booleana=false;booleanb=true;System.out.println(a&b);// falseSystem.out.println(a|b);// true

结果看起来和&&||很像,但执行过程不一样:&|会把左右两边都算完。

示例代码(Java):单个&不会短路

Strings=null;System.out.println(s!=null&s.length()>0);

这段代码会抛NullPointerException。虽然左边s != nullfalse,但单个&不短路,右边的s.length()仍然会执行。

|也一样:

示例代码(Java):|会执行右侧方法

staticbooleanlogAndReturnTrue(){System.out.println("right side executed");returntrue;}publicstaticvoidmain(String[]args){booleanleft=true;System.out.println(left||logAndReturnTrue());// 右边不执行System.out.println(left|logAndReturnTrue());// 右边会执行}

所以在普通条件判断里,看到单个&|要先警惕:它可能不是作者想要的短路逻辑。

^放在 boolean 上表示逻辑异或:左右刚好一个为true,结果才是true

示例代码(Java):boolean 异或

System.out.println(true^false);// trueSystem.out.println(true^true);// false

它也不会短路,因为异或必须知道左右两边的值才能判断“是否不同”。


四、&|^~放在整数上:逐位计算

位运算不是在比较“整个数真不真”,而是在比较每一位二进制。

1. 按位与&

对应位都为1,结果位才是1

示例代码(Java):按位与

System.out.println(3&5);// 1

二进制过程(text):3 & 5 的逐位结果

3 -> 0011 5 -> 0101 & 0001 -> 1

常见用途是检查某一位是否存在

示例代码(Java):用掩码检查权限位

intREAD=1;// 0001intWRITE=1<<1;// 0010intpermission=READ|WRITE;booleancanRead=(permission&READ)!=0;

注意括号不能省。!=的优先级高于&,如果写成permission & READ != 0,会先算READ != 0,表达式就变成int & boolean,直接编译失败。

2. 按位或|

对应位只要有一个是1,结果位就是1

示例代码(Java):按位或

System.out.println(6|2);// 6

二进制过程(text):6 | 2 的逐位结果

6 -> 0110 2 -> 0010 | 0110 -> 6

常见用途是合并标志位

示例代码(Java):合并多个标志位

intREAD=1;// 0001intWRITE=1<<1;// 0010intEXEC=1<<2;// 0100intpermission=READ|WRITE;// 同时拥有 READ 和 WRITEpermission=permission|EXEC;

3. 按位异或^

对应位不同,结果位才是1

示例代码(Java):按位异或

System.out.println(5^9);// 12

二进制过程(text):5 ^ 9 的逐位结果

5 -> 0101 9 -> 1001 ^ 1100 -> 12

异或常见于“切换某一位”的场景:同一位异或1会翻转,异或0会保持不变。

示例代码(Java):用异或切换某一位

intflag=0b0101;intmask=0b0001;System.out.println(flag^mask);// 0b0100

4. 按位取反~

~会把每一位都翻转,0110

示例代码(Java):按位取反

System.out.println(~5);// -6

这个结果看起来反直觉,是因为 Java 的int使用 32 位二进制补码表示。对任意int x,都有:

规律说明(text):按位取反和负数的关系

~x == -x - 1

所以~5等于-6


五、移位运算:移动的是二进制位

移位运算只用于整数类型。

运算符名称高位或低位如何补
<<左移右侧补0
>>有符号右移左侧补符号位,正数补0,负数补1
>>>无符号右移左侧一律补0

左移常能看成乘以2的若干次方:

示例代码(Java):左移两位

System.out.println(5<<2);// 20

二进制过程(text):左移后的位变化

0000 0101 -> 0001 0100

右移要更谨慎。对非负数,>> n通常像除以2^n

示例代码(Java):非负数右移

System.out.println(15>>2);// 3

但对负数,不要简单等同于/。Java 的整数除法向0截断,而>>会保留符号位:

示例代码(Java):负数右移和整数除法的差异

System.out.println(-5/2);// -2System.out.println(-5>>1);// -3

>>>不保留符号位,左侧永远补0。因此负数无符号右移后,常会变成很大的正数:

示例代码(Java):有符号右移和无符号右移

System.out.println(-6>>3);// -1System.out.println(-6>>>3);// 536870911

初学阶段不要为了“看起来更底层”而用移位替代乘除。只有在处理掩码、哈希、编码、底层协议、集合源码这类明确依赖二进制布局的场景里,移位才是自然表达。


六、优先级:能加括号就别考验读者

逻辑运算和位运算的优先级大致可以记成:

优先级速查(text):逻辑与位运算从高到低

~、! // 一元运算,优先级高 <<、>>、>>> // 移位 <、<=、>、>= // 关系比较 ==、!= // 相等比较 & // 按位与 / 非短路逻辑与 ^ // 异或 | // 按位或 / 非短路逻辑或 && // 短路逻辑与 || // 短路逻辑或

这能解释一些表达式为什么能按预期运行:

示例代码(Java):不写括号时的表达式

booleanresult=x<y&&!z;

它等价于:

示例代码(Java):加括号后的等价表达式

booleanresult=(x<y)&&(!z);

但工程代码里,不建议把优先级当成炫技空间。尤其是位运算和比较混在一起时,括号会让语义清楚很多:

示例代码(Java):位运算和比较混用时加括号

booleanhasRead=(permission&READ)!=0;intcombined=READ|WRITE|EXEC;intthirdBit=value&(1<<2);

判断规则很简单:如果读者需要停下来回忆优先级表,括号就应该出现。


七、实战判断口诀

遇到&&||&|^~、移位运算时,可以按这几个问题判断:

  1. 是不是条件判断?
    • 是:优先使用&&||
  2. 右边是否可能有空指针、数组越界、方法副作用?
    • 是:更要使用短路逻辑。
  3. 操作数是不是整数,而且你关心的是二进制的某一位?
    • 是:使用位运算。
  4. 是不是要表示权限、状态、掩码、哈希扰动、编码解码?
    • 是:位运算可能合适。
  5. 只是想把两个 boolean 条件连起来?
    • 不要随手写单个&|

最容易记错的一句话是:

记忆口诀(text):一句话区分短路逻辑和位运算

短路逻辑看“要不要继续算”,位运算看“每一位怎么算”。

&&||解决的是控制流问题;&|^~<<>>>>>解决的是二进制表示问题。把这个边界立住,空指针保护、条件副作用、权限掩码和移位计算就不会混成一团。


需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询