4.StringBuffer/StringBuilder
4.1.概述
- String、StringBuilder、StringBuffer的区别
- String是Java中基础且重要的类,并且String也是Immutable类的典型实现,被声明为final class,除了hash这个属性其它属性都声明为final,因为它的不可变性,所以例如拼接字符串时候会产生很多无用的中间对象,如果频繁的进行这样的操作对性能有所影响。
- StringBuffer就是为了解决大量拼接字符串时产生很多中间对象问题而提供的一个类,提供append和add方法,可以将字符串添加到已有序列的末尾或指定位置,它的本质是一个线程安全的可修改的字符序列,把所有修改数据的方法都加上了synchronized。但是保证了线程安全是需要性能的代价的。
- 在很多情况下我们的字符串拼接操作不需要线程安全,这时候StringBuilder登场了,StringBuilder是JDK1.5发布的,它和StringBuffer本质上没什么区别,就是去掉了保证线程安全的那部分,减少了开销。StringBuffer和StringBuilder二者都继承了 AbstractStringBuilder ,底层都是利用可修改的char数组(JDK9以后是 byte数组)。所以如果我们有大量的字符串拼接 ,如果能预知大小的话最好在new StringBuffer或者StringBuilder的时候设置好capacity,避免多次扩容的开销。扩容要抛弃原有数组,还要进行数组拷贝创建新的数组。
- 总结
-
在字符串不经常发生变化的业务场景优先使用String(代码更清晰简洁)。如常量的声明,少量的字符串操作(拼接,删除等)。
-
在单线程情况下,如有大量的字符串操作情况,应该使用StringBuilder来操作字符串。尽量避免使用
String"+"
来拼接,避免产生大量无用的中间对象,耗费空间且执行效率低下(新建对象、回收对象花费大量时间)。如JSON
的封装等。 -
在多线程情况下,如有大量的字符串操作情况,应该使用StringBuffer。如
HTTP
参数解析和封装等。 -
String: 不可变的字符序列,
StringBuffer: 可变的字符序列,线程安全的,效率低,
StringBuilder: 可变的字符序列,线程不安全的,效率高。
-
StringBuffer和数组都可以看成是一个容器,StringBuffer可以自动扩容,数组长度是固定的,只能存储一个数据类型,StringBuffer可以把任意数据类型转换成字符来存储。
-
4.2.StringBuffer
- 概述:表示一个字符串缓冲区,它的对象是可变的。也是线程安全的可变字符序列。底层为字符数组。初始容量为16个字符,可以自动扩容。这个大小为16的初始空间不存储东西,作为预留空间;比如存储一个长度为13 个字符的字符串,容量就变为了29。
StringBuffer
和String
的区别StringBuffer
: 对象可变的字符序列,对象是变量,在堆上,作为参数传递就是引用数据类型传递(对象可以改变)- StringBuffer 和 StringBuilder 类的对象能够被多次的修改,并且不产生新的未使用对象
String
: 对象不可变的字符序列,对象是常量,在常量池,String 作为参数传递类似于基本数据类型作为参数传递 (对象的不可改变性)
4.3.常用方法
- 因为
StringBuffer/StringBuilder
本质上只是相差了一个多线程,而他们与String又十分相似,因此只写一部分。
4.3.1.构造方法
public StringBuffer()
:构造一个其中不带字符的字符串缓冲区,其初始容量为 16 个字符public StringBuffer(int capacity)
:构造一个不带字符,但具有指定初始容量的字符串缓冲区。public StringBuffer(String str)
:构造一个字符串缓冲区,并将其内容初始化为指定的字符串内容。
4.3.2.获取功能
public int capacity()
:返回当前容量。容量指可用于最新插入的字符的存储量,超过这一容量就需要再次进行分配。(初始值为16,并且可以自动扩容)public int length()
:返回长度(字符数)。
4.3.3.添加功能
public StringBuffer append(String str)
:可以把任意类型追加进StringBuffer,并且在append之后,StringBuffer对象本身也会变化,所以可以直接返回该对象,不需要新建对象来接收。和String不同。其中参数可以是很多种类型,详见数据手册。public StringBuffer insert(int offset,String str)
:可以把任意数据类型,指定偏移位置插入字符串
4.3.4.删除功能
public StringBuffer deleteCharAt(int index)
:删除指定索引的字符public StringBuffer delete(int start, int end)
:(包左不包右)删除一段字符
4.3.5替换功能
public StringBuffer replace(int start,int end,String str)
:包含左侧不包含右侧
4.3.6反转功能
public StringBuffer reverse()
:将该字符串倒序,改变其本身
4.3.7.截取功能
public String substring(int start)
: (注意这个返回值,原对象没有修改)public String substring(int start,int end)
4.4.String和StringBuffer作为参数的区别
//String作为参数传递类似于基本数据类型作为参数传递 (对象的不可改变性)。
//StringBuffer作为参数传递就是引用数据类型传递(对象可以改变)
public class StringBufferTest1 {
public static void main(String[] args) {
String s1 = "Hello";
String s2 = "world";
StringBuffer sb1 = new StringBuffer("Hello");
StringBuffer sb2 = new StringBuffer("world");
System.out.println("s1 = " + s1); // Hello
System.out.println("s2 = " + s2); // world
change(s1, s2);
System.out.println("s1 = " + s1); // Hello
System.out.println("s2 = " + s2); // world
System.out.println("‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐‐");
System.out.println("sb1 = " + sb1); // Hello
System.out.println("sb2 = " + sb2); // world
change(sb1, sb2);
System.out.println("sb1 = " + sb1); // Hello
System.out.println("sb2 = " + sb2); // worldworld
}
private static void change(StringBuffer sb1, StringBuffer sb2) {
sb1 = sb2;
sb2 = sb1.append(sb2);
}
private static void change(String s1, String s2) {
s1 = s2;
s2 = s1 + s2;
}
}
- 解释:main方法入栈。在栈上有2个引用变量s1,s2,同时在常量池有常量”Hello”和”world”,地址分别为0x001和0x002,在栈上还有2个引用变量sb1,sb2,同时在堆上有对象”Hello”和”world”,地址分别为0x010和0x020,change(String,String)方法入栈,方法里也有s1和s2变量,把s2的地址赋值给s1,s1地址变为0x002,s2=s1+s2属于字符串拼接,因此在堆中拼接一个”Hello,World”的对象,地址为0x003,并把地址值赋给s2 。但是main方法中的s1和s2地址没有发生变化,因此还是输出’‘Hello’‘以及’‘World’’change(StringBuffer)方法入栈,方法里也有sb1和sb2变量,地址为0x010和0x020,指向堆中的对象。然后把sb2赋值给sb1,sb1=0x020,指向”World”。sb1.append(sb2)等于worldworld。但是main方法中的sb1和sb2没有发生改变,所以还是指向原来的对象,输出”Hello”和”WorldWorld”。
版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
文章由极客之音整理,本文链接:https://www.bmabk.com/index.php/post/181086.html