String,StringBuffer,StringBuilder的区别
文章目录
String
String是不可变的
1)String是只读字符串,String引用的字符串内容不可修改
String str="hel";
String str2="hel";
str="hello";
str和str2指向的地址是一样的所有(str==str2)为true
当我们改变String的值时,我们只是改变了String所指向的地址,实际上在字符串常量池会创建一个新的常量对象"hello",str会由“hel”指向“hello”。
String的两种实例化
1:字面量方式实例化
创建一个对象
只创建一个常量对象在常量池
String str1 = "hello";
2:new String()构造器实例化
创建两个对象
创建一个字符串对象在堆中,在创建一个常量对象在常量池,str2指向字符串对象,字符串对象指向常量对象
String str2 = new String("hello");
str1==str2
为false
“hello”字符串储存在常量池
str1指向常量池的“hello”常量对象
str2指向堆中的字符串对象
String的拼接
String s1="Hello";
String s2="World";
String s3="HelloWorld";
String s4="Hello"+"World";
String s5=s1+"World";
System.out.println(s3==s4); //true
System.out.println(s3==s5); //false
s3 ==s4为true是因为常量池中就有“HelloWorld”,s4拼接后就直接指向“HelloWorld”,所以为true
s3 ==s5 为false :
当变量与字面量或变量与变量进行拼接时,会在堆中创建一个StringBuilde对象,然后使用StringBuilder的append()方法将变量与字面量或变量与变量进行拼接,最后调用toString()方法转成String对象(字符串对象)。所以s5指向的是堆内存中String对象的地址值
StringBuffer和StringBuilder
底层用一个数组来存储字符串的值,数组的默认值是16(调无参构造时,空的StringBuffer对象数组长度为16)。
当我们调有参构造时,数组长度不是16,而是“当前对象的值的长度 + 16”,所以创建完对象后,有16个字符的空间可以对其值进行修改。如果修改的值超过这个范围,会先检查StringBuffer对象的原char数组的容量能不能装下新的字符串,如果装不下则会对 char 数组进行扩容。
StringBuffer扩容:
创建一个新的char数组,将现有容量扩大一倍再加上2,如果还是不够大,则直接等于需要的容量大小。扩容完成之后,将原数组的内容复制到新数组,最后将指针指向新的 char 数组。
面试题:String、StringBuffer和StringBuilder的异同?
相同点:底层都是通过char数组实现的
不同点:
String对象一旦创建,其值是不能修改的,如果要修改,会重新开辟内存空间来存储修改之后的对象;而StringBuffer和StringBuilder对象的值是可以被修改的;
StringBuffer几乎所有的方法都使用synchronized实现了同步,线程比较安全,在多线程系统中可以保证数据同步,但是效率比较低;而StringBuilder 没有实现同步,线程不安全,在多线程系统中不能使用 StringBuilder,但是效率比较高。
如果我们在实际开发过程中需要对字符串进行频繁的修改,不要使用String,否则会造成内存空间的浪费;当需要考虑线程安全的场景下使用 StringBuffer,如果不需要考虑线程安全,追求效率的场景下可以使用 StringBuilder。