java中StringBuilder、StringBuffer、String性能对比(史上最全)

书欣 Java经验 发布时间:2022-10-07 19:20:54 阅读数:6853 1 Java基础面试(2023年优化版)
下文可以毫不夸张的说是:"互联网中最全的一篇String,StringBuilder,StringBuffer"对比大全,希望给初学者提供帮助
String,StringBuilder,StringBuffer是我们日常编程开发中
  常用的字符串处理类,那么她们之间有什么区别及不同之处呢?
  下文笔者将一一道来,如下所示

可变性对比

 1.String类中使用字符数组保存字符串
     String类使用“final”修饰符
	 即表明作者的意图是String对象不可变 
     private final char value[];
   由于String不可变,所以每次String操作都会生成新的对象,可以说效率低下,且浪费空间
  
    String a = "a"; //假设a指向地址0x00888 
	 当使用 a = "Java";//重新赋值后a指向地址0x0889
     但0x00888地址中保存的"a"依旧存在,但已经不再是a所指向的,可以说没有任何意义了,等待回收
    如果String使用不当,会导致FullGC

 2.StringBuilder与StringBuffer都继承自AbstractStringBuilder类
    AbstractStringBuilder中也是使用字符数组保存字符串
	  
    char[] value;//从存储结构上,我们可以看出这两个对象是可变的
	对他进行新的赋值,当字符串大小超过时,则自动增大容量 
	例:
      StringBuffer buf=new StringBuffer(); 
	    //分配长16字节的字符缓冲区
	  StringBuffer buf=new StringBuffer(512); 
	  //分配长512字节的字符缓冲区
     StringBuffer buf=new StringBuffer("java265.com")
	 //在缓冲区中存放了字符串,并在后面预留了16字节的空缓冲区

是否多线程安全

String中的对象是不可变的
 也就可以理解为常量即线程安全

AbstractStringBuilder是StringBuilder与StringBuffer的公共父类
其中有一些字符串的基本操作
  如expandCapacity、append、insert、indexOf等公共方法。

StringBuffer对方法加了同步锁或者对调用的方法加了同步锁
  所以是线程安全的 
  例:
public synchronized StringBuffer reverse() {
    super.reverse();
    return this;
}

public int indexOf(String str) {
    return indexOf(str, 0);        
	//存在 public synchronized int indexOf(String str, int fromIndex) 方法
}

StringBuilder并没有对方法进行加同步锁,所以是非线程安全的
StringBuffer中很多方法都加了synchronized,所以StringBuffer是线程安全

StringBuffer和StringBuilder类的速度比较

通常情况下
 速度从快到慢:StringBuilder>StringBuffer>String
 
例:
package com.java265.test;

public class StringTest {
    final static int time = 50000; //循环次数 
    /*
     * String类测试方法
     */
    public void test(String s){
        long begin = System.currentTimeMillis();//获取当前系统时间(毫秒数),开始
        for(int i=0; i<time; i++){
        s += "add";
        }
        long over = System.currentTimeMillis();//获取当前系统时间(毫秒数),结束
        System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
        }
    /*
     * StringBuffer类测试方法
     */
    public void test(StringBuffer s){
        long begin = System.currentTimeMillis();
        for(int i=0; i<time; i++){
        s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println("操作"+s.getClass().getCanonicalName()+"类型使用的时间为:"+(over-begin)+"毫秒");
        }
    /*
     * StringBuilder类测试方法
     */
    public void test(StringBuilder s){
        long begin = System.currentTimeMillis();
        for(int i=0; i<time; i++){
        s.append("add");
        }
        long over = System.currentTimeMillis();
        System.out.println("操作"+s.getClass().getName()+"类型使用的时间为:"+(over-begin)+"毫秒");
        }

    /*对 String 直接进行字符串拼接的测试*/
    public void test2(){//操作字符串对象引用相加类型使用的时间
        String s2 = "java265.com";
        long begin = System.currentTimeMillis();
        for(int i=0; i<time; i++){
        String s = s2 + s2 +s2;
        }
        long over = System.currentTimeMillis();
        System.out.println("操作字符串对象引用相加类型使用的时间为:"+(over-begin)+"毫秒");
        }
    public void test3(){//操作字符串相加使用的时间
        long begin = System.currentTimeMillis();
        for(int i=0; i<time; i++){
        String s = "java265.com" + "java265.com" +  "java265.com";
        }
        long over = System.currentTimeMillis();
        System.out.println("操作字符串相加使用的时间为:"+(over-begin)+"毫秒");
        } 
    public static void main(String[] args) {
        // TODO Auto-generated method stub
        String s1 =  "java265.com";
        StringBuffer st1 = new StringBuffer( "java265.com");
        StringBuilder st2 = new StringBuilder( "java265.com");
        StringTest tc = new StringTest();
        tc.test(s1);
        tc.test(st1);
        tc.test(st2);
        tc.test2();
        tc.test3(); 
    }

}
性能使用注意事项:
    非多线程的情况下,String速度超快

StringBuilder与StringBuffer共同点

StringBuilder与StringBuffer有公共父类AbstractStringBuilder(抽象类)。
StringBuilder、StringBuffer的方法都会调用AbstractStringBuilder中的公共方法
   如super.append(...)。只是StringBuffer会在方法上加synchronized关键字,进行同步。
两个类的常见方法
方法 备注
StringBuffer append(参数) 追加内容到当前StringBuffer对象的末尾,类似于字符串的连接
StringBuffer deleteCharAt(int index) 删除指定位置的字符,然后将剩余的内容形成新的字符串
StringBuffer insert(位置, 参数) 在StringBuffer对象中插入内容,然后形成新的字符串
StringBuffer reverse() 将StringBuffer对象中的内容反转,然后形成新的字符串
void setCharAt(int index, char ch) 修改对象中索引值为index位置的字符为新的字符ch
void trimToSize() 将StringBuffer对象的中存储空间缩小到和字符串长度一样的长度,减少空间的浪费,和String的trim()是一样的作用
StringBuffer delete(int start, int end) 删除指定区域的字符串
StringBuffer replace(int start, int end, String s) 用新的字符串替换指定区域的字符串
void setlength(int n) 设置字符串缓冲区大小
int capacity() 获取字符串的容量
void ensureCapacity(int n) 确保容量至少等于指定的最小值。如果当前容量小于该参数,然后分配一个新的内部数组容量更大。新的容量是较大的
getChars(int start,int end,char chars[],int charStart); 将字符串的子字符串复制给数组
例:
//www.java265.com 示例分享
public static void main(String[] args) { 
        StringBuilder str=new StringBuilder("我最爱的编程语言就是java-我来自java265.com");
        
        //增加字符串内容的方法
        //append(参数),追加内容到当前对象的末尾
        str.append("学习使我快乐");
        System.out.println("追加内容到当前对象的末尾:"+str);
        // insert(位置, 参数),在对象中插入内容
        str.insert(10,',');
        System.out.println("在对象中插入内容:"+str);
        
        //操作字符串内容的方法
        //delete(int start, int end),删除指定区域的字符串
        str.delete(11, 17);
        System.out.println("删除指定区域的字符串:"+str);
        //deleteCharAt(int index),删除指定位置的字符
        str.deleteCharAt(10);
        System.out.println("删除指定位置的字符:"+str);
        //setCharAt(int index, char newChar),修改对象中索引值为index位置的字符为新的字符ch
        str.setCharAt(3, 'J');
        System.out.println("修改对象中索引值为index位置的字符为新的字符ch:"+str);
        //replace(int start, int end, String s), 用新的字符串替换指定区域的字符串
        str.replace(4, 7, "maomao");
        System.out.println("用新的字符串替换指定区域的字符串:"+str);
        // reverse()内容反转
        str.reverse();
        System.out.println("内容反转:"+str);
        //将字符串的子字符串复制给数组。
        char[] ch  = new char[5];
        str.getChars(0, 4, ch, 0);
        System.out.println("将字符串的子字符串复制给数组:"+Arrays.toString(ch));

        
        
        
        StringBuilder str2=new StringBuilder(30);//创建一个长度为30的字符串
        str2.append("JAVA");
        System.out.println("字符串长度为:"+str2.length());//length(),获取字符串长度
        System.out.println("字符串容量为:"+str2.capacity());//capacity(),获取字符串的容量
        //有关字符串空间的方法
        //setLength(int newSize),设置字符串缓冲区大小
        str2.setLength(20);
        System.out.println("字符串长度为:"+str2.length());
        System.out.println("字符串容量为:"+str2.capacity());
        //ensureCapacity(int n),重新设置字符串容量的大小
        str2.ensureCapacity(20);
        System.out.println("字符串长度为:"+str2.length());
        System.out.println("字符串容量为:"+str2.capacity());
        str2.ensureCapacity(35);
        System.out.println("字符串长度为:"+str2.length());
        System.out.println("字符串容量为:"+str2.capacity());
        //trimToSize(),存储空间缩小到和字符串长度一样的长度
        str2.trimToSize();
        System.out.println("字符串长度为:"+str2.length());
        System.out.println("字符串容量为:"+str2.capacity());   
    }
}
以上示例中方法功能说明
1、在使用有范围的参数方法时,要注意范围包括开头不包括结尾
2、insert方法的位置是你要插入的位置,不是插入前一个位置
3、getChars方法中注意字符数组的长度一定要大于等于begin到end之间字符的长度
4、length是字符串内容的长度,而capacity是字符串容量(包括缓存区)的长度
5、ensureCapacity方法是确保容量至少等于指定的最小值。如果当前容量小于该参数,
   然后分配一个新的内部数组容量更大(不是你指定的值,系统自动分配一个空间)
    如果当前容量不小于该参数,则容量不变
6、trimToSize(),存储空间缩小到和字符串长度一样的长度。避免空间的浪费

String,StringBuffer,StringBuilder使用场景

 1.如果要操作少量的数据用 = String 
 2.单线程操作字符串缓冲区 下操作大量数据 = StringBuilder 
 3.多线程操作字符串缓冲区 下操作大量数据 = StringBuffer
版权声明

本文仅代表作者观点,不代表本站立场。
本文系作者授权发表,未经许可,不得转载。

本文链接: https://www.Java265.com/JavaJingYan/202210/16651417054579.html

最近发表

热门文章

好文推荐

Java265.com

https://www.java265.com

站长统计|粤ICP备14097017号-3

Powered By Java265.com信息维护小组

使用手机扫描二维码

关注我们看更多资讯

java爱好者