String 为啥是不可变的?
String 被声明为final
,因此它不可被继承。内部使用 char
数组存储数据,该数组被声明为 final
,这意味着 value 数组初始化之后就不能再引用其它数组。并且 String 内部没有改变 value 数组的方法,因此可以保证 String 不可变。
public final class String
implements java. io. Serializable, Comparable < String > , CharSequence {
private final char value[ ] ;
StringBuffer和StringBuilder为啥是可变的?
StringBuffer stringBuffer = new StringBuffer ( "123" ) ;
stringBuffer. append ( "123" ) ;
@Override
public synchronized StringBuffer append ( String str) {
toStringCache = null ;
super . append ( str) ;
return this ;
}
在父类append()中调用ensureCapacityInternal()主要是用来给StringBuffer里面的数组扩容的
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 ;
}
ensureCapacityInternal()的扩容 先调用newCapacity()给数组扩容,再调用Arrays.copyOf()复制一个新的数组出来,长度是扩容之后的长度,赋值给数组 StringBuffer中的vakue数组不是final类型的 newCapacity()细节略过
private void ensureCapacityInternal ( int minimumCapacity) {
if ( minimumCapacity - value. length > 0 ) {
value = Arrays . copyOf ( value,
newCapacity ( minimumCapacity) ) ;
}
}
再看str.getChars(0, len, value, count),底层是使用System.arraycopy()进行赋值,arraycopy()是一个native方法 第一个参数是0,第二个参数是增加的字符窜的长度,第三个是原字符数组,count是被使用的字符个数
public void getChars ( int srcBegin, int srcEnd, char dst[ ] , int dstBegin) {
if ( srcBegin < 0 ) {
throw new StringIndexOutOfBoundsException ( srcBegin) ;
}
if ( srcEnd > value. length) {
throw new StringIndexOutOfBoundsException ( srcEnd) ;
}
if ( srcBegin > srcEnd) {
throw new StringIndexOutOfBoundsException ( srcEnd - srcBegin) ;
}
System . arraycopy ( value, srcBegin, dst, dstBegin, srcEnd - srcBegin) ;
}
这里复制之后,StringBuffer内部的字符数组内容就变化了,所以是可变的.