提到String、StringBuffer和StringBuilder大家都不陌生,在javase或多或少有过接触,但你真正了解它们之间的联系与区别吗?在面试中也是会被常常问道的题目,如果你有疑惑,或许我整理的文章可以帮到你!
目录
StirngBuffer与StringBuilder的扩容机制
String和StringBuffer、StringBuilder三者的比较
String和StringBuffer、StringBuilder三者的选择
String类的特点
public final class String
implements java.io.Serializable, Comparable<String>, CharSequence
{...}
-
String类是一个final修饰的类,不能被继承
-
String实现了java.io.Serializable接口:表示字符串是支持序列化的
-
String实现了Comparable接口:表示String可以比较大小
-
String类存储数据使用的是一个final修饰的char数组,char数组的地址值不能改变。(jdk8及以下版本使用的底层是使用char数组,jdk9及以上底层是使用的byte数组)
-
String存储的是不可变字符序列(字符串常量),值是不能改变的。每次修改都会在常量池中创建一个新的字符串,效率较低。
-
通过字面量的方式(区别于new)给一个字符串赋值,此时的字符串值声明在字符串常量池中
-
字符串常量池中是不会存储相同内容的字符串
-
@Test public void testSting(){ //字面方式建立字符串,使用intern()方法可以返回对象字符串在常量池中的地址 String a="abc"; String b="abc"; System.out.println(a.intern()==b.intern()); //因为new方式建立对象,即是内容是相同的,他们的对象地址也是不同 String a1 = new String("abc"); String b1 = new String("abc"); System.out.println(a1==b1); }
运行结果:
-
true false
StringBuffer类、StringBuilder类的特点
public final class StringBuffer
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuffer>, CharSequence
{...}
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, Comparable<StringBuilder>, CharSequence
{
-
StringBuffer类、StringBuilder类也都实现了java.io.Serializable接口和Comparable接口,与上String相同
-
StringBuffer类、StringBuilder类都继承AbstractStringBuilder类
-
StringBuffer类、StringBuilder类都被final修饰,所以其不能被其他类继承的
-
StringBuffer类、StringBuilder类底层都是使用char数组存储字符串(jdk8及以下版本使用的底层是使用char数组,jdk9及以上底层是使用的byte数组)
-
StringBuffer类、StringBuilder类存放的字符串是可以改变的,初始容量是16,当我们追加修改,或者是在构造时的容量超过了16,底层会自动扩容。
-
StringBuffer类、StringBuilder类继承了AbstractStringBuilder类,当然也重写了其中的方法,但其实这些重写的方法有的还是会调用 AbstractStringBuilder 中的公共方法。利用super.父类方法去调用父类的方法。
-
StringBuilder类线程不安全,区别于StringBuffer的线程安全
-
StringBuilder效率比StringBuffer快,单线程的时候优先考虑使用
StirngBuffer与StringBuilder的扩容机制
StringBuffer类、StringBuilder类存放的字符串是可以改变的,初始容量是16,当我们追加修改,或者是在构造时的容量超过了16,底层会自动扩容。
有参和无参扩容方法都一样的。都是从当前容量开始扩容
当我们追加长度超过当前数组容量的时候,默认情况下,会按照 当前容量的2倍多2进行 扩容
当进行默认情况的扩容任然不够时,这时候会将容量直接扩容到与所添加的字符串长度相等的长度。
扩容原理是:底层会新建一个扩容后长度的新数组,并把原有数组中的元素复制到新的数组中返回。
@Test
public void testStringBuffer(){
StringBuffer s = new StringBuffer();
// 使用 capacity()方法可以查看当前容量、length()方法查看当前字符个数
System.out.println("capacity:"+s.capacity()+"------- length:"+s.length());
//追加长度为17时,超过了默认长度16,会按默认情况自动扩容
s.append("12345678901234567");
System.out.println("capacity:"+s.capacity()+"------- length:"+s.length());
//追加长度超过当前容量的2倍多2个容量时,默认情况扩容也剩不下,会直接扩容到字符串的长度
s.append("sssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssssss");
System.out.println("capacity:"+s.capacity()+"------- length:"+s.length());
}
运行结果:
capacity:16------- length:0
capacity:34------- length:17
capacity:90------- length:90
String和StringBuffer、StringBuilder三者区别
相同点:
-
三者都是用来存储字符串。
不同点:
-
String保存的是字符串常量,值不能被更改。每次更新字符串,实际上是更新了地址值
-
String使用的是final修饰的char型数组保存数据,代表不可变的字符序列。简称:不可变性
-
String的效率低,但是复用率高。
-
StringBuffer保存的是字符串变量,值可以更改,
-
底层数组的初始容量是16,修改值时不会每次都更新地址,增加和删除字符串的内容时,效率较高。
-
StringBuffer是线程安全的,但效率低
-
StringBuilder虽然线程不安全的,但效率最高。
三者在运行时的效率:StringBuilder(单线程) > StringBuffer(线程安全) > String(不可变的字符序列)
String和StringBuffer、StringBuilder三者如何选择
-
如果字符串存在大量的修改和删除操作,使用StringBuffer或StringBuilder
-
如果字符串很少修改,同时被多多个对象引用,比如配置信息等,使用String
-
如果在单线程的情况中,使用效率高的StringBuilder
-
如果是多线程的清空中,使用线程安全的StringBuffer
结语
如果您在阅读文章发现了错误,还望您能及时联系我予以斧正,在这里先拜谢了!!!