Java 为什么是;。混凝土(细绳)";比”快得多+&引用;?

Java 为什么是;。混凝土(细绳)";比”快得多+&引用;?,java,string,performance,string-concatenation,Java,String,Performance,String Concatenation,我编写的一些代码比较了将字符串与“string”+“string”连接所需的时间: 其中str==“string” 我得到的输出与此一致,尽管平均差通常接近61纳秒: 字符串str2=str+str:118.57349468纳秒 String str2=str.concat(str):52.36809985纳秒 .concat比+快66.20539483纳秒 这表明,即使循环并赋值给新字符串,.concat也比+快两倍以上。当我使用更长的字符串时(str==“这是一个非常长的字符串,非常长”),

我编写的一些代码比较了将字符串与
“string”+“string”
连接所需的时间:

其中
str==“string”

我得到的输出与此一致,尽管平均差通常接近61纳秒:

字符串str2=str+str
:118.57349468纳秒

String str2=str.concat(str)
:52.36809985纳秒

.concat
+
快66.20539483纳秒

这表明,即使循环并赋值给新字符串,
.concat
也比
+
快两倍以上。当我使用更长的字符串时(
str==“这是一个非常长的字符串,非常长”
),它的速度会快大约三倍。这尤其奇怪,因为如果
.concat
更快,他们不应该让
+
编译成
.concat

我的主要问题是:为什么
.concat
更快?

完整代码,以防您想要运行它并进行实验:

public class TimeCompare
{
    public static void main(String[] args)
    {
        final long times = 100000000L;

        String str = "String";

        long start1 = System.nanoTime();

        for(int i = 0; i < times; i++)
        {
            String str2 = str + str;
        }

        long end1 = System.nanoTime();
        long time1 = end1 - start1;

        System.out.println((double)(time1) / times);
        System.out.println();

        long start2 = System.nanoTime();

        for(int i = 0; i < times; i++)
        {
            String str2 = str.concat(str);
        }

        long end2 = System.nanoTime();
        long time2 = end2 - start2;

        System.out.println((double)(time2) / times);
        System.out.println();

        System.out.println(".concat is faster than \"+\" by " + ((double)(time1 - time2) / times) + " nanoseconds");
    }
}
公共类时间比较
{
公共静态void main(字符串[]args)
{
最终长时间=100000000升;
String str=“String”;
long start1=System.nanoTime();
for(int i=0;i
编辑:回顾这个答案,我现在意识到它是多么的不科学和推测。虽然它不一定是错的,但我对它的正确性不再有信心。


以下是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);
}
“字符串”+“字符串”
编译为
新的StringBuilder().append(“字符串”).append(“字符串”).toString()
append
的源代码使用其超类,
AbstractStringBuilder
,方法:

public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}
用方法的源替换方法调用后:

/////////////////concat

int otherLen = str.length();
if (otherLen == 0) {
    return this;
}

int len = value.length;

char buf[] = ((Object)value.getClass() == (Object)Object[].class)
    ? (T[]) new Object[len + otherLen]
    : (T[]) Array.newInstance(value.getClass().getComponentType(), len + otherLen);

System.arraycopy(value, 0, buf, 0, Math.min(value.length, len + otherLen));

System.arraycopy(str.value, 0, buf, len, str.value.length);

return new String(buf, true);

///////////////append

if (str == null) str = "null";
int len = str.length();

if (value.length + len - value.length > 0)
{
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - value.length + len < 0)
        newCapacity = value.length + len;
    if (newCapacity < 0) {
        if (value.length + len < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }

    value = ((Object)value.getClass() == (Object)Object[].class)
        ? (T[]) new Object[newCapacity]
        : (T[]) Array.newInstance(value.getClass().getComponentType(), newCapacity);

    System.arraycopy(value, 0, value, 0, (value.length <= newCapacity) ? value.length : newCapacity;
}

if (0 < 0) {
    throw new StringIndexOutOfBoundsException(0);
}
if (len > str.value.length) {
    throw new StringIndexOutOfBoundsException(len);
}
if (0 > len) {
    throw new StringIndexOutOfBoundsException(len - 0);
}
System.arraycopy(str.value, 0, value, value.length, len - 0);

count += len;
return this;
您可以看到,几乎在所有情况下,一个concat都比一个append快,并且
+
编译为两个append和一个
toString


1:


@SotiriosDelimanolis问
+=
是否与
.concat
相同,我问的是为什么
.concat
+
快。但我想这是你应该关闭的,根据这个:好的。据英国《金融时报》报道,它不应该是一个复制品。另一个选择是关闭它,因为它基于一个有缺陷的基准。
public AbstractStringBuilder append(String str) {
    if (str == null) str = "null";
    int len = str.length();
    ensureCapacityInternal(count + len);
    str.getChars(0, len, value, count);
    count += len;
    return this;
}
/////////////////concat

int otherLen = str.length();
if (otherLen == 0) {
    return this;
}

int len = value.length;

char buf[] = ((Object)value.getClass() == (Object)Object[].class)
    ? (T[]) new Object[len + otherLen]
    : (T[]) Array.newInstance(value.getClass().getComponentType(), len + otherLen);

System.arraycopy(value, 0, buf, 0, Math.min(value.length, len + otherLen));

System.arraycopy(str.value, 0, buf, len, str.value.length);

return new String(buf, true);

///////////////append

if (str == null) str = "null";
int len = str.length();

if (value.length + len - value.length > 0)
{
    int newCapacity = value.length * 2 + 2;
    if (newCapacity - value.length + len < 0)
        newCapacity = value.length + len;
    if (newCapacity < 0) {
        if (value.length + len < 0) // overflow
            throw new OutOfMemoryError();
        newCapacity = Integer.MAX_VALUE;
    }

    value = ((Object)value.getClass() == (Object)Object[].class)
        ? (T[]) new Object[newCapacity]
        : (T[]) Array.newInstance(value.getClass().getComponentType(), newCapacity);

    System.arraycopy(value, 0, value, 0, (value.length <= newCapacity) ? value.length : newCapacity;
}

if (0 < 0) {
    throw new StringIndexOutOfBoundsException(0);
}
if (len > str.value.length) {
    throw new StringIndexOutOfBoundsException(len);
}
if (0 > len) {
    throw new StringIndexOutOfBoundsException(len - 0);
}
System.arraycopy(str.value, 0, value, value.length, len - 0);

count += len;
return this;
//////////////concat

int len = value.length;
len + otherLen
System.arraycopy(value, 0, buf, 0, Math.min(value.length, len + otherLen));
System.arraycopy(str.value, 0, buf, len, str.value.length);
this.value = value;

/////////////////append

if(value.length + len - value.length > 0)
int newCapacity = value.length * 2 + 2;
if(newCapacity - value.length + len < 0)
if(newCapacity < 0)
System.arraycopy(value, 0, value, 0, (value.length <= newCapacity) ? value.length : newCapacity);
if(0 < 0)
if(len > str.value.length)
if(0 > len)
System.arraycopy(str.value, 0, value, value.length, len - 0);
count += len;
concat
--------
int assignment: 0
int +/-: 0
int comparison: 0
char[] assignment: 1
arraycopy: 0
int *: 0


append
--------
int assignment: 1
int +/-: 5
int comparison: 6
char[] assignment: 0
arraycopy: 0
int *: 1