双指针反转数组时for循环边界应设为i < j,即i从0开始、j从length-1开始,每次交换后i++、j--,当i≥j时停止,确保不越界且每个元素仅交换一次。

Java里用双指针反转数组,for循环边界怎么设才不越界
双指针反转本质是交换 arr[i] 和 arr[j],关键在循环条件:必须让 i 成立,否则会重复交换甚至越界。常见错误是写成 <code>i 或 <code>i ,导致中间元素被换两次、或访问 <code>arr[arr.length] 报 ArrayIndexOutOfBoundsException。
- 正确写法:
for (int i = 0, j = arr.length - 1; i - 当数组长度为奇数(如5),循环在
i=2, j=2前停止,中间元素不动,符合预期 - 当长度为偶数(如4),最后一次交换是
i=1, j=2,之后i变成2、j变成1,i 不再成立,自然退出
原地反转 vs 创建新数组:为什么别轻易用 Arrays.copyOf
有人习惯先复制数组再反转,以为“更安全”,但实际多分配内存、触发GC,且掩盖了对原数组修改意图不明确的问题。除非业务明确要求保留原数组,否则原地反转更直接、也更符合多数场景(比如排序前预处理、字符串转字符数组后清洗)。
- 原地反转:只用
O(1)额外空间,时间O(n/2) - 复制+反转:额外
O(n)空间,且如果后续忘了用新数组,可能还在操作旧引用 - 若真需副本,显式写
char[] copy = Arrays.copyOf(arr, arr.length),比隐式复制更可控
int[] 和 String 反转不能套同一套逻辑
String 是不可变对象,没有“原地反转”这回事;而 int[] 是可变引用,可以直接改内容。想反转字符串,必须先转成 char[],反转完再用 new String(charArr) 构造新串。
- 错例:
str.charAt(0) = str.charAt(str.length()-1)—— 编译报错,charAt是 getter,没 setter - 对例:
char[] cs = str.toCharArray(); reverseInPlace(cs); return new String(cs); - 注意
toCharArray()返回的是新数组,不影响原String,这点和ArrayList.toArray()类似
泛型数组无法直接用双指针反转?T[] 的坑在哪
Java 泛型擦除后,T[] 无法像 int[] 那样直接 new 出运行时类型数组,所以通用反转方法要么限定为 Object[],要么靠反射或用户传入 Class<t></t>。日常开发中,90% 的情况其实不需要泛型版本——用 Collection 接口的 Collections.reverse() 更稳妥。
立即学习“Java免费学习笔记(深入)”;
- 对
List<String>:直接Collections.reverse(list),内部也是双指针,但封装好了 - 对原始类型数组(
int[],double[]):只能手写,因为Arrays工具类没提供原生反转方法 - 自己写泛型方法时,别写
public static <T> void reverse(T[] arr)—— 运行时会因类型擦除导致ClassCastException
双指针看着简单,但边界、可变性、类型擦除这三个地方一不留神就掉坑里。尤其当数组来自外部输入或嵌套在复杂对象里时,先确认它是可变的、长度非零、索引合法,比急着写交换逻辑更重要。


















