走近Java之幕后的String

时间:2021-06-11 01:02:28

前几天,有个同事问了我一个表面看起来显而易见的问题,是关于String的,我们一起来看一下(如果有说的不正确的地方,欢迎大家指正)。

走近Java之幕后的String

java中,字面量在编译期计算,并且String字面量作为常量,存储在方法区中,仅保留一份。带有变量的计算,在运行期执行。那么,str3在执行的时候,发生了什么。

第一步,初始化一个StringBuilder对象,并在构造器中调用父类AbstractStringBuilder的构造器,初始化一个长度16的字符数组

走近Java之幕后的String

走近Java之幕后的String

第二步,调用StringBuilder的append()方法,传入变量str1,内部调用父类AbstractStringBuilder的append()方法

走近Java之幕后的String

走近Java之幕后的String

在入参不为null的情况下,先调用ensureCapacityInternal()方法,判断拼接后的字符串长度是否超过当前字符数组的长度。如果超过了,就计算一个新的长度,然后创建一个新的数组,将现有数组的值复制给它,

走近Java之幕后的String

具体扩容规则是,将当前字符数组长度扩容一倍再加2,如果扩容后的数组长度还不够,就和Integer.MAX_VALUE - 8(即MAX_ARRAY_SIZE)比较,如果还不够,则就用拼接后的字符串长度,但是最大也不能超过Integer.MAX_VALUE。(有一个newCapacity <= 0的判断,是考虑到value.length << 1变负数;至于扩容一倍还要+2,个人以为是为了提高性能,普遍计算得出,如果有不同理解,欢迎大家评论)

走近Java之幕后的String

走近Java之幕后的String

第三步,调用str.getChars()方法,将入参字符串拼接到现有的字符数组后面,实际操作是调用本地方法

System.arraycopy()。
走近Java之幕后的String

第四步,记录下字符个数,最后返回当前StringBuilder对象。

第五步,拼接字符串”bbb”,重复第二步到第四步,

最后,调用StringBuilder的toString方法,去掉多余的空字符,返回一个当前累计字符长度的String对象,

其实也是调用本地方法System.arraycopy()。复制一个新的字符数组。正好符合String的不变类特性。

走近Java之幕后的String

走近Java之幕后的String

走近Java之幕后的String