直击面试:String、StringBuilder 和 StringBuffer 区别详解

String

在Java中字符串不是基本数据类型,而是对象。

Java提供了String类来创建和操作字符串。需要注意的是,String的值是不可变的,因为String对象被final修饰,是不可变的类对象。

从String的源码中可以看出,String类是一个final类,因此每次对String的操作都会生成新的String对象,这样不仅效率低下,而且大量浪费有限的内存空间。

String name="王者荣耀";
System.out.println(name);
name="吃鸡";
System.out.println(name);

很多人会认为,不是说字符串不可变吗?这个name的值怎么变化了呢?其实我们看似变化了,其实jvm内部是这样操作的。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BsvXPv11-1594178929049)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1594175231885.png)]

由此可见,name最终抛弃了“王者荣耀”这个值,最后指向了“吃鸡”,但是“王者荣耀”这个内容还在内存中,会随着下一次垃圾回收给回收掉。可是垃圾回收机制的时机是不可控的,这就造成了在此期间内存的浪费!

再看以下的代码:

String str1 = "hello world";
String str2 = new String("hello world");
String str3 = "hello world";
String str4 = new String("hello world");
         
 System.out.println(str1==str2);
 System.out.println(str1==str3);
 System.out.println(str2==str4);

输出结果:

false
true
false

在上述代码中,String str1 = “hello world”;和String str3 = “hello world”; 都在编译期间生成了 字面常量和符号引用,运行期间字面常量"hello world"被存储在运行时常量池(当然只保存了一份)。通过这种方式来将String对象跟引用绑定的话,JVM执行引擎会先在运行时常量池查找是否存在相同的字面常量,如果存在,则直接将引用指向已经存在的字面常量;否则在运行时常量池开辟一个空间来存储该字面常量,并将引用指向该字面常量。

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-C0un5eKI-1594178929052)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1594175433176.png)]

众所周知,通过new关键字来生成对象是在堆区进行的,而在堆区进行对象生成的过程是不会去检测该对象是否已经存在的。因此通过new来创建对象,创建出的一定是不同的对象,即使字符串的内容是相同的。

StringBuffer

简单的说, String 类型和 StringBuffer 类型的主要性能区别其实在于 String 是不可变的对象, 因此在每次对 String 类型进行改变的时候其实都等同于生成了一个新的 String 对象,然后将指针指向新的 String 对象,所以经常改变内容的字符串最好不要用 String ,因为每次生成对象都会对系统性能产生影响,特别当内存中无引用对象多了以后, JVM 的 GC 就会开始工作,那速度是一定会相当慢的。

而如果是使用 StringBuffer 类则结果就不一样了,每次结果都会对 StringBuffer 对象本身进行操作,而不是生成新的对象,再改变对象引用。所以在一般情况下我们推荐使用 StringBuffer ,特别是字符串对象经常改变的情况下。

​ StringBuffer是线程安全的,所有的方法都加锁,进行资源同步串行化处理,我们可以通过它的源码可以看出:

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-lCy3W5JH-1594178929056)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1594175638647.png)]

StringBuilder

​ StringBuilder是线程不安全的,StringBuilder 类表示一个可变的字符序列,我们知道,StringBuilder 是非线程安全的容器,一般适用于单线程场景中的字符串拼接操作。

StringBuilder与StringBuffer继承体系

[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-RAx621TP-1594178929058)(C:\Users\Administrator\AppData\Roaming\Typora\typora-user-images\1594175821334.png)]

应用场景

String

​ 在字符串内容不经常发生变化的业务场景优先使用String类例如:常量声明、少量的字符串拼接操作等

StringBuffer

​ 在频繁进行字符串的运算(如拼接、替换、删除等),并且运行在多线程环境下例如XML解析、HTTP参数解析与封装。

StringBuilder

​ 在频繁进行字符串的运算(如拼接、替换、删除等) ,并且运行在单线程环境下例如SQL语句拼装、JSON封装等。

StringBuilder

​ 在频繁进行字符串的运算(如拼接、替换、删除等) ,并且运行在单线程环境下例如SQL语句拼装、JSON封装等。

三者在执行速度方面的比较:StringBuilder>StringBuffer>String

你可能感兴趣的:(直击面试:String、StringBuilder 和 StringBuffer 区别详解)