可以用异或交换两个整数变量,但仅限不同内存位置的int、long等整型;若a与b指向同一地址(如swap(x,x)或同一数组元素),结果全为0;浮点数、对象、字符串不适用,且无性能优势,可读性差,工程中应优先使用临时变量。

用 ^ 异或交换两个整数变量,前提是不能是同一个变量
直接说结论:可以用 a = a ^ b; b = a ^ b; a = a ^ b; 完成交换,但只适用于 int、long 等整型,且 a 和 b 必须指向不同内存位置。如果写成 swap(x, x) 这种调用,结果会变成 0 —— 因为异或相同值恒为 0。
常见错误现象:a 和 b 是同一引用(比如数组元素 arr[0] 和 arr[0])时,三步算完 a 变 0,b 也变 0;Java 没有指针,所以别幻想“绕过”这个限制。
- 必须确保
a != b(不是值相等,而是不指向同一存储单元) - 浮点数、对象、字符串完全不适用——
^不支持这些类型 - 编译器不会优化这三行成一条指令,实际性能未必比临时变量快,现代 JVM 对
int temp = a;这类操作早已做了寄存器级优化
为什么 a ^= b; b ^= a; a ^= b; 看似简洁却容易出错
表面看是把三步缩写成复合赋值,更“酷”,但隐患藏在中间状态里。第二步 b ^= a 中的 a 已经是新值(即原 a ^ b),而人脑容易默认它还是旧 a,导致逻辑推演错乱。
使用场景极少:基本只出现在算法题“禁止用额外空间”的约束下;工程代码里这么写,同事 review 时大概率会加 comment 问“这里确定没 bug?”
立即学习“Java免费学习笔记(深入)”;
- 第一步
a ^= b后,a已不是原始值,后续两步都依赖这个变化 - 如果某步被意外打断(比如加了日志或断点),中间态不可逆,调试成本高
- 字节码层面仍是三条
ixor指令,没省指令数,也没省栈深度
Java 中真正安全的无临时变量交换,其实只有一种情况
那就是交换数组中两个不同下标的元素,且用的是 int[] 这类基本类型数组:因为数组元素是独立内存槽,不存在“同一变量被反复读写覆盖”的问题。
示例:int[] arr = {1, 2}; arr[0] ^= arr[1]; arr[1] ^= arr[0]; arr[0] ^= arr[1]; —— 这能正确得到 {2, 1}。
- 对象数组(如
String[])不行:^不支持引用类型 - 包装类(如
Integer)也不行:自动拆箱后虽是int,但每次赋值都涉及新对象创建,原引用不变 - 如果数组越界或下标相同,运行时可能静默出错(比如下标一样就全变 0),不抛异常
别为了技巧牺牲可读性和边界安全
真实项目里,int temp = a; a = b; b = temp; 是最稳妥的选择。JVM 对这种模式识别极好,甚至可能把 temp 完全优化掉,不占栈空间。
位运算交换真正的复杂点不在实现,而在验证:你得确认调用方永远不会传入相同变量、不会用于非整型、不会在多线程里被并发修改——而这些,光看函数签名根本看不出来。










