String和StringBuffer,StringBuilder
今天看了看String,又对比了StringBuffer和StringBuilder看了看,感觉里面的知识点还挺多的,而且String的使用我还不是很熟练,包括他们之间的区别,又是面试中经常问到的,这里我就来分享分享自己的想法吧。
String
看看源码的介绍
value数组
这个value是一个字符数组,可以知道是用来存储字符串的,字符串的底层就是字符数组char[],而且它被定义成了value,注意了,这里是value数组被定义成value,只是value这个对象不可以改变,但是value里面的值还是可以改变的,这里我在很多博客里面都说String对象的底层值不能改变,但具体也没说清楚。
举个例子:final int x[]={1,2,3};这个数组,只是标识x这个变量的指向不可以变,不代表x[1]的具体值不可以变。
而在value数组中,记录的就是我们创建的字符串,它又被定义了private,所以在创建String对象时,所以直接情况下,是改变不了String对象的值的,而平时的“+”操作符,实际是新建了一个对象。
还有就是注意这个类和value都是被final修饰的所以不能被继承访问
再来看看几个构造方法:
这里的构造方法都会给value赋值,从虚拟机的角度分析一下String对象创建时的流程:
以String s = new String(“ak”);为例
在内存里面是这样的,这里实际上是有两个对象的,也就是说,new String时,创建了两个对象
- 一就是s这个对象在堆中的实例
- 二时value数组在常量池中保存的真正的常量字符序列
以String s = “ak”;为例
这里s变量就直接指向了在字符串常量池中的实际“ak"序列
而字符串常量池中的Stirng数据可以说是共享的,也就是说,如果还有一个ak的序列,就不会重新创建,而会用原来的。但是如果要用别的序列,如果常量池中没有,就会要重新在常量池中创建一个新的。
String s = new String(“abc”)实际上是"abc"本身就是文字池中的一个对象, 在运行 new
String()时,把文字池即pool中的字符串"abc"复制到堆中,
并把这个对象的应用交给s,所以创建了两个String对象,一个在pool 中,一个在堆中。
也就始说在堆中的就是从常量池中复制过来的副本
在我的知乎文章Class文件结构 - Tmhoney的文章 - 知乎
https://zhuanlan.zhihu.com/p/44378698
中,已经详细介绍了在java虚拟机里面关于内存区域和类文件结构运行时常量结构的有关内容,可以去看看,有启发的话可以关注我一下,哈哈哈。
在比较字符串是”==“比较的是对象的地址,而equals是比较的实际值。
那么既然了解了String创建过程,我们还是来几个有意义的问答。
一
可以看到这里的s1和s2是指向常量池中的同一字符序列对象。
二
s4可以说是abc对象的副本,s5是直接指向了abc对象,s4和s5的地址值不同,但是字符内容相同。
三
java语言提供的字符串串联符号“+”以及其他对象转换为字符串的特殊支持
字符串串联时通过StringBuilder或者StringBuffer及其append方法实现的
字符串转换通过toString实现,该方法由Object类定义。 String s1 = “ab”; String s2 =
“abc”;
String s3 = s1 + “c”; 这个时候ab和abc已经在常量池中创建了两个对象 这个后s3在s1和c串联,底层先创建一个StringBuffer对象 将abc放在StringBuffer里面
调用StrigBuffer的toString方法转化成String对象,和StringBuffer那个对象不一样
StringBuffer
StringBuffer是一个线程安全,可修改的字符序列。
StringBuffer可以在任意一个时间点改变其中的序列。
从源码来看,它继承了AbstractStringBuilder类并实现了序列化接口。先来看看AbstractStringBuilder类
AbstractStringBuilder类
它是一个抽象类,成员变量包括了字符数组的保存值value,还有实际字符数目的大小count
length()是返回实际长度大小,capacity()是返回最大容量的理论大小
两个构造方法:
- 空构造方法什么也没做
- 而带参的则告诉了字符的最大容量大小。
StringBuffer类
这里StringBuffer的实现基本和AbstractStringBuilder差不多,只是另外定义了toStringCache的缓冲区变量,而且它的空构造使用了最小的字符空间16
而length和capacity方法还是和父类一样。
StringBuilder
StringBuilder和StringBuffer几乎一模一样,同样继承了AbstractStringBuilder,这里就不对源码进行分析了。只是StringBuffer比StringBuilder多了一个同步锁,能够保证StringBuffer在对StringBuffer的对象进行增删操作时,能够保证线程安全。
比较
性能比较
Stringbuilder>StringBuffer>String
因为StringBuilder减少了性能开销,但是线程不安全,而StringBuffer能够保证线程安全,但是效率不高,而String就更不用说了,根本就是不能够增加减少,每次都是重新创建一块区域来锁定目标字符串,对于多次创建字符串的情况下,应该减少String的使用,对于StringBuilder和StringBuffer只是重新创建了对象中的value字符数组,用来保存字符串,而String则需要重新在堆中创建整个对象来锁定字符串。
所以:
一般情况下:
对于单线程数据大的情况下,使用StringBuilder
对于多线程数据大的情况下,使用StringBuffer
其他一般清情况下斟酌使用String;