string与stringbuild与stringbuffer

1 string源码

 

源码里可以看到String被final修饰并继承了三个接口
它们的值在创建后无法更改.Stringbuffers支持可变字符串。
因为String对象是不可变的,所以它们可以共享

public final class String
    implements java.io.Serializable, Comparable, CharSequence {
    /** The value is used for character storage. */
    private final char value[];

    /** Cache the hash code for the string */
    private int hash; // Default to 0

    ......

}
public boolean equals(Object anObject) {
        if (this == anObject) {
            return true;
        }
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }

 

public native String intern();

注:方法注释会有写到,意思就是调用方法时,
如果常量池有当前String的值,就返回这个值,没有就加进去,返回这个值的引用
        String str1="a";
        String str2="b";
        String str3="ab";
        String str4 = str1+str2;
        String str5=new String("ab");

        System.out.println(str5==str3);//堆内存比较字符串池
        //intern如果常量池有当前String的值,就返回这个值,没有就加进去,返回这个值的引用
        System.out.println(str5.intern()==str3);//引用的是同一个字符串池里的
        System.out.println(str5.intern()==str4);//变量相加给一个新值,所以str4引用的是个新的
        System.out.println(str4==str3);//变量相加给一个新值,所以str4引用的是个新的
        
        false
        true
        false
        false
重点: --两个字符串常量或者字面量相加,不会new新的字符串,其他相加则是新值,(如 String str5=str1+"b";)

 

2 stringbuild与stringbuffer

stringbuffer线程安全

String一旦赋值或实例化后就不可更改,如果赋予新值将会重新开辟内存地址进行存储。 而StringBuffer类使用append和insert等方法改变字符串值时只是在原有对象存储的内存地址上进行连续操作,减少了资源的开销。  

append原理

@Override
    public synchronized StringBuffer append(String str) {
        toStringCache = null;
        super.append(str);
        return this;
    }


public AbstractStringBuilder append(String str) {
        if (str == null)
            return appendNull();  //如果str为null扩容原有长度+4,count记录null字数 
        int len = str.length();  //此时新的字符进来
        ensureCapacityInternal(count + len);//之前null字符长度+len 扩容
        str.getChars(0, len, value, count);
        count += len;
        return this;
    }


count记录null字数
private AbstractStringBuilder appendNull() {
        int c = count;
        ensureCapacityInternal(c + 4);
        final char[] value = this.value;
        value[c++] = 'n';
        value[c++] = 'u';
        value[c++] = 'l';
        value[c++] = 'l';
        count = c;
        return this;
    }


   @Override
    public synchronized void getChars(int srcBegin, int srcEnd, char[] dst,
                                      int dstBegin)
    {
        super.getChars(srcBegin, srcEnd, dst, dstBegin);
    }


abstract class AbstractStringBuilder implements Appendable, CharSequence {
    /**
     * The value is used for character storage.
     */
    char[] value;
    ......

}

  //在原有数组的基础上进行复制数组
  public void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin)
    {
        if (srcBegin < 0)
            throw new StringIndexOutOfBoundsException(srcBegin);
        if ((srcEnd < 0) || (srcEnd > count))
            throw new StringIndexOutOfBoundsException(srcEnd);
        if (srcBegin > srcEnd)
            throw new StringIndexOutOfBoundsException("srcBegin > srcEnd");
        System.arraycopy(value, srcBegin, dst, dstBegin, srcEnd - srcBegin);

       此时的value是全局变量  char[] value; copy之后更新stringbuffer当前值
    }

 

 

你可能感兴趣的:(string与stringbuild与stringbuffer)