参考:
https://blog.csdn.net/rusbme/article/details/51389623
https://blog.csdn.net/matrix5267/article/details/62423340
String 字符串常量
StringBuffer 字符串变量(线程安全)
StringBuilder 字符串变量(非线程安全)
String a= new String("hello");
1:在栈内存中定义了一个a对象引用,指向堆内存的值“hello”内存地址。最终开辟了一个内存空间
2:在栈内存重定义了一个a对象引用,先指向堆内存值为“hello”内存地址,然后又指向new之后堆内存为“hello”的地址。最终开辟了两个空间,第一个空间没有对象引用,会被JVM垃圾回收。
str += "andy";
str的值不是也改变了吗?
其实上述代码在内存中已经开辟了3个空间,分别是:”hello“, ”andy“, ”helloandy“,他们的堆内存大小是固定的,最终str指向了”helloandy“的堆地址。 而StringBuffer使用时,只会开辟一块内存空间,可以使用append添加delete等操作内容。
首先我们来看两个类的继承体系
public final class StringBuilder extends AbstractStringBuilder implements Appendable, CharSequence, Serializable; public final class StringBuffer extends AbstractStringBuilder implements Appendable, Serializable, CharSequence
AbstravtStringBuilder类
private char[] value; static final int INITIAL_CAPACITY = 16; AbstractStringBuilder() { value = new char[INITIAL_CAPACITY]; } AbstractStringBuilder(int capacity) { if (capacity < 0) { throw new NegativeArraySizeException(Integer.toString(capacity)); } value = new char[capacity]; } AbstractStringBuilder(String string) { count = string.length(); shared = false; value = new char[count + INITIAL_CAPACITY]; string.getCharsNoCheck(0, count, value, 0); }
构造函数:
//两个类的构造方法完全相同,都是调用父类的构造函数,并且留有16的空间 publicStringBuilder() { super(16); } public StringBuilder(int capacity) { super(capacity); } public StringBuilder(String str) { super(str.length() + 16); append(str); } public StringBuilder(CharSequence seq) { this(seq.length() + 16); append(seq); }
默认初始容量为16,当然我们也可以自己设置容量大小;接着我们看看拼接过程
final void append0(char[] chars) { int newCount = count + chars.length; if (newCount > value.length) { enlargeBuffer(newCount); } System.arraycopy(chars, 0, value, count, chars.length); count = newCount; }
接下来我们看看SB 扩容过程,
void expandCapacity(int minimumCapacity) { int newCapacity = value.length * 2 + 2; if (newCapacity - minimumCapacity < 0) newCapacity = minimumCapacity; if (newCapacity < 0) { if (minimumCapacity < 0) // overflow throw new OutOfMemoryError(); newCapacity = Integer.MAX_VALUE; } value = Arrays.copyOf(value, newCapacity); }
尝试将新容量扩为大小变成2倍+2 ,容量如果不够,直接扩充到需要的容量大小。所以我们在创建SB的时候,可以估算新字符串的长度来适当避免多次扩容,影响效率。
基本方法:
append
//先看StringBuilder public StringBuilder append(Object obj) { return append(String.valueOf(obj)); } //StringBuffer,CharSequence,char[]与之类似 public StringBuilder append(String str) { super.append(str); return this; } //boolean,char,long,float,double与之类似 public StringBuilder append(int i) { super.append(i); return this; }
//StringBuffer public synchronized StringBuffer append(Object obj) { toStringCache = null; super.append(String.valueOf(obj)); return this; } //StringBuffer,CharSequence,char[]与之类似 public synchronized StringBuffer append(String str) { toStringCache = null; super.append(str); return this; } //boolean,char,long,float,double与之类似 public synchronized StringBuffer append(int i) { toStringCache = null; super.append(i); return this; }
insert
//StringBuilder public StringBuilder insert(int index, char[] str, int offset, int len) { super.insert(index, str, offset, len); return this; } public StringBuilder insert(int offset, Object obj) { super.insert(offset, obj); return this; } public StringBuilder insert(int offset, int i) { super.insert(offset, i); return this; }
//StringBuffer publicsynchronized StringBuffer insert(int index, char[] str, int offset, int len) { toStringCache = null; super.insert(index, str, offset, len); return this; } public synchronized StringBuffer insert(int offset, Object obj) { toStringCache = null; super.insert(offset, String.valueOf(obj)); return this; } public StringBuffer insert(int offset, int i) { // Note, synchronization achieved via invocation of StringBuffer insert(int, String) // after conversion of i to String by super class method // Ditto for toStringCache clearing super.insert(offset, i); return this; }
- 3
- 4
- 5
delete
//StringBuilder publicStringBuilder delete(int start, int end) { super.delete(start, end); return this; } public StringBuilder deleteCharAt(int index) { super.deleteCharAt(index); return this; } public StringBuilder replace(int start, int end, String str) { super.replace(start, end, str); return this; }
//StringBuffer public synchronized StringBuffer delete(int start, int end) { toStringCache = null; super.delete(start, end); return this; } public synchronized StringBuffer deleteCharAt(int index) { toStringCache = null; super.deleteCharAt(index); return this; } public synchronized StringBuffer replace(int start, int end, String str) { toStringCache = null; super.replace(start, end, str); return this; }
reverser
public StringBuilder reverse() { super.reverse(); return this; } publicsynchronized StringBuffer reverse() { toStringCache = null; super.reverse(); return this; }
toString
//StringBuilder public String toString() { // Create a copy, don't share the array return new String(value, 0, count); } //StringBuffer public synchronized String toString() { if (toStringCache == null) { toStringCache = Arrays.copyOfRange(value, 0, count); } return new String(toStringCache, true); }
StringBuffer独有:
//如果一个方法修改了value,那么同步使用length()方法就会出问题 public synchronized int length() { return count; } public synchronized int capacity() { return value.length; } public synchronized void ensureCapacity(int minimumCapacity) { if (minimumCapacity > value.length) { expandCapacity(minimumCapacity); } } //同样的道理,这个也加了synchronized public synchronized char charAt(int index) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); return value[index]; } public synchronized void getChars(int srcBegin, int srcEnd, char[] dst, int dstBegin) { super.getChars(srcBegin, srcEnd, dst, dstBegin); }
public synchronized void setLength(int newLength) { toStringCache = null; super.setLength(newLength); } public synchronized void setCharAt(int index, char ch) { if ((index < 0) || (index >= count)) throw new StringIndexOutOfBoundsException(index); toStringCache = null; value[index] = ch; }
public synchronized String substring(int start) { return substring(start, count); } public synchronized String substring(int start, int end) { return super.substring(start, end); } publicsynchronized CharSequence subSequence(int start, int end) { return super.substring(start, end); }