String 不可变的字符串

String类部分源码如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
public final class String
// 可序列化
// 可比较大小
implements java.io.Serializable, Comparable<String>, CharSequence {
/** The value is used for character storage. */
private final char value[]; //数组元素不可修改(final)

/** Cache the hash code for the string */
private int hash; // Default to 0

public String concat(String str) {
if (str.isEmpty()) {
return this;
}
int len = value.length;
int otherLen = str.length();
char buf[] = Arrays.copyOf(value, len + otherLen);
str.getChars(buf, len);
return new String(buf, true);
}
}
  • String类被定义成final,不能被扩展,也不需要被扩展(定义的方法很全)。
  • 用char数组来存储,并定义成final,不可变
  • 对字符串操作,不改变原字符串,都是new String()。
image-20220421094420345

intern():如果字符串常量池中包含一个等于String对象的字符串(通过equals()),则返回池中的字符串,否则,将String对象添加到池中,并返回该对象的引用。由此可见,对于任何两个字符串 s 和 t,当且仅当 s.equals(t) 为真时,s.intern() == t.intern() 才为真。

String & StringBuffer & StringBuilder

StringBuilder部分源码

1
2
3
4
5
6
7
8
9
10
11
12
public final class StringBuilder
extends AbstractStringBuilder
implements java.io.Serializable, CharSequence{
char[] value;

@Override
public AbstractStringBuilder append(char c) {
ensureCapacityInternal(count + 1);
value[count++] = c;
return this;
}
}
  • 保存数据的char数组并未被定义成final
  • 可变字符序列
  • String是不可变字符序列,而StringBuffer,StringBuilder都是可变字符序列
  • String可以通过字面量方式赋值,StringBuffer/StringBuilder只能是通过构造器 new
  • StringBuffer线程安全,效率低(里面的方法都是synchronized,同步方法),而StringBuilder线程不安全的,效率高

三者底层都是使用char[]数组进行存储,那如何实现可变和不可变?

String s=new String() //new char[0],长度为0

String s=new String("abc") //new char[3]{‘a’,’b’,’c’}

StringBuffer buffer=new StringBuffer()// new char[capacity] capacity=16

StringBuffer buffer1=new StringBuffer("abc")// new char[s.length()+capacity] capacity=16 capacity+s.length()作为初始容量,然后调用buffer.append() (看一下如何进行扩容)

问题1:此时buffer1.length() 是3 //append()后count+buffer1.length()返回count的值,而不是数组的容量

问题2:char数组如何进行扩容?

1
2
3
4
5
6
7
8
private void ensureCapacityInternal(int minimumCapacity) {   //确保容量是够的
// minimumCapacity是count+append的字符长度
if (minimumCapacity - value.length > 0) {//大于数组长度,不够了,需要扩容
value = Arrays.copyOf(value,
newCapacity(minimumCapacity));//默认下,扩充的容量是2倍的value+2
}
//int newCapacity = (value.length << 1) + 2;
}

如果append次数很多,频繁扩容,扩容要复制一份,影响效率,所以可以使用StringBuffer(int capacity)构造器,指定容量

1
2
3
4
//跟 String做对比
StringBuffer buffer=new StringBuffer("abc");
buffer.setCharAt(1,'m');//void方法,没有返回值
System.out.println(buffer);//amc