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未使用同步锁,故效率提高。

posted @ 2021-10-08 09:34  pioner  阅读(68)  评论(0编辑  收藏  举报