您的位置:首页 > 产品设计 > UI/UE

String,StringBuilder,StringBuffer总结

2016-09-29 10:40 274 查看
String:不可变字符序列    Stringbuilder和StringBuffer:可变字符序列三个类都在java.lang包,都是final类不可继承,都用char[]保存内容

String:

关于String s = "abc";和String s = new String("abc");

拘留字符串对象:equals相同的字符串对象,在堆内存中只会有一个拘留字符串对象。

String s = new String("abc");堆中两个对象:一个拘留对象一个普通对象。在此基础上加:String s2 = new String("abc"); 此时堆中一共三个对象(一个拘留两个普通)

String s = "abc"; 堆中只有一个拘留对象。在此基础上加:String s2 = "abc"; 此时堆中仍然只有一个拘留对象,两个引用指向同一个堆中地址。

“ab”+“cd” == “abcd”,true,一共三个拘留字符串对象,常量池中三个值;

String s = “ab”,s+“cd" == "abcd"; false,四个对象,其中三个拘留字符串对象,常量池中三个值。

String类中的源码:

private final char[] value;  所以String是不可变的,new出来的String对象进行操作“+”会new一个新对象然后改变引用(大量+导致效率低:JVM时间消耗主要在创建对象和回收对象)。

重写equals:

public boolean equals(Object anObject) {
if (this == anObject) {<span style="white-space:pre">//先判断地址,是不是同一个对象
return true;
}
if (anObject instanceof String) {
String anotherString = (String)anObject;
int n = value.length;
if (n == anotherString.value.length) {<span style="white-space:pre">//待比较对象是字符串且长度相同时,拿到String的value(字符数组),依次比较
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;
}
重写equals必重写hashcode。 源码中hashcode的值:h = 31 * h + val[i];     val表示String存内容的那个字符数组,字符数组多长循环多少次。

substring方法:先判断index是否正确,然后new了一个新String返回。

StringBuilder和StringBuffer:

   异:StringBuffer中所有的insert、append、delete等方法都加了synchronized锁,保证多线程下的同步,但是影响效率;

  StringBuilder是JDK1.5新增的,所有的方法都没有加锁。适用于单线程下的操作,效率比StringBuffer高。但是多线程下不能使用,会出现线程安全问题。

同:都继承自抽象类AbstractStringBuilder,大部分方法的实现都是在这个类里写的,两个实现类基本都是super调它的方法(有无synchronied)。

关于AbstractStringBuilder中的源码:

  char[] value; 保存各字符;区别于String类少了private final的修饰。所以可以改value的引用地址,使这两个类看上去长度是可变的(长度不够数组扩容)。

      append源码:

public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);//保证不会超过当前数组的容量,超过则建新数组替换引用(因为数组长度是final,只能创建新的容量更大的数组,同时拷贝原来的数据)
str.getChars(0, len, value, count);//将str放到value数组的最后(len)的位置。实现:System.arraycopy(),五个参数。
count += len;
return this;
}
  insert方法类似:判断形参、保证数组容量、System.arraycopy将目标索引后面的元素都向后移、str.getChars将新的str放到字符数组。

  数组扩容的源码:

void expandCapacity(int minimumCapacity) {  //形参的值:新字符串的实际长度
int newCapacity = value.length * 2 + 2;  //扩容后的默认大小是原来数组长度的两倍+2
if (newCapacity - minimumCapacity < 0)  //两倍+2 长度仍然不够新的实际长度
newCapacity = minimumCapacity;
if (newCapacity < 0) {
if (minimumCapacity < 0)
throw new OutOfMemoryError();
newCapacity = Integer.MAX_VALUE;
}
value = Arrays.copyOf(value, newCapacity);//改变value的引用。原来那个char数组由于没有任何引用可以到达,下一次GC会被回收掉
}</span>

总结:不需要改变字符串的内容时,使用String,且尽量不要new对象;

     需要改动字符串的内容时[b](增插删),单线程内使用StringBuilder,多线程使用StringBuffer。[/b]
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息