1.String效率和StringBuilder效率比较
从下面代码可以看出,同样在字符串“test”后面拼接一百万次,用String耗时98417毫秒,用StringBuilder耗时17毫秒。
因为String是不可变的,拼接时会复制一百万份数据在常量池中,但真正有用的只有一个,耗时长,浪费资源。
而StringBuilder的长度是可变的,直接在原字符串的基础上拼接,无需重新赋值
public class Demo09 {
public static void main(String[] args) {
String str="test";
long start = System.currentTimeMillis();
for(int i=0;i<1000000;i++){
str = str.concat("t");
}
long end = System.currentTimeMillis();
System.out.println("String毫秒值:"+(end-start));//String毫秒值:98417
StringBuilder stringBuilder = new StringBuilder("test");
long start1 = System.currentTimeMillis();
for(int i=0;i<1000000;i++){
stringBuilder.append("t");
}
long end1= System.currentTimeMillis();
System.out.println("StringBuilder毫秒值:"+(end1-start1));//StringBuilder毫秒值:17
}
}
2.StringBuffer和StringBuilder的区别
StringBuffer:jdk1.0提供,线程安全,做线程同步检查,效率低
StringBuilder:jdk1.5提供,线程不安全,不做线程同步检查,效率高,建议采用
3.StringBuilder的方法
public class Demo10 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("test");
char c = stringBuilder.charAt(1);//取出指定下标的字符
System.out.println(c);//e
//stringBuilder.append("t");//在末尾拼接 testt
// stringBuilder.insert(2,"a");//在指定位置添加指定字符 teast
//stringBuilder.setCharAt(2,‘a‘);//给指定位置设置字符 teat
// stringBuilder.deleteCharAt(2);//删除制定法位置的字符 tet
// stringBuilder.delete(1,3);//删除指定区间的字符(含头不含尾) tt
// stringBuilder.replace(1,3,"测试");//替换指定区间的字符(含头不含尾) t测试t
//stringBuilder.reverse();//字符串的反转 tset
System.out.println(stringBuilder);
//StringBuilder转String
String s = stringBuilder.toString();
//String转StringBuilder
String str="aaa";
StringBuilder stringBuilder1 = new StringBuilder(str);
}
}
4.StringBuilder源码
StringBuilder stringBuilder = new StringBuilder();//调用StringBuilder的无参构造器,初始化底层数组长度为16
源码:
public StringBuilder() {
super(16);
}
StringBuilder stringBuilder = new StringBuilder("test");//调用StringBuilder的构造器,初始化底层数组长度为所传字符串长度+16
源码:
public StringBuilder(String str) {
super(str.length() + 16);
append(str);
}
StringBuilder stringBuilder = new StringBuilder(20);//自定义底层数组长度
源码:
public StringBuilder(int capacity) {
super(capacity);
}
测试:
public class Demo11 {
public static void main(String[] args) {
StringBuilder stringBuilder = new StringBuilder("test");
System.out.println("字符串真实长度1:"+stringBuilder.length());//字符串真实长度:4
System.out.println("底层数组长度1:"+stringBuilder.capacity());//底层数组长度:20
for (int i = 0; i <16 ; i++) {
stringBuilder.append("a");
}
System.out.println("字符串真实长度2:"+stringBuilder.length());//字符串真实长度:20
System.out.println("底层数组长度2:"+stringBuilder.capacity());//底层数组长度:20
stringBuilder.append("a");
System.out.println("字符串真实长度3:"+stringBuilder.length());//字符串真实长度:21
System.out.println("底层数组长度3(扩容):"+stringBuilder.capacity());//底层数组长度:42;(扩容前长度X2)+2
for (int i = 0; i <21 ; i++) {
stringBuilder.append("a");
}
System.out.println("字符串真实长度4:"+stringBuilder.length());//字符串真实长度:42
System.out.println("底层数组长度4:"+stringBuilder.capacity());//底层数组长度:42
stringBuilder.append("aa");
System.out.println("字符串真实长度5:"+stringBuilder.length());//字符串真实长度:44
System.out.println("底层数组长度5(扩容):"+stringBuilder.capacity());//底层数组长度:86(扩容前长度X2)+2
}
}
append()扩容机制
扩容后的底层数组长度=原底层数组长度X2+2,默认底层数组长度为16
将一个字符串拼接100次时,使用String的concat()方法,需要复制一百次。使用stringBuilder.append()最多扩容3次(复制三次),所以stringBuilder.append()效率高
stringBuilder.append()源码:
public AbstractStringBuilder append(String str) {
if (str == null)
return appendNull();
int len = str.length();
ensureCapacityInternal(count + len);
str.getChars(0, len, value, count);
count += len;
return this;
}
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}