String、StringBuffer与StringBuilder

394 阅读2分钟

String对象不可改变,意思是说内存中某个对象本身所在的内存位置里面的内容不能更改;但是字符串引用是可以改变指向的。

三者的比较

Item 中文解释 执行速度 线程安全 如何选择
String 字符串常量 最慢 安全 操作少量数据时使用
StringBuffer 字符串变量 中间 线程安全 多线程,大量数据
StringBuilder 字符串变量 最快 线程不安全 单线程,操作大量数据
伪代码
String s="abcd";
s=s+1;
System.out.println(s);
//result:abcd1
不要迷惑上面这段代码不是说String不可变吗?怎么回事?其实这个不可变指的不是s的指向不可变,而是"abcd"不可变。JVM计算过程并不是在原"abcd"上面进行的,而是又创建了对象"abcd1",将s指向新创建的"abcd1",这样不断的创建对象回收对象,导致效率低下。而如果使用的是StringXxxx就是在原来的对象"abcd"上面直接进行的。

但但但是一个特殊的例子:
String str="this is only a"+"simple"+"test";居然比
StringBufferbuilder = new StringBuilder(“This is only a”).append(“ simple”).append(“test”); 
还要快,为嘛?这是因为:
String str="this is only a"+"simple"+"test";其实就是:
String str = “This is only a simple test”;
如果你拼接的这几个字母是来自其它字符串变量的引用那就不一样了:
String str2 = “This is only a”;
String str3 = “ simple”;
String str4 = “ test”;
String str1 = str2 +str3 + str4;

StringXxxx的扩容问题:

  1. 无参构造方法直接给与16字节的空间;
  2. 有参给与字节长度+16的空间;
  3. append过程中如果长度超过了空间大小就需要扩容,如何扩容?

    • 当你append时先计算你append之后的长度,如果大于当前的空间长度就会自动给你分配2*append之前的长度+2;
    • 如果步骤1进行之后仍然达不到你的长度要求,那么就直接给你append之后你需要的长度。

        进行伪代码举例:
        StringBuffer sb=new StringBuffer("abc");//当前长度:3+16=19;
        sb.append("123");//当前长度:3+19=22;
        sb.append("qwertyuiopasdfghjklz");//此时会先计算append之后需要的长度是26;但是当前长度只有22,此时会先扩容到2*22+2=48;
      
        如果第三行代码append了100个字节,那经过计算2*22+2=48<106满足不了需求怎么破?那就直接给它扩容到106个字节就好了。

希望大家不吝赐教,指出我理解不到位和错误的地方。感谢!!!