三者的引入:
在操作字符串的时候常用到String、StringBuilder、StringBuffer这三个类。那么为啥要设计出三个类,这三个类有什么区别,分别适用于哪些场景。下边我们来探索一下。
1.String类:
1)原理理解:
- 先直接下定义:String类是用来操作字符串的,它每次操作字符串时String对象都是不可变的(Sring类是用final关键字修饰的)。
- 在实际操作中,我们在写代码时给人的感觉貌似是直接在原字符串上进行修改的。其实并不是那样,原字符串是不会变化的,在修改时会创建出新的str对象,然后对原来的字符串进行修改(一般是在其基础上进行拼接),最后只是改变了String的指向罢了。
- 下边我通过一段代码加图片加说明的方式详细给大家解String是如何进行指向的。
- 展示完整过程:
2)执行效率和内存占有:
- 结论:String的
运行效率低,对内存耗费大
。 - 解释:正如上图所展示的,我们起初就像进行字符串的拼接,但是在实际操作过程中却开辟了三次内存空间。第一次:先在堆上开辟了“hello”字符串的内存。第二次:在堆上开辟了要拼接的“world”字符串的内存。第三次:开辟最终拼接好的“hello world”字符串的内存。可以看出一次简单的字符串拼接在用string操作的时候要开辟三次内存,最后再改变String对象的指向。不管是效率上还是内存占有上都是极大的浪费。
3)线程安全性:
- 结论:String在操作字符串时
线程是安全
的。 - 解释:要将线程安全就要牵扯到多线程,只有多个线程在并发并行执行的时候才会牵扯到线程安全问题。String类的源码是用final来修饰的,是不可变的。用发final修饰只能进行只读操作,在同一个时间只能进行单独一个操作,其他的操作不能进行就是线程安全的。
4)使用场景:
- 上边也说过了,String在进行字符串拼接时,不论是从执行效率还是内存占有上都没有优势。所以它只适用于没有循环的字符串拼接。
2.StringBuilder
1)StringBuilder引入:
- 上边我们研究了String的用法、优缺点、使用场景。String最大的特点就是它是不可变对象,不能在原对象上直接修改,而是创建新的String对象,最终改变String的指向。也正是基于这种特性,导致用String操作字符串的时候不论是效率上还是内存占有上都没有优点。因此我们引入StringBuilder。
2)操作原理:
- StringBuilder的引入就是为了解决String类不能直接修改的特性。因此它在操作字符串的时候最大的优点就是不用再堆上创建新的字符串对象,而是能直接调用内部方法,将字符串添加在缓冲区的末端。
3)执行效率和内存占有:
- 先直接下结论:StringBuilder相比于String来讲,它的
执行效率快,占据资源更少
。 - 解释:还是要从内存的开辟和时间的耗费来讲。StringBuilder在对字符串修改时能直接在原来基础上进行修改。这样一来,第一:不会在堆上创建新的String对象,对内存的消耗就会大大的减少。第二:在创建对象的时候都是要花费时间的,不用反复创建对象就不用花费时间。执行效率自然会提升。
4)线程安全性:
- 结论:StringBuilder在牵扯多线程编程的时候
线程不安全
。 - 解释:多线程编程的时候,往往是多行代码同时执行的。要保证线程安全就要在操作一个动作的时候保证其他的动作都处于挂起状态。简单讲就是在操作一个对象的时候不让其他的操作进行,等这个操作完成之后再让其他的动作进行。
- 形象理解:现在我们要举行一场晚会,在同一时刻所有准备节目的人员本来是能同时进行的。但是在实际过程中,节目组提前进行了排序,让选手有序进行。在一个选手进行唱歌的时候,其他的选手是不能上台展示他们的节目。这就好比在一个选手进行表演时(等价为一个线程的进行),其他所有的节目都不能进行,只能等待属于他们时刻的来临(等价为剩余的所有线程只能挂起)。在多线程中解决一个线程执行,其他线程等待的方法就是对正在进行的线程进行加锁操作(synchronized),保证其他的线程不能进行操作。多线程牵扯的知识点是很多的,本人将会有详细博客进行介绍,欢迎大家点击学习。
5)使用场景: - 基于StringBuilder能直接对字符串进行操作,首先就是它适用于反复的修改字符串操作。又基于它是线程不安全性,其适用于单线程的操作。
- 综合来讲
StringBuilder适用于单线程下反复对字符串的操作
。
3.StringBuferr
1)StringBuffer引入:
- 上边我们介绍了StringBuilder,它相比于String有好多优点。唯一的缺点就是只能进行单线性操作。在多线程时它是线程不安全的。因此引入了StringBuffer,其在StringBuilder的基础上解决了多线程的安全问题。
2)操作原理:
- 基本操作还是不用在堆上创建新的String对象,不用耗费时间,能直接进行字符串的操作。
具备StringBuilder的所有特性,原理也是一样的
。 - 唯一加强的是它用于多线程编程时能保证线程安全性。上边也讲过,StringBuilder没有对对象进行加锁处理,所以在操作一个线程时其他线程也可能操作共享变量。
StringBuffer进行了加锁处理(用synchronized修饰),保证了多线程的线程安全问题
。
3)执行效率和内存占有:
-
优于String,弱于StringBuilder
。 - 解释:和StringBuilder原理完全一样,不同的是进行了加锁处理。在加锁的时候就要进行申请锁,就要开辟内存空间,在操作完后在要释放锁,执行效率会降低。
4)使用场景:
- 综合来讲
StringBuffer适用于多线程下反复对字符串的操作
。
4.三者区别:
上边的模块已经详细讲解三者区别,下边用一张图来进行简单的总结: