String.getChars()核心用途是绕过字符串不可变性直接批量复制字符,不创建新对象、无GC压力;性能比substring().toCharArray()高2–3倍,尤其拷贝超64字符时;需确保srcBegin≤srcEnd≤length、dst非null、dstBegin+(srcEnd−srcBegin)≤dst.length。

String.getChars() 的核心用途和性能优势
String.getChars() 是 Java 中少数能绕过字符串不可变性、直接批量复制底层字符的原生方法。它不创建新 String 对象,也不触发 GC 压力,适合高频、大块字符搬运场景(比如解析器逐段提取 token、日志截断写入缓冲区)。它的效率比 substring().toCharArray() 高 2–3 倍,尤其在拷贝长度超过 64 字符时差异明显。
使用前提是:你已有目标字符数组,且明确知道源字符串中要拷贝的起始、结束位置。
参数含义与常见越界错误
getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) 四个参数必须同时满足约束,否则抛 IndexOutOfBoundsException:
-
srcBegin必须 ≥ 0,且不能大于字符串长度 -
srcEnd必须 ≥srcBegin,且不能大于字符串长度(注意:它是**结束索引,不包含**) -
dst数组不能为null -
dstBegin必须 ≥ 0,且dstBegin + (srcEnd - srcBegin)不能超过dst.length
典型错误写法:str.getChars(0, str.length(), buf, 0) 看似合理,但如果 buf 长度刚好等于 str.length() 就会越界——因为 dstBegin + length 要 ≤ dst.length,不是 。
立即学习“Java免费学习笔记(深入)”;
实际使用时的三类典型场景
根据目标数组生命周期,选择不同初始化方式:
- 复用固定缓冲区(推荐):提前分配足够大的
char[] buf = new char[1024],每次调用前确认长度,用str.getChars(i, j, buf, 0)写入头部 - 按需分配新数组:先算长度
int len = j - i,再char[] dst = new char[len],最后str.getChars(i, j, dst, 0) - 追加到已有数组末尾:若
dst已存部分数据,需传入当前有效长度作dstBegin,例如str.getChars(i, j, dst, pos),之后记得更新pos += (j - i)
注意:getChars() 不做编码转换,源字符串是 UTF-16 编码,拷贝结果也是 UTF-16;遇到代理对(surrogate pair)时,它按 char 单位拷贝,不会自动拆分或合并,这点和 codePointAt() 行为不同。
和 toCharArray() / getBytes() 的关键区别
别把 getChars() 当成语法糖。它和以下操作有本质差异:
-
str.toCharArray():总是新建数组,无法复用内存,返回副本 -
str.getBytes():涉及字符集编码转换(默认平台编码),可能丢数据或抛UnsupportedEncodingException -
str.charAt(i)单字符访问:每次调用都有边界检查开销,循环拷贝 N 个字符比getChars()慢一个数量级
真正需要高效拷贝时,getChars() 是 JDK 自带最轻量的选择。但它的“高效”只在你已持有目标数组的前提下成立——如果每次都要 new 一个新数组,那不如直接用 substring().toCharArray() 更清晰。
最容易被忽略的是:它不处理 null 字符('\u0000'),也不跳过 BOM 或控制字符,拷什么就是什么。如果你在解析二进制协议或混合编码文本,得自己额外校验内容合法性。


















