2015-05-28 5 views
6

Gibt es eine Möglichkeit, zwei Strings (nicht endgültig) ohne Speicherzuordnung zu verketten?String-Verkettung ohne Zuweisung in Java

Zum Beispiel, ich habe diese beiden Saiten:

final String SCORE_TEXT = "SCORE: "; 
String score = "1000"; //or int score = 1000; 

Wenn ich diese zwei Strings verketten, ein neues String Objekt erstellt wird.

font.drawMultiLine(batch, SCORE_TEXT + score, 50f, 670f);//this creates new string each time 

Da dies im Hauptspiel Schleife getan (ausgeführt ~ 60-mal in einer Sekunde), es gibt eine Menge von Zuweisungen ist.

Kann ich das irgendwie ohne Zuteilung machen?

+3

Führt dies tatsächlich zu einem Leistungsproblem oder machen Sie [vorzeitige Optimierung] (http://c2.com/cgi/wiki?PrematureOptimization)? – Jesper

+1

Ja, es verursacht tatsächlich Leistungsprobleme, wegen der GC. Das Spiel ist für mobile Geräte, und auf langsameren Geräten verursacht GC fps fällt ... – pedja

+0

@Kenneth Clark, String-Format erstellt ein paar neue Objekte. z.B. 'Formatter',' Pattern' ... – pedja

Antwort

4

Die offensichtliche Lösung besteht darin, die Ausgabe String nicht auf jedem Frame neu zu erstellen, sondern nur, wenn es sich ändert.

Ein Weg, dies zu tun ist, es irgendwo außerhalb Ihrer Hauptschleife zu speichern und es zu aktualisieren, wenn ein bestimmtes Ereignis eintritt, d. H. Die "Punktzahl" ändert sich tatsächlich. In Ihrer Hauptschleife verwenden Sie dann einfach das bereits erstellte String.

Wenn Sie diese ereignisbasierte Methode nicht verwenden können oder wollen, können Sie immer die "vorherige" Bewertung speichern und nur eine neue Zeichenfolge verketten, wenn sich die vorherige Bewertung von der aktuellen Bewertung unterscheidet.

Abhängig davon, wie oft sich Ihr Score tatsächlich ändert, sollte dies die meisten Neuzuweisungen ausschließen. Es sei denn natürlich ändert sich die Punktzahl bei 60 fps, in diesem Fall ist dieser ganze Punkt völlig stumm, weil niemand den zu druckenden Text lesen kann.

+0

das ist eigentlich der beste Vorschlag bisher. Aber ich denke, dass es sogar noch besser ist, jede Saite einzeln zu zeichnen. Ich werde noch einen Draw-Call haben, aber ich denke, es ist viel besser als viele Zuweisungen – pedja

+0

@pedja Sie könnten das auch tun, aber Sie müssten wahrscheinlich die beiden Zeichenfolgen dann manuell ausrichten, was in Ihrem Fall machbar ist, weil Die erste Zeichenfolge ist statisch. –

+0

ja, genau, tnx, ich werde deine Antwort akzeptieren – pedja

1

Ich habe die Frage beim ersten Mal nicht verstanden. Haben Sie Folgendes versucht?

SCORE_TEXT.concat(score); 
+0

'sb.toString();' erstellt neuen String – pedja

+0

benutze das 'res' Objekt, das bereits instanziiert ist, anstatt auf der Fly – nuno

+0

Score ist keine statische Zeichenfolge, es ist dynamisch erstellt – pedja

0

Ich glaube nicht, dass Sie für sie einen Wert ohne Zuweisung eines Speicherbevölkern können .. was am besten können Sie tun, ist eine globale String-Variable zu schaffen und den Wert von SCORE_TEXT + ihm punkten. Verwenden Sie diese globale Zeichenfolgenvariable in der font.drawMultiLine() -Methode.

Auf diese Weise können Sie die Speichermenge minimieren, die zugewiesen wird, da Speicher nur einmal zugewiesen wird und derselbe Speicherort erneut aktualisiert wird &.

+0

Was Sie vorschlagen, ist unmöglich, weil Score ist dynamische Zeichenfolge – pedja

1

Seems thatdrawMultiLine akzeptiert keine String, aber CharSequence. So können Sie wahrscheinlich Ihre eigene CharSequence implementieren, die nicht wirklich zwei Strings verkettet. Hier ist der Entwurf Umsetzung:

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

Verwenden Sie es wie folgt aus:

font.drawMultiLine(batch, new ConcatenatedString(SCORE_TEXT, score), 50f, 670f); 

intern in Ihrem Fall drawMultiline braucht nur die length und charAt Methoden. Mit ConcatenatedString erstellen Sie nur ein neues Objekt. Wenn Sie dagegen SCORE_TEXT + score verwenden, erstellen Sie ein temporäres StringBuilder, das intern char[] Array erstellt, die Eingabesymbole kopiert, das Array bei Bedarf ändert und anschließend das endgültige String-Objekt erstellt, das das neue char[]-Array erstellt und die Symbole erneut kopiert. Daher ist es wahrscheinlich, dass ConcatenatedString schneller wird.

+0

aber 'left.concat (rechts);' erstellt einen neuen String – pedja

+0

Nur wenn 'toString' oder' subSequence' ist namens. Aber es ist in deinem Fall unwahrscheinlich. –

+0

ok, tnx, ich werde versuchen, – pedja

0

String ist in Java unveränderlich. Verwenden Sie StringBuilder