1. String 类(字符串)的特点
- 字符串是常量,创建后不可改变;
- 字符串字面值存储在字符串池中,可以共享;
JVM内存管理中:栈、堆、方法区(方法区中有常量池,常量池中嵌套了字符串池)
先来看个简单的案例:
public class TestString {
public static void main(String[] args) {
String str = "Hello";
for (int i = 0; i < 100; i++) {
str += i;
}
System.out.println(str);
}
}
这种追加字符串的情况,在理论上会产生若干的中间变量,浪费内存。
而实际结果却不然,如何说明和证明呢?
2. Java反编译分析字符串追加时的优化
找到编译生成的.class文件,然后对应目录下,执行反编译命令:
javap -v TestString > TestString.bytecode
命令说明:
-v 是输出附加信息
TestString 是类名即文件名
> 重定向符号,将命令的输出全部重定向到文件中保存
.bytecode 后缀名无所谓,使用.txt也一样,我们只需要查看内容
查看和分析反编译信息:
进而得出结论:
str += i; // 被JVM自动优化了,实际不会产生中间变量
JDK的实现方式是什么?
- 自动创建了StringBuilder对象
- 调用StringBuilder的构造方法
- 调用StringBuilder的append(int i)方法
- 调用StringBuilder的toString()方法转回为String类型,并赋值给str
StringBuilder直接在str指向的对象空间里扩展空间追加。
3. StringBuilder类介绍
参考JDK1.8 API 文档。
public final class StringBuilder
extends Object
implements Serializable, CharSequence
一个可变的字符序列。此类提供与StringBuffer的API,但不保证同步。 此类设计用作简易替换为StringBuffer在正在使用由单个线程字符串缓冲区的地方(如通常是这种情况)。 在可能的情况下,建议使用这个类别优先于StringBuffer ,因为它在大多数实现中将更快。
StringBuilder的主要append和insert方法,它们是重载的,以便接受任何类型的数据。 每个都有效地将给定的数据转换为字符串,然后将该字符串的字符附加或插入字符串构建器。 append方法始终在构建器的末尾添加这些字符; insert方法将insert添加到指定点。
一般情况下,如果某人是指的一个实例StringBuilder ,则sb.append(x)等同于sb.insert(sb.length(), x) 。
每个字符串构建器都有一个容量。 只要字符串构建器中包含的字符序列的长度不超过容量,则不需要分配新的内部缓冲区。 如果内部缓冲区溢出,则会自动变大。
StringBuilder不能安全使用多线程,因为异步问题无法保证数据安全访问。如果需要同步,那么建议使用StringBuffer。
除非另有说明,否则将null参数传递给null中的构造函数或方法将导致抛出NullPointerException 。