为什么会有这种性能差异

why is that performance diffrence

import java.util.Calendar;

public class MainClass
{
  public static void main(String args[])
  {
    String s = new String("ABCD");

    long swapStart = Calendar.getInstance().getTimeInMillis();
    for(int i=0; i<s.length()/2;i++)
    {
        char left = s.charAt(i);
        char right = s.charAt(s.length()-(i+1));
        s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());
    }
    long swapStop = Calendar.getInstance().getTimeInMillis();

    long bufStart = Calendar.getInstance().getTimeInMillis();
    String str = new String("ABCD");
    StringBuffer strBuf = new StringBuffer(str);
    str = strBuf.reverse().toString();
    long bufStop = Calendar.getInstance().getTimeInMillis();

    System.out.println(swapStop-swapStart);
    System.out.println(bufStop-bufStart);
  }
}

***** 在字符串的新字符串 ("ABCD") 中,如果我提供一个非常大的字符串,比如说几百个字母数字

*****在控制台输出是:

61
0

***** 字符串缓冲区始终以 0 毫秒计算,我的字符交换算法根据字符串大小进行计算

问。为什么我的交换算法不能在 0 毫秒内完成,为什么 stringbuffer 总是在 0 毫秒内完成?


我检查了 Java 源代码, StringBuffer.reverse() 实现如下:

public AbstractStringBuilder reverse() {
    boolean hasSurrogate = false;
    int n = count - 1;
    for (int j = (n-1) >> 1; j >= 0; --j) {
        char temp = value[j];
        char temp2 = value[n - j];
        if (!hasSurrogate) {
            hasSurrogate = (temp >= Character.MIN_SURROGATE && temp <= Character.MAX_SURROGATE)
                || (temp2 >= Character.MIN_SURROGATE && temp2 <= Character.MAX_SURROGATE);
        }
        value[j] = temp2;
        value[n - j] = temp;
    }
    if (hasSurrogate) {
        // Reverse back all valid surrogate pairs
        for (int i = 0; i < count - 1; i++) {
            char c2 = value[i];
            if (Character.isLowSurrogate(c2)) {
                char c1 = value[i + 1];
                if (Character.isHighSurrogate(c1)) {
                    value[i++] = c1;
                    value[i] = c2;
                }
            }
        }
    }
    return this;
}

问。请解释代理人的事情。

Q1:存在性能差异,因为您的交换代码创建了很多要操作的 String 对象,而另一个例程直接使用 char 数组并且不需要创建额外的对象。让我们检查一下您的代码行:

s=s.substring(0, i)+right+s.substring(i+1, s.length()-(i+1))+left+s.substring(s.length()-i, s.length());

它做这样的工作:

s = [new String 1] + char + [new String 2] + char + [new String 3]

这是 4 个新的 String 对象(显示的三个对象,加上添加 String 个对象后产生的对象。此外,显示的 3 个新字符串中的每一个都调用了 substring处理时间。此外,您在 for 循环中完成所有这些工作,因此它会针对每个字符重复!

字符串操作方便但昂贵。数组操作是直接的,不需要额外的对象或内存块,因此速度要快得多。

Q2:代理是 unicode 字符的一种特殊情况,创建它是为了处理更长的 unicode 字符。有关详细信息,请参阅 this article。代理项的 hi/low 部分的顺序很重要,因此交换代码将这两个字符颠倒是错误的,因此如果找到它们,它们的顺序将按原样放回去。