java中无分配的字符串连接

java中无分配的字符串连接,java,string,memory,concatenation,allocation,Java,String,Memory,Concatenation,Allocation,有没有一种方法可以在不分配内存的情况下连接两个字符串(不是final) 例如,我有两个字符串: final String SCORE_TEXT = "SCORE: "; String score = "1000"; //or int score = 1000; 当我连接这两个字符串时,将创建一个新的String对象 font.drawMultiLine(batch, SCORE_TEXT + score, 50f, 670f);//this creates new string each ti

有没有一种方法可以在不分配内存的情况下连接两个字符串(不是final)

例如,我有两个字符串:

final String SCORE_TEXT = "SCORE: ";
String score = "1000"; //or int score = 1000;
当我连接这两个字符串时,将创建一个新的
String
对象

font.drawMultiLine(batch, SCORE_TEXT + score, 50f, 670f);//this creates new string each time
由于这是在主游戏循环中完成的(在一秒钟内执行约60次),因此有很多分配


我可以不分配就这样做吗?

第一次不理解这个问题。您是否尝试过使用以下方法

SCORE_TEXT.concat(score);

我不认为你可以在没有内存分配的情况下填充一个值。。您最好创建一个全局字符串变量,并向其提供SCORE_TEXT+SCORE的值。在font.drawMultiLine()方法中使用该全局字符串变量

通过这种方式,您可以最大限度地减少分配的内存量,因为内存只分配一次,同一位置会再次更新。

drawMultiLine
不接受
字符串,而是接受
CharSequence
。因此,您可能会实现自己的
CharSequence
,它实际上并不连接两个字符串。以下是实施草案:

public class ConcatenatedString implements CharSequence {
    final String left, right;
    final int leftLength;

    public ConcatenatedString(String left, String right) {
        this.left = left;
        this.right = right;
        this.leftLength = left.length();
    }

    @Override
    public int length() {
        return leftLength+right.length();
    }

    @Override
    public char charAt(int index) {
        return index < leftLength ? left.charAt(index) : right.charAt(index-leftLength);
    }

    @Override
    public CharSequence subSequence(int start, int end) {
        if(end <= leftLength)
            return left.substring(start, end);
        if(start >= leftLength)
            return right.substring(start-leftLength, end-leftLength);
        return toString().substring(start, end);
    }

    @Override
    public String toString() {
        return left.concat(right);
    }
}

在您的案例中,
drawMultiline
只需要
length
charAt
方法。使用
ConcatenatedString
只创建一个新对象。相反,当您使用
SCORE\u TEXT+SCORE
时,您会创建一个临时
StringBuilder
,它在内部创建
char[]
数组,复制输入符号,根据需要调整数组大小,然后创建最终的
String
对象,创建新的
char[]
数组并再次复制符号。因此,
ConcatenatedString
可能会更快。

显而易见的解决方案是不要在每一帧上重新创建输出
字符串,而只是在它发生变化时

一种方法是将其存储在主循环之外的某个位置,并在某个事件发生时进行更新,即“分数”实际发生变化。在主循环中,您只需使用预先创建的
字符串

如果您不能/或不希望使用这种基于事件的方法,则始终可以存储“先前”分数,并且仅当先前分数与当前分数不同时才连接新字符串


根据你的分数实际变化的频率,这将减少大部分的重新分配。当然,除非分数以60 fps的速度变化,在这种情况下,整个分数是完全静音的,因为没有人能够阅读您正在打印的文本。

字符串在Java中是不可变的。使用StringBuilder

这是否真的会导致性能问题,或者您正在这样做?是的,由于gc,它实际上会导致性能问题。游戏适用于移动设备,在速度较慢的设备上,gc会导致fps下降…@Kenneth Clark,“字符串格式”会创建一些新对象。例如,
格式化程序
模式
…字符串生成器或缓冲区,直接写入,无需concat
sb.toString()创建新字符串使用已实例化的
res
对象,而不是在flyscore上关联的对象不是静态字符串,而是动态字符串created@nuno,这与编写
String res=SCORE\u TEXT+SCORE
完全相同:javac编译器有效地生成相同的字节码。第一次不理解这个问题-编辑您的建议是不可能的,因为只有在调用
toString
子序列
时,SCORE才是动态字符串。但在您的情况下不太可能。但是,等等,
new ConcatenatedString
,这也在创建新对象吗?它只是一个新对象。当您使用
SCORE\u TEXT+SCORE
时,您至少创建了四个对象(可能更多)并复制了符号数组。我不知道,我认为它只创建了一个新对象,我想我需要更多地阅读字符串连接…这实际上是目前为止最好的建议。但我认为更好的办法是分别画每根线。我会再打一次平局,但我认为这比很多平局要好得多allocations@pedja您也可以这样做,但是您可能需要手动对齐两个字符串,这在您的情况下可能是可行的,因为第一个字符串是静态的。
font.drawMultiLine(batch, new ConcatenatedString(SCORE_TEXT, score), 50f, 670f);