
源代码:public String(char value[], int offset, int count) { if (offset 0) { throw new StringIndexOutOfBoundsException(offset); } if (count 0) { if (count 0) { throw new StringIndexOutOfBoundsException(count); } if (offset value.length) { this.value .value; return; } } // Note: offset or count might be near -11. if (offset value.length - count) { throw new StringIndexOutOfBoundsException(offset count); } this.value Arrays.copyOfRange(value, offset, offsetcount); }先说结论这是 JDKString(char[] value, int offset, int count)原生构造器源码它的逻辑本身是对的、是防御性拷贝不能改业务语义但可以调整分支顺序、注释、拆分判断可读性大幅提升同时保留原有校验逻辑行为完全一致。原代码小问题count 0分支嵌套读起来绕offset value.length - count溢出风险offset count有可能 int 溢出源码注释也标注了这点Note: offset or count might be near -11.校验顺序不够直观先校验 offset再 count最后边界越界优化后版本行为 100% 对齐更好读/** * 从char数组指定区间构造字符串拷贝子数组 * param value 源字符数组 * param offset 起始下标 * param count 取多少个字符 */ public String(char value[], int offset, int count) { // 1. 先判空原生源码没有判数组null原生直接NPE这里可选加上看需求 if (value null) { throw new NullPointerException(); } // 2. 非法起始位置 if (offset 0) { throw new StringIndexOutOfBoundsException(offset: offset); } // 3. 长度不能负数 if (count 0) { throw new StringIndexOutOfBoundsException(count: count); } // 4. 取0个字符 - 空字符串 if (count 0) { // offset不能超过数组长度和原版逻辑保持一致 if (offset value.length) { throw new StringIndexOutOfBoundsException(offset); } this.value .value; return; } // 5. 边界校验防止 offset count 溢出不用 offset count 判断 // 等价于 offset count value.length但规避int溢出 if (offset value.length - count) { throw new StringIndexOutOfBoundsException(offset count); } // 拷贝区间 [offset, offset count) this.value Arrays.copyOfRange(value, offset, offset count); }改动点说明不改变原有逻辑把count 0拆成count 0和count 0去掉嵌套 if线性判断一眼看懂异常信息带上字段名调试友好原生只抛数字分不清是 offset 还是 count 错增加数组非空判断【可选】原生是不传 null 校验传 null 进value.length直接 NPE如果你想主动抛出 NPE、提前拦截可以加上保留offset value.length - count这个经典防溢出写法重点不要写成offset count value.length超大值会 int 溢出变负数校验失效注释拆分每个校验对应一个语义再精简一版适合学习看去掉多余文字public String(char value[], int offset, int count) { if (offset 0) { throw new StringIndexOutOfBoundsException(offset); } if (count 0) { throw new StringIndexOutOfBoundsException(count); } if (count 0) { if (offset value.length) { throw new StringIndexOutOfBoundsException(offset); } this.value .value; return; } // 防溢出边界检查 if (offset value.length - count) { throw new StringIndexOutOfBoundsException(offset count); } this.value Arrays.copyOfRange(value, offset, offset count); }和原版行为对比原版count 0先判断count0 时再判断 offset优化后顺序调整逻辑等价。 原版流程 count 0 → 抛异常 count0 → 判断 offset 是否合法赋值空串返回重点提醒【不要踩坑】❌ 错误写法很多人会这么改会有溢出 bug// 禁止这样写offsetcount 超出int上限会溢出变成负数判断失效 if (offset count value.length) { throw ... }✅ 源码原版方案offset value.length - count利用减法规避溢出这是核心巧思不能改掉。能不能再性能优化原生已经是Arrays.copyOfRange底层是System.arraycopy是 JVM 原生拷贝没有更快的纯 Java 写法这个构造器必须拷贝数组防御拷贝防止外部修改 char [] 影响 String不能直接引用原数组这是 String 不可变的底线省不掉