必知必会:String、StringBuilder及StringBuffer区别?
问题背景
String、StringBuilder及StringBuffer这几个类在日常工作可谓无时无刻不在使用,他们之间的区别也是面试或者工作中的必备知识点。梳理一波,查漏补缺。
String特性梳理
(1)实现了序列化Serializable,Comparable以及CharSequence字符序列接口
String是Java字符串对象,底层是基于char字符数组,使用了final修饰类,表示最终类,不能被继承和修改,线程安全~
(2)每一次对String声明的对象的内容进行修改,得到的都是另外一个新的字符串常量对象,如果字符串常量池中已经存在该字符串常量对象,则不会再创建~
(3)JDK1.8,字符串常量拼接还被自动优化成了StringBuilder,例如:
Strings1=“first”;
Strings2=“second”;
Strings3=s1+s2;
//先javac编译java源文件得到Class,再经过javap-cClassName反编译查看汇编指令发现,发现s1+s2等价于
Strings4=newStringBuffer().append(s1).append(s2).toString();
如下图所示:
(4)String重写了Object类中的equals、hashCode方法,重写后equals方法比较了字符串的每一个字符,而重写hashCode方法则是由字符串的每一个字符计算出字符串的hashCode值~
(5)String常用API
2.StringBuilder特性梳理
(1)底层继承了AbstractStringBuilder,实现了Serializable、CharSequence接口
(2)底层基于char字符数组,可以修改操作对象,非线程安全
(3)StringBuilder初始化时默认字节数组初始化容量大小为16,当容量大于当前字节数组容量时会自动进行1倍扩容再加2,每次扩容都会开辟新空间,并且进行新老字符数组的复制:源码底层通过调用System的一个native本地方法arraycopy实现新老字符数组的复制,该native方法底层会直接操作内存,比一般的for循环遍历复制数组的效率要快很多;
(4)如果要操作拼接字符串,并且拼接的字符串很长,又没有给StringBuilder指定合适的初始化容量大小,可能会导致底层的字符数组进行多次扩容,多次申请内存空间来完成新老字符数组的复制,性能开销比较大;
(5)StringBuilder常用API
3.StringBuffer特性梳理
StringBuffer底层实现与StringBuffer最大的区别在于方法使用了synchronized关键字同步,因此是线程安全的,StringBuilder非线程安全!
总结:String、StringBuilder及StringBuffer的区别是什么?
(1)String使用final修饰,表示最终类,不可继承和修改,线程安全;
(2)而StringBuilder和StringBuffer都是可修改对象,StringBuffer使用synchronized同步修饰方法,线程安全,StringBuilder非线程安全;
(3)String在JDK1.8时字符串常量拼接被自动优化成了StringBuiler。