String
不可变特性,长度有限制,编译期,存储在常量池中,容量受到常量池最大上限限制,最大是65534;在运行期间,受限于int类型的长度,最大为4GB(参考理解:https://juejin.im/post/5d53653f5188257315539f9a
)。
- final类,内部使用char value[]保存值。
- 通过反射可以修改String的value字符数组值
private static void modifyString() {
String s = "Hello World";
try {
// 获取String类中的value字段
Field valueFieldOfString = String.class.getDeclaredField("value");
// 改变value属性的访问权限
valueFieldOfString.setAccessible(true);
// 获取s对象上的value属性的值
char[] value = (char[]) valueFieldOfString.get(s);
// 改变value所引用的数组中的第5个字符
value[5] = '_';
} catch (NoSuchFieldException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
- 线程安全
- 适用场景:不经常修改的情况下,如常量、少量字符串拼接等。
StringBuffer
实现原理,基于可修改的char数组,初始容量16,随着存储的元素越来越多,会尝试扩容,代码如下:
// 追加元素
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
// 计算当(前字符长度+追加字符的长度),并传入ensureCapacityInternal判断是否需要扩容
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
// 扩容之前先判断空间是否足够容纳新追加的元素
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
// 原来容量的2倍+2
int newCapacity = (value.length << 1) + 2;
// 取newCapacity与minCapacity二者的最大值
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
- 线程安全
- 适用场景:在频繁进行字符串的运算(拼接、替换、删除等),并且在多线程环境下,如解析xml,解析http参数,封装http参数等。
StringBuilder
可以理解为StringBuffer的线程非安全版本,特性与StringBuffer基本一致。
- 非线程安全
- 适用场景:运行在单线程环境下,如sql语句拼装,JSON封装等。