String、StringBuilder和StringBuffer学习并区分(结对团队博客03)
目录大纲:
一、String、StringBuilder以及StringBuffer
二、既然有了String,为什么需要StringBuilder 与StringBuffer呢
三、三者区别
一、String、StringBuilder以及StringBuffer
String类,通过我们寻找,可以找到该类的源码:
1 public final class String 2 implements java.io.Serializable, Comparable<String>, CharSequence 3 { 4 /** The value is used for character storage. */ 5 private final char value[]; 6 7 /** The offset is the first index of the storage that is used. */ 8 private final int offset; 9 10 /** The count is the number of characters in the String. */ 11 private final int count; 12 13 /** Cache the hash code for the string */ 14 private int hash; // Default to 0 15 16 /** use serialVersionUID from JDK 1.0.2 for interoperability */ 17 private static final long serialVersionUID = -6849794470754667710L; 18 19 ...... 20 21 }
(1)可以发现,该类由final修饰,因此String类不能被继承。
(2)而且是通过char数组来保存字符串的。
(3)一旦定义了一个String变量,该变量内容不可改变。
而查看到String 类的方法源码:
1 public String substring(int beginIndex, int endIndex) { 2 if (beginIndex < 0) { 3 throw new StringIndexOutOfBoundsException(beginIndex); 4 } 5 if (endIndex > count) { 6 throw new StringIndexOutOfBoundsException(endIndex); 7 } 8 if (beginIndex > endIndex) { 9 throw new StringIndexOutOfBoundsException(endIndex - beginIndex); 10 } 11 return ((beginIndex == 0) && (endIndex == count)) ? this : 12 new String(offset + beginIndex, endIndex - beginIndex, value); 13 } 14 15 public String concat(String str) { 16 int otherLen = str.length(); 17 if (otherLen == 0) { 18 return this; 19 } 20 char buf[] = new char[count + otherLen]; 21 getChars(0, count, buf, 0); 22 str.getChars(0, otherLen, buf, count); 23 return new String(0, count + otherLen, buf); 24 } 25 26 public String replace(char oldChar, char newChar) { 27 if (oldChar != newChar) { 28 int len = count; 29 int i = -1; 30 char[] val = value; /* avoid getfield opcode */ 31 int off = offset; /* avoid getfield opcode */ 32 33 while (++i < len) { 34 if (val[off + i] == oldChar) { 35 break; 36 } 37 } 38 if (i < len) { 39 char buf[] = new char[len]; 40 for (int j = 0 ; j < i ; j++) { 41 buf[j] = val[off+j]; 42 } 43 while (i < len) { 44 char c = val[off + i]; 45 buf[i] = (c == oldChar) ? newChar : c; 46 i++; 47 } 48 return new String(0, len, buf); 49 } 50 } 51 return this;
含有concet , replace , substring 方法,从这些源码 可以看到,无论是哪个方法和操作功能,都是返回一个新的字符串对象,而不是在原字符串上操作,原字符串未发生改变
因此,总结一下String类的特点:
(1)不能被继承
(2)通过char数组存储内容
(3)方法 / 函数都不是对原字符串操作,而是产生一个新的字符串
而StringBuilder 与StringBuffer都继承自AbstractStringBuilder,拥有的成员属性以及成员方法基本相同。
二、既然有了String,为什么需要StringBuilder 与StringBuffer呢
以寻找的博客例子 来说,思考一下下面的代码:
1 public class Main { 2 3 public static void main(String[] args) { 4 String string = ""; 5 for(int i=0;i<10000;i++){ 6 string += "hello"; 7 } 8 } 9 }
这句 string += "hello";的过程相当于将原有的string变量指向的对象内容取出,与"hello"作字符串相加操作,再存进另一个新的String对象当中,再让string变量指向新生成的对象。
(新)而在实际运行中,在每次循环,都会new出一个StringBuilder对象,然后进行append操作,最后通过toString方法返回String对象。因此,在这个程序里,我们new了1000个新的对象,造成了巨大的内存资源浪费。在编译中,string+="hello"的操作事实上会自动被JVM优化成:
StringBuilder str = new StringBuilder(string);
str.append("hello");
str.toString();
而在查看一下新的代码:
1 public class Main { 2 3 public static void main(String[] args) { 4 StringBuilder stringBuilder = new StringBuilder(); 5 for(int i=0;i<10000;i++){ 6 stringBuilder.append("hello"); 7 } 8 } 9 }
区别在是从“String”变成了“StringBuilder”。在编译运行过程,只生成了一个对象,append操作是在原有对象的基础上进行的。因此在循环了10000次之后,这段代码所占的资源要比上面小得多。
因此,可以说,StringBuilder就是在进行字符串操作时,优化节省内部资源的。比String更节省资源。
那StringBuilder和StringBuffer类的区别是什么呢
他们拥有的成员属性以及成员方法基本相同,区别是StringBuffer类的成员方法前面多了一个关键字:synchronized
这个关键字是在多线程访问时起到安全保护作用的,也就是说StringBuffer是线程安全的。
下面以StringBuffer和StringBuilder两个类的insert方法的源码为例:
StringBuilder:
1 public StringBuilder insert(int index, char str[], int offset, 2 int len) 3 { 4 super.insert(index, str, offset, len); 5 return this; 6 }
StringBuffer:
1 public synchronized StringBuffer insert(int index, char str[], int offset, 2 int len) 3 { 4 super.insert(index, str, offset, len); 5 return this; 6 }
StringBuffer比StringBuilder多了一个关键字,确保了线程安全。
三、三者区别
(1)String、StringBuilder、StringBuffer三者的执行效率:
StringBuilder > StringBuffer > String
再细致到操作时
当字符串相加操作或者改动较少的情况下,建议使用 String str="hello"这种形式;
当字符串相加操作较多的情况下,建议使用StringBuilder,
如果采用了多线程,则使用StringBuffer。
或者是
少量数据 用 String
大量数据,单线程 用 StringBuilder
多线程用 StringBuffer
(2)StringBuffer在拼接字符串时,使用了同步锁,安全性提高;而StringBuilder未使用同步锁,故效率提高。