前言
private final char value[];
java 中 String 是不可变字符串,通过源码可以知晓原因。
字符串本质是通过字符数组存储的,并且声明为了 final,因此在第一次赋值后就不能进行更改了
注:char value[]
等同于char[] value
,这是 java 为了c++程序员设计的用来适应的语法
神奇的构造器
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
这个构造器是唯一一个不被public
修饰的,不能被我们在外部调用。同时,与其他构造器的最大区别是:这里直接修改value
的地址引用,而其他构造器都是将参数拷贝一份作为value
不加访问权限修饰符,默认为default,也就是同包下可以访问,借助IDEA总共可以找到9处引用
方便起见,直接分析String类中的引用
concat
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
concat 方法用来拼接字符串,并且返回拼接后的新字符串。
拼接的源码部分不难理解。
而最后生成字符串用的构造器正是上面介绍的这个构造器。
理解:
直接修改
value
引用的好处是,减少了重新拷贝一次的性能损失。不能随意使用这个构造器,原因是新生成的字符串如果和另一个变量共享一个地址,那么当这个变量的值修改时,字符串也会修改,如下例子:
static class Test { private final int[] value; public Test(int[] value) { this.value = value; } @Override public String toString() { return Arrays.toString(value); } } public static void main(String[] args) { int[] ints = new int[]{1, 2, 3}; Test test = new Test(ints); System.out.println(test); ints[0] = 0; System.out.println(test); }
运行效果如下:
[1, 2, 3] [0, 2, 3] Process finished with exit code 0
所以使用这个构造器的前提是:作为参数的那个变量,将不再使用(或者说即将被销毁)
concat 正好是要生成一个新的字符串,并且在具体的代码实现中使用了 char 数组,当方法结束时,这个数组已经被新字符串引用,而原本的变量
buf
也在方法结束时销毁了,符合了上述条件,也提高了性能
总结
String(char[] value, boolean share) {
// assert share : "unshared not supported";
this.value = value;
}
- 这个构造器被 JDK 用来提高字符串创建的性能
- 使用这个构造器有前提,否则会造成字符串可变
- 开发中无法调用这个构造器,但是可以学习这种设计