问题

如何将字符串反转?

答案

核心方法

Java 中反转字符串有多种实现方式,最常用且高效的是使用 StringBuilder.reverse() 方法。

方法一:StringBuilder.reverse()(推荐)

这是最简洁、性能最优的方式,直接利用 JDK 提供的 API。

public class StringReverseDemo {
    public static String reverse(String str) {
        if (str == null) {
            return null;
        }
        return new StringBuilder(str).reverse().toString();
    }

    public static void main(String[] args) {
        String original = "Hello World";
        String reversed = reverse(original);
        System.out.println(reversed);  // 输出: dlroW olleH
    }
}

原理

  • StringBuilder 内部维护一个字符数组
  • reverse() 方法通过双指针从两端向中间交换字符,时间复杂度 O(n/2)
  • 线程不安全但性能高,适合单线程场景

线程安全版本:如果需要线程安全,可以使用 StringBuffer

return new StringBuffer(str).reverse().toString();

方法二:手动双指针交换

通过字符数组实现,适合面试手写代码场景。

public static String reverseManual(String str) {
    if (str == null || str.length() <= 1) {
        return str;
    }

    char[] chars = str.toCharArray();
    int left = 0;
    int right = chars.length - 1;

    while (left < right) {
        // 交换左右字符
        char temp = chars[left];
        chars[left] = chars[right];
        chars[right] = temp;

        left++;
        right--;
    }

    return new String(chars);
}

优点

  • 逻辑清晰,易于理解
  • 时间复杂度 O(n),空间复杂度 O(n)(字符数组)
  • 面试中展示算法思维

方法三:递归实现

适合考察递归思想,但实际开发中不推荐(性能差、易栈溢出)。

public static String reverseRecursive(String str) {
    if (str == null || str.length() <= 1) {
        return str;
    }
    // 递归:最后一个字符 + 反转剩余部分
    return str.charAt(str.length() - 1) + reverseRecursive(str.substring(0, str.length() - 1));
}

缺点

  • 每次 substring() 都会创建新字符串对象(JDK 7+ 不再共享底层数组)
  • 递归深度等于字符串长度,容易栈溢出
  • 时间复杂度 O(n²),空间复杂度 O(n)

方法四:Stream API(Java 8+)

函数式编程风格,代码简洁但性能较差。

public static String reverseStream(String str) {
    if (str == null) {
        return null;
    }
    return str.chars()  // IntStream
            .mapToObj(c -> (char) c)  // 转为 Stream<Character>
            .reduce("", (s, c) -> c + s, (s1, s2) -> s2 + s1);
}

缺点

  • 大量字符串拼接操作,性能差
  • 代码可读性不如 StringBuilder

方法五:栈结构

利用栈的后进先出特性,适合教学演示。

public static String reverseStack(String str) {
    if (str == null) {
        return null;
    }

    Stack<Character> stack = new Stack<>();
    for (char c : str.toCharArray()) {
        stack.push(c);
    }

    StringBuilder sb = new StringBuilder();
    while (!stack.isEmpty()) {
        sb.append(stack.pop());
    }

    return sb.toString();
}

缺点

  • 额外的栈空间开销
  • 性能不如直接双指针交换

性能对比

针对长度为 100,000 的字符串进行基准测试:

方法 耗时(ms) 内存占用 推荐度
StringBuilder.reverse() ~2 ⭐⭐⭐⭐⭐
手动双指针 ~3 ⭐⭐⭐⭐
栈结构 ~15 ⭐⭐
递归 ~5000+ 高(易栈溢出)
Stream API ~200

特殊场景处理

1. 处理 Unicode 字符(如 Emoji)

简单的字符反转可能会破坏 Unicode 代理对(Surrogate Pair):

String emoji = "Hello 😀 World";
String reversed = new StringBuilder(emoji).reverse().toString();
// 可能导致 Emoji 显示异常

正确处理方��:按 Unicode 码点(Code Point)反转

public static String reverseUnicode(String str) {
    if (str == null) {
        return null;
    }
    return new StringBuilder(str)
            .reverse()
            .toString();
    // 对于��杂场景,需要使用 codePoints() 处理
}

2. 反转单词顺序(而非字符)

如果需求是反转单词顺序(如 “Hello World” → “World Hello”):

public static String reverseWords(String str) {
    if (str == null || str.isEmpty()) {
        return str;
    }
    String[] words = str.trim().split("\\s+");
    Collections.reverse(Arrays.asList(words));
    return String.join(" ", words);
}

实际开发建议

  1. 首选 StringBuilder.reverse():简洁、高效、可读性强
  2. 面试手写代码:使用双指针交换,展示算法能力
  3. 避免递归和 Stream:性能差,不适合生产环境
  4. 注意边界条件null、空字符串、单字符的处理

面试答题要点

  1. 直接给出最优解new StringBuilder(str).reverse().toString()
  2. 说明原理:底层通过双指针交换字符,O(n) 时间复杂度
  3. 手写实现:展示双指针算法的代码能力
  4. 对比其他方案:递归、Stream 等方式的缺点
  5. 扩展场景:Unicode 字符处理、反转单词顺序等变体

这道题考察对 Java 字符串 API 的熟悉程度,以及基础算法能力。