杰瑞科技汇

char数组与String在Java中如何转换?

核心概念:char[] vs. String

可以把它们想象成两种不同的“容器”,用来存放字符。

char数组与String在Java中如何转换?-图1
(图片来源网络,侵删)

char[] - 字符数组

  • 本质:它是一个基本数据类型数组,每个元素都是一个char类型。
  • 特点
    • 可变:创建后,你可以随时修改数组中的任何一个字符,增加或删除元素(需要创建新数组)。
    • 高效:因为它是一个简单的数组,在需要频繁修改字符内容时,性能通常比String更好。
    • 没有高级方法:它本身不提供像substring(), indexOf(), split()等专门处理字符串的便捷方法,你需要自己实现这些逻辑,或者借助String类。
    • 非对象char是基本数据类型,char[]是一个对象,但它的设计初衷是作为一个原始的、可变的字符序列容器。

示例:

// 1. 声明和初始化
char[] chars = new char[5]; // 创建一个长度为5的字符数组,默认值为'\u0000'
chars[0] = 'H';
chars[1] = 'e';
chars[2] = 'l';
chars[3] = 'l';
chars[4] = 'o';
// 2. 可变性
chars[0] = 'J'; // 完全合法,修改了第一个字符
System.out.println(chars); // 输出: Jello

String - 字符串

  • 本质:它是一个不可变的、最终final类,它内部使用一个private final char[] value来存储字符。
  • 特点
    • 不可变:一旦String对象被创建,其内部的字符序列就不能被改变,任何看似修改String的操作(如replace, substring)实际上都是创建了一个新的String对象,而原始对象保持不变。
    • 丰富的方法String类提供了大量非常方便的方法来操作字符串,如连接、查找、分割、替换、大小写转换等。
    • 线程安全:因为不可变,所以它在多线程环境下是安全的,无需额外的同步措施。
    • 性能优化:Java虚拟机会对String进行特殊优化,例如字符串常量池,可以重用相同的字符串字面量,节省内存。

示例:

// 1. 声明和初始化
String str = "Hello";
// 2. 不可变性
// str = str.replace('H', 'J'); // 这行代码看起来是修改,但实际上是创建了一个新的字符串 "Jello" 并让str引用它
System.out.println(str); // 输出仍然是 Hello,因为str没有指向新的对象
// 正确的“修改”方式
str = str.replace('H', 'J'); // 必须将新对象赋值回给str变量
System.out.println(str); // 输出: Jello

转换方法

这是实际开发中最常用的部分。

char[]String

有三种主要方式,它们有细微但重要的区别。

char数组与String在Java中如何转换?-图2
(图片来源网络,侵删)

直接构造函数(最常用)

char[] chars = {'J', 'a', 'v', 'a'};
String str1 = new String(chars); // 使用char数组创建一个新的String对象
System.out.println(str1); // 输出: Java

String.valueOf(char[])

这是官方推荐的方式,因为它能处理null值,避免NullPointerException

char[] chars = {'J', 'a', 'v', 'a'};
String str2 = String.valueOf(chars); // 静态方法
System.out.println(str2); // 输出: Java
char[] nullArray = null;
// String str3 = new String(nullArray); // 抛出 NullPointerException
String str4 = String.valueOf(nullArray); // 返回字符串 "null",不会报错
System.out.println(str4); // 输出: null

String.copyValueOf(char[])

功能和构造函数new String(char[])几乎完全一样,也是静态方法。

char[] chars = {'J', 'a', 'v', 'a'};
String str5 = String.copyValueOf(chars);
System.out.println(str5); // 输出: Java

日常使用,new String(chars)String.valueOf(chars)都是不错的选择,如果需要健壮性(处理null),首选String.valueOf

Stringchar[]

只有一种主要方式,即调用String对象的toCharArray()方法。

char数组与String在Java中如何转换?-图3
(图片来源网络,侵删)
String str = "Hello World";
char[] chars = str.toCharArray(); // 将字符串转换为字符数组
// 遍历输出数组
for (char c : chars) {
    System.out.print(c + " "); // 输出: H e l l o   W o r l d
}

何时使用 char[],何时使用 String

这是一个关键的设计决策问题。

特性 char[] String
可变性 可变 不可变
性能 频繁修改时性能更高 查询、拼接等操作有JVM优化,且线程安全
功能 功能简单,无内置方法 功能极其丰富,是Java API的核心
安全性 不安全(如密码处理) 安全(不可变,防止意外修改)
主要用途 密码存储(可以清空内存)
需要频繁修改字符序列的场景(如图像处理、游戏开发)
与C/C++等本地代码交互
几乎所有文本处理场景
作为方法参数或返回值
当数据不需要被修改时

经典场景:为什么存储密码要用 char[] 而不是 String

这是一个面试高频题,完美体现了两者的区别。

使用 String 存储密码的问题:

  1. 不可变性String对象一旦创建就无法修改,当你处理完密码(验证用户输入)后,你无法清空内存中的String,它会一直留在内存中,直到被垃圾回收,在这期间,任何能访问内存的恶意程序(如内存转储工具)都可能窃取到密码。
  2. 易被缓存String会被字符串常量池缓存,增加了密码在内存中长期存在的风险。
  3. 在日志中意外打印:如果日志级别配置不当,密码可能会被意外打印到日志文件中,造成严重的安全泄露。

使用 char[] 存储密码的优势:

  1. 可变性char[]是可变的,一旦验证完成,你可以立即将数组中的所有元素置为'\u0000'(空字符),从而从内存中安全地清除密码。
  2. 不被日志记录:大多数日志框架(如Log4j, SLF4J)默认不会将char[]打印到日志中,这提供了额外的安全层。

示例代码:

import java.util.Arrays;
public class PasswordTest {
    public static void main(String[] args) {
        // --- 使用 String (不安全) ---
        String passwordString = "mySecretPassword123";
        // ... 验证密码 ...
        System.out.println("密码已验证,但String仍在内存中: " + passwordString); // 可能被日志记录
        // passwordString = null; // 只能断开引用,但数据可能仍在内存中等待GC
        System.out.println("--------------------");
        // --- 使用 char[] (更安全) ---
        char[] passwordChars = "mySecretPassword123".toCharArray();
        // ... 验证密码 ...
        System.out.println("密码已验证,准备清空char[]...");
        // 安全地清空密码
        Arrays.fill(passwordChars, '\u0000');
        System.out.println("清空后的char[]: " + Arrays.toString(passwordChars)); // 输出: [\u0000, \u0000, ...]
    }
}
方面 char[] String
核心 可变的字符容器 不可变的字符对象
选择 当你需要修改,尤其是在安全敏感的场景(如密码)时。 当你需要存储、处理、传递文本,且内容不需要改变时,这是绝大多数情况下的默认选择。

char[] 是用来“建造”和“修改”文本的砖块和工具,而 String 是用来“展示”和“使用”成品的精美画框。 在Java中,除非有特殊需求(如性能优化或安全考虑),否则你应该优先使用String

分享:
扫描分享到社交APP
上一篇
下一篇