1 string源码
源码里可以看到String被final修饰并继承了三个接口
它们的值在创建后无法更改.Stringbuffers支持可变字符串。
因为String对象是不可变的,所以它们可以共享
public final class String
implements java.io.Serializable, Comparable<String>, 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当前值
}