String 是 Java 语言非常基础和重要的类,它是典型的 Immutable 类,被声明成为 final class,所有属性也都是 final 的。也由于它的不可变性,类似拼接、裁剪字符串等动作,都会产生新的 String对象。
StringBuffer 是为解决上面提到拼接产生太多中间对象的问题而提供的一个类,我们可以用 append 或者add 方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer 本质是一个线程安全的可修改字符序列,它保证了线程安全,也随之带来了额外的性能开销,所以除非有线程安全的需要,不然还是推荐使用它的后继者,也就是 StringBuilder
StringBuilder 是 Java 1.5 中新增的,在能力上和 StringBuffer 没有本质区别,但是它去掉了线程安全的部分(去掉关键字synchronized),有效减小了开销,是绝大部分情况下进行字符串拼接的首选。
异同点对比(Java 1.8):
String类中使用字符数组保存字符串,因为有“final”修饰符,所以可以知道string对象是不可变的
private final char value[];
StringBuilder与StringBuffer都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串,这两种对象都是可变的
char[] value;
在我们创建StringBuilder和StringBuffer时,对应字符数组大小是有默认值的,构建时初始字符串长度加 16,如果初始没有传入字符串,初始值即为16
public StringBuffer() { super(16);}
执行速度:StringBuilder (非线程安全)> StringBuffer > String
String:适用于少量的字符串操作的情况
StringBuilder:适用于单线程下在字符缓冲区进行大量操作的情况
StringBuffer:适用多线程下在字符缓冲区进行大量操作的情况
String#intern()扩展
String 在 Java 6 以后提供了 intern()方法,目的是提示 JVM 把相应字符串缓存起来,以备重复使用。在我们创建字符串对象并调用 intern() 方法的时候,如果已经有缓存的字符串,就会返回缓存里的实例,否则将其缓存起来。一般来说,JVM 会将所有的类似“abc”这样的文本字符串,或者字符串常量之类缓存起来。
intern()方法在不同的JDK版本,有着较大的变化,这里不细讲,参考网上其他文章,了解即可intern深入分析
以下代码在JDK1.8环境执行结果
String a = new String("aa");
a.intern();
String b = "aa";
System.out.println(a == b); // false
String c = new String("1");
c = c.intern();
String d = "1";
System.out.println(c == d); // true
String s3 = new String("1") + new String("1"); // 此时生成了四个对象 常量池中的"1" + 2个堆中的"1" + s3指向的堆中的对象(注此时常量池不会生成"11")
s3.intern(); // jdk1.7之后,常量池不仅仅可以存储对象,还可以存储对象的引用,会直接将s3的地址存储在常量池
String s4 = "11"; // jdk1.7之后,常量池中的地址其实就是s3的地址
System.out.println(s3 == s4); // true
s3 = new String("2") + new String("2");
s4 = "22"; // 常量池中不存在22,所以会新开辟一个存储22对象的常量池地址
s3.intern(); // 常量池22的地址和s3的地址不同
System.out.println(s3 == s4); // false
网友评论