常量池
public static void main(String[] args) {
String str = “ab”;
String str1 = “a” + “b”;
String str2 = new String(“ab”);
String str3 = “ab”.intern();
String str4 = “a”.intern() + “b”.intern();
String str5 = new String(“ab”).intern();
System.out.println(str == str1); // true
System.out.println(str == str2); // false
System.out.println(str == str3); // true
System.out.println(str == str4); // false
System.out.println(str == str5); // true
}
运行时常量池是方法区的一部分,Class 文件中常量池表中的字符串字面量将在类加载后存放到运行时常量池。使用 new 的将会在 Java 堆中分配。
intern()
方法注释:
返回字符串对象的规范表示。
一个字符串池,最初是空的,由 String 类私有地维护。
当调用 intern 方法时,如果池中已经包含了一个由 equals(Object) 方法确定的与这个 String 对象相等的字符串,那么将返回池中的字符串。否则,这个String对象将被添加到池中,并返回对这个String对象的引用。
由此可见,对于任何两个字符串 s 和 t,如果且仅当 s.equals(t) 为真时, s.intern() == t.intern() 为真。
所有字面字符串和字符串值的常量表达式都会被 intern。字符串字面量的定义在 The Java™ 语言规范的 3.10.5 节中。
String#concat
public String concat(String str) {
int otherLen = str.length();
if (otherLen == 0) {
return this;
}
int len = value.length;
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
Arrays.copyOf(char[], int)
用来扩大一个数组的长度,返回一个新的字符数组:
public static char[] copyOf(char[] original, int newLength) {
char[] copy = new char[newLength];
System.arraycopy(original, 0, copy, 0,
Math.min(original.length, newLength));
return copy;
}
new 了一个新的长度的 char[],再调用 System.arrayCopy()
:
public static native void arraycopy(Object src, int srcPos,
Object dest, int destPos,
int length);
是一个 native 方法,将 src 从 srcPos 位置 copy 到 dest 的 destPos 开始,copy length 长度。
上面我们 copy 了二者长度的较小值,得到了新的 buf[]
。接着调用str.getChars(buf, len);
:
void getChars(char dst[], int dstBegin) {
System.arraycopy(value, 0, dst, dstBegin, value.length);
}
将要添加的字符串 copy 到处于 buf[]
原字符串 len 之后的位置,copy 要添加的字符串的长度这么长。
最后以 buf[]
为参数构造了一个新的字符串返回。
StringBuilder
field
从 AbstractStringBuilder 中继承:
char[] value;
存储 SB 中的字符。
int count;
value 数组中已经使用的数量。
`private static final int MAX_ARRA
《一线大厂Java面试题解析+后端开发学习笔记+最新架构讲解视频+实战项目源码讲义》
【docs.qq.com/doc/DSmxTbFJ1cmN1R2dB】 完整内容开源分享
Y_SIZE = Integer.MAX_VALUE - 8;`
构造方法
SB 初始容量是 16。
public StringBuilder() {
super(16);
}
StringBuilder#append
@Override
public StringBuilder append(String str) {
super.append(str);
return this;
}
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;
}
如果传入的是 null
,转换为字符串插进去:
private AbstractStringBuilder appendNull() {
int c = count;
ensureCapacityInternal(c + 4);
final char[] value = this.value;
value[c++] = ‘n’;
value[c++] = ‘u’;
value[c++] = ‘l’;
value[c++] = ‘l’;
count = c;
return this;
}
构造方法传 null 会报 NPE。
ensureCapacityInternal 也是用 Arrays.copyOf
增加长度:
private void ensureCapacityInternal(int minimumCapacity) {
// overflow-conscious code
if (minimumCapacity - value.length > 0) {
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));
}
}
新的长度一般是原长度的 2 倍 + 2:
private int newCapacity(int minCapacity) {
// overflow-conscious code
int newCapacity = (value.length << 1) + 2;
if (newCapacity - minCapacity < 0) {
newCapacity = minCapacity;
}
return (newCapacity <= 0 || MAX_ARRAY_SIZE - newCapacity < 0)
? hugeCapacity(minCapacity)
: newCapacity;
}
接着调用了 String#getChars 的另一个重载方法:
public void getChars(int srcBegin, int srcEnd, char dst[], int dstBegin) {