不积跬步,无以至千里

String,StringBuilder和StringBuffer比较


今天用idea的时候,注意到生成toString代码的时候,提供了两种方式:StringBuilder和StringBuffer,之前一直用的StringBuilder,避免在修改字符串的时候频繁申请内存空间,StringBuffer倒是很少用,刚好有时间,理下这三个类的区别。

String

String变量是不可更改的,每次初始化一个String变量:String parameter="test"; 在堆内存中都会保存一个常量字符串,每次对String变量做修改都会新建一个字符串常量

    public String substring(int beginIndex) {
        if (beginIndex < 0) {
            throw new StringIndexOutOfBoundsException(beginIndex);
        }
        int subLen = value.length - beginIndex;
        if (subLen < 0) {
            throw new StringIndexOutOfBoundsException(subLen);
        }
        return (beginIndex == 0) ? this : new String(value, beginIndex, subLen);
    }
    public String concat(String str) {
        int otherLen = str.length();
        if (otherLen == 0) {
            return this;
        }
        int len = value.length;
        char buf[] = Arrays.copyOf(value, len + otherLen);
        str.getChars(buf, len);
        return new String(buf, true);
    }
    public String replace(char oldChar, char newChar) {
        if (oldChar != newChar) {
            int len = value.length;
            int i = -1;
            char[] val = value; /* avoid getfield opcode */

            while (++i < len) {
                if (val[i] == oldChar) {
                    break;
                }
            }
            if (i < len) {
                char buf[] = new char[len];
                for (int j = 0; j < i; j++) {
                    buf[j] = val[j];
                }
                while (i < len) {
                    char c = val[i];
                    buf[i] = (c == oldChar) ? newChar : c;
                    i++;
                }
                return new String(buf, true);
            }
        }
        return this;
    }

可以看到,由于String实例只是堆内存中一个常量字符串的引用,对这个String实例指向的字符串常量是不可修改的,唯一能修改的是这个实例指向的内存地址,所以每次对一个String实例做修改的时候,只会重新分配一个内存空间,赋值后将这个String实例指向修改后的内存空间。

多说一句关于String的方法public native String intern();看网上分析说1.6和1.7的intern方法实现不同,我粘一段1.8的解释,这个方法用于返回一个字符串,它的内容与这个字符串相同,但它来自于字符串常量池。

返回字符串对象的规范表示。 一组字符串,最初是空的,由类String私下维护。 当调用intern()方法时,如果池中已经包含了一个字符串,该字符串等于equals(object)方法所确定的string对象,那么将返回池中的字符串。否则,这个String对象被添加到池中,并返回这个String对象的引用。
它遵循了任何两个字符串s和t,只有当s.equals(t)的时候,才会有s.intern()==t.intern()。 所有的字符串和字符串值常量表达式都被interned。String 3.10.5节中定义的Java™语言规范。

StringBuffer

StringBuffer是线程安全的,这个类中需要做多线程同步的方法都加了synchronized关键字做线程同步。

StringBuilder

StringBuilder是StringBufferr的补充版,两个类提供了一样的接口,但是由于StringBuilder不需要做同步处理,所以处理速度要比StringBuffer快。