美文网首页
String、StringBuffer、StringBuilde

String、StringBuffer、StringBuilde

作者: weifansym | 来源:发表于2020-11-22 22:07 被阅读0次

    在Java中,我们有三种存储字符串的方式:String、StringBuffer、StringBuilder。这篇文章主要是整理一下他们各自的优缺点和使用场景。该问题也是面试中常常被问到的基础知识。

    它们之间的关系图如下:

    image

    1.三者区别

    1.1 是否可变

    String定义的字符串不可被改变。 每次对String对象进行改变的时候,其实是Java新创建了一个对象,然后将之前的指针指向的新的对象。这样做不仅浪费了很多空间,还降低了效率。
    而StringBuilder和StringBuffer是可变对象。它们都继承自AbstractStringBuilder类,在AbstractStringBuilder中也是使用字符数组保存字符串。因此他们的类创建的字符串对象能够被多次修改,而不产生新的未使用对象。他们俩可使用的方法也是相同的。

    1.2 线程安全

    StringBuilder是线程不安全的,StringBuffer是线程安全的。因此单线程下使用StringBuilder会效率更高,多线程下使用StringBuffer会效率更高。操作小数据的话,还是String效率高。

    1.3 应用场景

    String使用场景:

    • 字符串内容不长发生改变的业务场景
    • 比如:常量声明、少量字符串拼接

    StringBuffer应用场景:

    • 频繁进行字符串运算时(拼接、替换、删除)
    • 多线程时、因为它支持线程安全
    • 比如:XML解析、HTTP参数的解析与封装

    StringBuilder应用场景:

    • 频繁进行字符串运算时(拼接、替换、删除)
    • 单线程时,因为它不支持线程安全
    • 比如:SQL语句拼接、Json数据封装

    2.StringBuffer

    了解StringBuffer之前,我们先回顾一下String的特点,String字符串一旦定义就不能修改也不能扩充的,而且,当使用连接符对字符串进行拼接的时候java会为字符串新开辟空间,这样就造成了空间的浪费。

    为此StringBuffer作为解决方案应运而生,他是线程安全的可变字符序列。他是一个用final修饰的类,它继承于Object,实现了两个接口。该接口定义后内容可变,大小可变,使用拼接不会产生新的空间。他就类似于一个字符串的缓冲区。

    2.1 容量和长度

    StringBuffer有两个属性,一个是容量,一个是当前长度。容量代表的是能容纳多大的字符串,默认是16个字符大小。

    2.2 构造方法

    它有三个构造方法,一个是无参的(最常用),一个是传入整型参数的,用于指定容量,指定了多少,容量就变成多少。一个是字符串参数的,用于指定内容,容量是16+参数的长度。

    new StringBuffer(); //容量为16
    new StringBuffer(int capacity); //容量是int
    new StringBuffer(String str);   //容量是str.length()+16
    

    2.3 常用方法

    • append:追加

    可以将任意的类型的数据添加到字符串的缓冲区,返回值是StringBuffer,就是它缓冲区本身。

    StringBuffer sb = new StringBuffer();
    StringBuffer sb1 = sb.append("hello");
    System.out.println(sb); //输出hello
    System.out.println(sb1); //输出hello
    System.out.println(sb == sb1); //输出true
    

    因此,直接sb.append()即可,无需使用引用进行接收。

    StringBuffer sb = new StringBuffer();
    sb.append(true).append(123).append("heihei");   //链式编程
    System.out.println(sb);                         //输出true123heihei
    
    • insert:插入

    此方法可指定位置插入任意类型数据。从0开始计数。

    sb.insert(5,"world");
    
    • deleteCharAt:删除指定位置的一个字符
    public StringBuffer deleteCharAt(int index);
    
    • delete(int start, int end ):删除指定长度字符串
    public StringBuffer delete(int start, int end);
    
    • replace(int start, int end, String str):替换指定位置、长度字符串
    public StringBuffer replace(int start, int end, String str);
    
    • reverse():翻转
    public StringBuffer reverse();
    
    • 字符串截取
    public String substring(int start); //从start开始截取直到最后
    pubic String substring(int start, int end); //从start截取,到end结束
    

    注意返回的是字符串

    2.4 String到StringBuffer的转换

    错误转换方式:

    StringBuffer sb = "hello";
    Stringbuffer sb = s;
    

    正确的方式:

    StringBuffer sb = new StringBuffer(s);
    StringBuffer sb1 = new Stringbuffer();
    sb1.append(s)
    

    2.5 StringBuffer到String的转换

    1.通过构造方法

    String str = new String(buffer)
    

    2.通过toString()

    String str = buffer.toString()
    

    任何引用类型调用toString都可以转换成字符串。

    2.6 String与StringBuffer作为形参传递的不同

    对于基本数据类型来说,形参的改变不影响实参,但是对于引用数据类型来说,形参的改变直接改变了实际的参数。

    但是字符串虽然是引用类型,但他是比较特殊的,因为它是常量,存储在字符串常量池中。是一种特殊的引用类型,我们可以将它是为基本数据类型,所以当字符串作为形参的时候,形参改变但实参是不改变的。

    StringBuffer是正常的引用类型,形参改变则实参改变。

    3.可变原理

    StringBuffer(始于 JDK 1.0 )和StringBuilder(始于 JDK 1.5)都是为了提高字符串的拼接效率,直接使用String的+进行拼接的话JVM会创建多个字符串对象,造成开销浪费。他俩用法一样,只不过Buffer是线程安全,Builder是线程不安全的。

    String源码中有一个成员是,使用了final修饰,意思是不能更改:

    private final char value[];
    

    而Buffer和Builder的成员同样也是一个字符数组,但是没有使用final修饰:

    char value[];
    

    所以这就是可变和不可变的基础和前提。

    当要存入字符串的长度+value的长度-value的长度>0的时候,说明,此时的容量已经不足以装下新的字符串了。然后Java会将原来的字符数组复制一份(使用的是str.getchars()),然后开辟一个新的数组,赋予新的容量,该容量是str.length()+value,最后return this,返回当前对象。返回当前对象的好处就是可以写成链式编程。
    String只要已添加就去开辟新对象,而Buffer和Builder只有在容量不够的时候才去开辟新对象。

    4.注意事项

    StringBuilder sb1 = new StringBuilder("abc");
    StringBuilder sb2 = new StringBuilder("abc");
    
    System.out.println(sb1 == sb2);//false
    System.out.println(sb1.equals(sb2));//false
    

    第一个返回的是false是因为它比较的是对象的地址值,而第二个返回的是false是因为StringBuilder没有重写equals方法,使用的是Object的比较方式,也就是比较地址值。所以,要想用值来比较,应该重写equals方法。

    String str1 = "abc";
    StringBuilder sb1 = new StringBuilder("abc");
    System.out.println(str1.equals(sb1));//false
    

    虽然string重写了equals方法,但是,sb1对象不是String类的实例,所以返回的也是false.

    参考:

    相关文章

      网友评论

          本文标题:String、StringBuffer、StringBuilde

          本文链接:https://www.haomeiwen.com/subject/mtypiktx.html