JAVA基础:String、StringBuffer、StringBuilder全面分析

三者就使用层面的简略分析:
三者就字符串拼接方面运行速度快慢为:StringBuilder > StringBuffer > String。 
线程安全上:StringBuilder是线程不安全的,而StringBuffer是线程安全的,原因StringBuffer中使用了很多synchronized。
小结:(1)如果要操作少量的数据用 String;
(2)多线程操作字符串缓冲区下操作大量数据 StringBuffer;
(3)单线程操作字符串缓冲区下操作大量数据 StringBuilder;

三者的主要继承关系:都实现了Serializable(略)

三者字符串可变与不可变问题:
String是不可变长度的字符串,
StringBuffer是可变长度的字符串,
StringBuilder是效率更高的可变长度的字符串。

从源码中分析(略):
String:

String 中用了final来修饰value为不可变的。
先提出一个问题:string是final修饰的是不可变的,为何利用"+"后,返回了一个拼接后改变的字符串?前后不矛盾?详细请看下个 string的"+"问题  的分析。
StringBuffer:

分析:可以看见只要创建StringBuffer()对象,至少也分配了16个字符的空间。 

这里的value没有被final修饰

*String创建对象问题:

		//例题四
		String s5="abc";        //创建1个对象abc
		String s6="abc"+"de";   //创建2个对象de,abcde
		String s7="abcde";      //未创建对象
		System.out.println(s6==s7);//true
		
	//面试(重点重点):
		//例题五
		//题目:程序依次执行分别创建了多少新对象?
		String a1=new String("我");
		String a2="我";
		String a3=new String("我");
/*		答案:从上到下依次执行程序,
		     a1创建2个对象
		     a2未创建对象
		     a3创建1个对象
		解析:
		    a1:常量池中创建了"我",堆中创建了一个String类的对象。
		    (说明:new创建String对象时,需要传入"我"这个字符串,因此会首先去常量池中寻找"我",因为没有,所以就在常量池中创建了"我"这个字符串及对象)
		    a2 :直接引用a1在常量池中创建的"我"。
		    a3:同理,只创建了一个新的String类对象*/

*(重点)String典型的“+”问题:


  public static void main(String[] args)  {
	        String a = "hello2";
	        final String b = "hello";	        
	        String c = b + 2;	       
	        String f ="hello"+"2";
	        
	        String d = "hello";
	        String e = d + 2;
	        String g = d + 2;
	        //第一类问题:直接字符串拼接
	        System.out.println(a == c);// true 
	        System.out.println(a == f);// true 

	        //第二类问题:字符串变量+字符串
	        System.out.println(a == e);// false
	        System.out.println(e == g);// false
       
 
    }

 解析:
a==c : 由于final的修饰,b在编译期间就已经是一个确定值!由于各变量都为确定值,因此b+2="hello"+"2"="hello2",注意这是在编译时完成的(自动对代码的优化),拼接好后由于常量池中已经存在"hello2"的字符串,因此不会创建新的字符串,最后c即指向"hello2",实际直接指向的是常量池的"hello2",a最早也指向常量池的"hello2",因此 a、c指向同一个地址。
a==f:同理。

a==e:编译期间不知道d是什么,会自动创建了一个StringBuffer对象,依次append(d).append("2"),最后toString给e。a指向的是常量池,而e指向的是对象及是指向的堆!因此a、e指向的是两个地方,肯定不可能相等。
超级经典的例子让你明白横线上的问题:

String s=null;
s=s+"abc";
System.out.println(s);//nullabc

e==g:如果你看明白了a==e那这里就太简单了,因为创建了两个不同的StringBuffer对象,e、g分别指向这两个对象!因此地址肯定不等!

*StringBuffer扩容问题:

StringBuffer初始化及扩容机制

1.StringBuffer()的初始容量可以容纳16个字符,当该对象的实体存放的字符的长度大于16时,实体容量就自动增加。StringBuffer对象可以通过length()方法获取实体中存放的字符序列长度,通过capacity()方法来获取当前实体的实际容量。

2.StringBuffer(int size)可以指定分配给该对象的实体的初始容量参数为参数size指定的字符个数。当该对象的实体存放的字符序列的长度大于size个字符时,实体的容量就自动的增加。以便存放所增加的字符。

3.StringBuffer(String s)可以指定给对象的实体的初始容量为参数字符串s的长度额外再加16个字符。当该对象的实体存放的字符序列长度大于size个字符时,实体的容量自动的增加,以便存放所增加的字符。

扩容算法:
使用append()方法在字符串后面追加东西的时候,如果长度超过了该字符串存储空间大小了就需要进行扩容:构建新的存储空间更大的字符串,将久的复制过去;

再进行字符串append添加的时候,会先计算添加后字符串大小,传入一个方法:ensureCapacityInternal 这个方法进行是否扩容的判断,需要扩容就调用expandCapacity方法进行扩容

尝试将新容量扩为大小变成2倍+2   if 判断一下 容量如果不够,直接扩充到需要的容量大小。

猜你喜欢

转载自blog.csdn.net/qq_41877184/article/details/103114203
今日推荐