append方法的追踪(课堂复现)

append方法的追踪(课堂复现)

将原有的字符串扩展,或是进行不同字符串之间的拼接,往往很容易想到在两个字符串之间直接用“+”号运算来达到目的,而在java中这样的方法会残留些不必要的内容,而推荐使用Stringbuilder或StringBuffer中的append()方法,以下就以StringBuffer为例

public class FeiWuTest {     public static void main(String[] args) {         String s1 = "Wo ";         String s2 = s1 + "shi ";         String s3 = s2+"Fei";         String s4 = s3+"wu";         System.out.println(s4); //这里会比下面多存在"Wo shi "、"Wo shi Fei"从而浪费空间           StringBuffer sb1 = new StringBuffer("Wo ");         sb1.append("shi ");         sb1.append("Fei");         sb1.append("wu");         System.out.println(sb1);     } } 

以第一个append为例

首先构造的一个sb1这个对象

public StringBuffer(String str) {     super(str.length() + 16);     append(str); } 

调用父类构造

AbstractStringBuilder(int capacity) {     value = new char[capacity]; } 

即构建出一个长度为输入字符串的长度+16,这里我写入的是”Wo “,所以对用传入的长度为19.(如果没有传入字符串,对应构造方法,传入的长度为16)

进入 append()方法,这里是构建第一个对象sb1时append

@Override public synchronized StringBuffer append(String str) {     toStringCache = null;     super.append(str);     return this; } 

其中

private transient char[] toStringCache; 

super.sppend(str);调用父类AbstractStringBuilder的append方法,其中str="Wo "

public AbstractStringBuilder append(String str) {     if (str == null)//flase         return appendNull();     int len = str.length();//len=19     ensureCapacityInternal(count + len)     str.getChars(0, len, value, count);     count += len;     return this; } 

其中

int count;//未赋值,默认为零 

进入ensureCapacityInternal()传入的参数值为19

这里就开始了扩容操作

private void ensureCapacityInternal(int minimumCapacity) {     // overflow-conscious code     if (minimumCapacity - value.length > 0) {//true         value = Arrays.copyOf(value,                 newCapacity(minimumCapacity));     } } 

其中value

char[] value; 

value = Arrays.copyOf(value,newCapacity(minimumCapacity));

这是"类名."的方式调用,括号内newCapacity(minimumCapacity)大概最后还是返回这个minimumCapacity,也就是19

具体代码

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; } 

看到copyOf()方法

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; } 

里面的arrycopy就不用说了,就是将传进来的字符数组复制一份给了copy这个数组然后返回,到这里AbstractStringBuilder的append方法中的value就被赋值了

之后的这个 str.getChars(0, len, value, count);在上一篇博文中也提到了,主要就是将这个value给赋值出来

最后两次return

至此”Wo “就被传入了sb1这个对象中,也就是构建出了一个StringBuffer对象sb1

现在我们进去测试类中的第一个append方法

@Override public synchronized StringBuffer append(String str) {     toStringCache = null;     super.append(str);     return this; } 

这里传入的str也就是”shi “

这里append方法跟上面构建是的方法是一样的

public AbstractStringBuilder append(String str) {     if (str == null)//flase         return appendNull();     int len = str.length();     ensureCapacityInternal(count + len);     str.getChars(0, len, value, count);     count += len;     return this; } 

又是一步一步调用,确定字符串应该扩容的长度,然后经历getChats等直到用arraycopy将新传入的字符串复制到了原有字符串的后面,从此对象sb1的内容成了”Wo shi “,之前的”Wo “就没有东西指向了,而到了第二次append(“Fei”);就使sb1的内容变成了”Wo shi Fei“,之前的”Wo shi “就也没有了谁去指向就被回收了。

而相反使用”+“这样的方法,之前几次组合的字符串都有被指向,一直不会消失,如果多次使用这样的方式拼接,有很大的弊端。

最后将输出结果也贴一下吧

public class FeiWuTest {     public static void main(String[] args) {         String s1 = "Wo ";         String s2 = s1 + "shi ";         String s3 = s2+"Fei";         String s4 = s3+"wu";         System.out.println(s4);            StringBuffer sb1 = new StringBuffer("Wo ");         sb1.append("shi ");         sb1.append("Fei");         sb1.append("wu");         System.out.println(sb1);     } }   /* Wo shi Feiwu Wo shi Feiwu  Process finished with exit code 0 */  

这篇也就是粗略地回忆一下讲过的这玩意

至于System.out,println这玩意有兴趣可以看看我上篇的”瞎撞“

版权声明:玥玥 发表于 2021-03-28 3:53:30。
转载请注明:append方法的追踪(课堂复现) | 女黑客导航