Java中的String,StringBuffer和StringBuilder

在了解这个问题的时候查了不少资料,最有帮助的是这个博文:http://swiftlet.net/archives/1694,看了一段时间,咀嚼了一段时间,写一个经过自己消化的博文,希望能帮到大家。

首先,String,StringBuffer,和StringBuilder都是对char[]的封装,而不同点在于String可以被认为是字符串常量,而StringBuffer,StringBuilder则是字符串变量。

String的成员变量如下:

1 private final char value[];
2 private final int offset;
3 private final int count;

注意到char value[]是final的,代表着对象一旦被创建就不可改。我们平时常对String执行类似如下操作看起来更改字符串比较自由随意,但是其本身是不断创建新对象的过程:

String a="Hello World";
a=a+"!";
System.out.println(a);
//result: Hello World!

所以,对String执行这种经常修改字符串的操作是效率低下的。

与String不同,StringBuffer和StringBuilder都继承于AbstractStringBuilder,所以我们从AbstractStringBuilder看起

其中成员变量如下

1 char value[];
2 int count;

首先不是final的,其次这个类引入了很多对“容量”控制的方法,很像C++中的<Vector>

例如扩容:当添加字符的长度使得char value[]超出了其本身的最大大小,需要创建一个更大的char[]并将内容复制:

 1 void expandCapacity(int minimumCapacity) 
 2 {
 3     int newCapacity = (value.length + 1) * 2;
 4         if (newCapacity < 0) 
 5         {
 6             newCapacity = Integer.MAX_VALUE;
 7         } else if (minimumCapacity > newCapacity)
 8         {
 9         newCapacity = minimumCapacity;
10     }    
11     char newValue[] = new char[newCapacity];
12     System.arraycopy(value, 0, newValue, 0, count);
13     value = newValue;
14  }

同样,char[]不可能所有容量都被使用,结束标识符同C一样是“”;

补长或者截断:

 1 public void setLength(int newLength) 
 2 {
 3     if (newLength < 0)
 4         throw new StringIndexOutOfBoundsException(newLength);
 5     if (newLength > value.length)
 6         expandCapacity(newLength);
 7     if (count < newLength)
 8         {
 9         for (; count < newLength; count++)
10         value[count] = '';
11      } else 
12          {
13             count = newLength;
14          }
15  }

内存复制的方法常用的是:

public static native void arraycopy(Object src, int  srcPos, Object dest, int destPos, int length);

那么StringBuffer和StringBuilder有什么区别:先从StringBuffer和StringBuilder到String的转换看起:

 1 public String(StringBuffer buffer)
 2 {
 3     synchronized(buffer)
 4     {
 5       this.value = Arrays.copyOf(buffer.getValue(), buffer.length()); }
 6   }
 7 public String(StringBuilder builder)
 8 {
 9     this.value = Arrays.copyOf(builder.getValue(), builder.length());
10 }

可见,对于StringBuffer而言,处处要考虑其在多线程环境下的并发问题。也就是说,相比于StringBuilder而言,StringBuffer是线程安全的。

另外,关于String的intern方法,是将字符串常量放在一个由String类维护的常量池中。当调用intern 方法时,如果池中已经包含一个等于此String 对象的字符串(是否相等由 equals(Object)方法确定),则返回池中的字符串引用。否则,将此 String 对象添加到池中,并且返回此String 对象的引用。例如:对于任何两个字符串s和t,当且仅当s.equals(t)为true时,s.intern()==t.intern()才为true。

原文地址:https://www.cnblogs.com/lumaoxin/p/7826941.html