
Java里不能直接用指针交换两个基本类型变量
Java没有指针,也没有类似C语言的 & 取地址和 * 解引用操作,所以写 swap(a, b) 期望原地交换两个 int 变量是无效的——函数内交换的只是副本。这是绝大多数初学者踩的第一个坑:以为传参能改外面的值。
常见错误现象:a 和 b 调用完还是老样子;IDE甚至可能提示“方法没有副作用”,但你没意识到问题出在语言模型上。
- 基本类型(
int、double等)永远按值传递,函数内修改不影响调用方 - 包装类(
Integer、Double)也是按值传递——传的是对象引用的副本,不是引用本身 - 只有数组元素或对象字段能被间接修改,比如
arr[0]或obj.value
用数组或容器包装变量来实现“伪交换”
如果真需要交换逻辑(比如排序算法中),最轻量的做法是把变量塞进长度为2的数组里,靠数组可变性达成效果。这不是“优雅”,而是务实妥协。
使用场景:手写冒泡、选择排序,或调试时临时交换两个值观察行为。
立即学习“Java免费学习笔记(深入)”;
-
int[] pair = {a, b};→pair[0] = pair[1]; pair[1] = temp; - 用
AtomicInteger也能做,但过度——除非在多线程里且已引入java.util.concurrent.atomic - 别用
ArrayList<Integer>:自动装箱/拆箱 + 对象开销,纯属画蛇添足
示例:
int a = 5, b = 8;<br>int[] box = {a, b};<br>int temp = box[0];<br>box[0] = box[1];<br>box[1] = temp;<br>a = box[0]; b = box[1]; // 此时 a==8, b==5
对象字段交换比“交换变量”更贴近真实需求
实际代码里,几乎没人真想交换两个孤立的局部变量。你要交换的,通常是某个对象的状态,比如 user.firstName 和 user.lastName,或者数组中的两个位置。
这时候直接操作字段或索引,比绕一圈包装变量干净得多。
- 交换数组元素:
int[] arr = {...}; int temp = arr[i]; arr[i] = arr[j]; arr[j] = temp; - 交换对象字段:直接写
temp = obj.x; obj.x = obj.y; obj.y = temp;,不封装函数 - 避免写通用
swap(T a, T b)方法——Java泛型擦除后无法处理基本类型,又没法约束字段访问,意义不大
别碰反射或Unsafe去“强行交换”
有人搜到用 Field.setAccessible(true) 修改私有字段,或用 Unsafe.putInt 直接写内存地址——这些在JDK 9+基本失效,且破坏模块化、触发安全限制、让代码不可维护。
性能/兼容性影响:反射慢一个数量级;Unsafe 在不同JVM版本行为不一致,GraalVM等原生镜像根本不用它。
- JDK 12+ 默认禁止反射访问非开放模块的字段
-
Unsafe不是公开API,连Javadoc都不保证,升级JDK就可能崩 - 就算成功,也掩盖了设计问题:为什么需要交换两个本不该独立存在的变量?
事情说清了就结束:Java里没有交换变量这回事,只有交换位置、交换字段、交换容器里的内容。盯着“变量”本身打转,往往说明还没想清楚数据到底属于谁、生命周期在哪。










