参考:
这篇比较细节 关于如何扩容 复制原数组内容到新数组等
https://blog.csdn.net/qq_17505335/article/details/52806096
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
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);
}
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;
}
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的时候,可以估算新字符串的长度来适当避免多次扩容,影响效率。
//先看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;
}
//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;
}
//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;
}
public StringBuilder reverse() {
super.reverse();
return this;
}
publicsynchronized StringBuffer reverse() {
toStringCache = null;
super.reverse();
return this;
}
//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);
}
//如果一个方法修改了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);
}