Domanda

Mi sono spesso chiesto questo, c'è un costo prestazionale di dividere una stringa su più righe per aumentare la leggibilità quando si assegna inizialmente un valore a una stringa. So che le stringhe sono immutabili e quindi una nuova stringa deve essere creata ogni volta. Inoltre, il costo delle prestazioni è in realtà irrilevante grazie all'hardware veramente veloce di oggi (a meno che tu non sia in un ciclo diabolico). Quindi ad esempio:

String newString = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";

In che modo gestisce il compilatore JVM o .Net e altre ottimizzazioni. Creerà una singola stringa? O creerà 1 stringa, quindi una nuova concatenando il valore e poi un'altra concatenando nuovamente i valori?

Questo è per mia curiosità.

È stato utile?

Soluzione

Questo è garantito dalle specifiche C # per essere identiche alla creazione della stringa in un singolo letterale, perché è una costante di compilazione-tempo. Dalla sezione 7.18 della specifica C # 3:

  

Ogni volta che un'espressione soddisfa il   requisiti sopra elencati, il   l'espressione è valutata a   compile-time. Questo è vero anche se il   espressione è una sottoespressione di a   espressione più grande che contiene   costrutti non costanti.

(Vedi le specifiche per i dettagli esatti di " i requisiti sopra elencati " :)

La specifica del linguaggio Java lo specifica nella parte inferiore di sezione 3.10.5 :

  

Stringhe calcolate da costante   le espressioni (& # 167; 15.28) vengono calcolate in   tempo di compilazione e quindi trattati come se   erano letterali.

Altri suggerimenti

In effetti, in Java, il compilatore trasformerà la String in una costante.

class LongLongString
{
    public LongLongString()
    {
        String newString = "This is a really long long long long long" +
            " long long long long long long long long long long long long " +
            " long long long long long long long long long string for example.";
    }

    public static void main(String[] args)
    {
        new LongLongString();
    }
}

È compilato in:

Compiled from "LongLongString.java"
class LongLongString extends java.lang.Object{
public LongLongString();
  Code:
   0:   aload_0
   1:   invokespecial   #1; //Method java/lang/Object."<init>":()V
   4:   ldc #2; //String This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example.
   6:   astore_1
   7:   return

public static void main(java.lang.String[]);
  Code:
   0:   new #3; //class LongLongString
   3:   dup
   4:   invokespecial   #4; //Method "<init>":()V
   7:   pop
   8:   return

}

Come si può vedere, una riga singola viene caricata nella riga 4, anziché caricare più istanze String .

Modifica: il file sorgente è stato compilato usando javac versione 1.6.0_06. Guardando The Java Language Specification, Third Edition , (e la stessa sezione menzionata in La risposta di Jon Skeet ), non sono riuscito a trovare alcun riferimento per stabilire se un compilatore dovrebbe concatenare un String in una singola String , quindi questo comportamento è probabilmente specifico dell'implementazione del compilatore.

Provalo tu stesso. Nel codice C # (funzionerebbe anche Java equivalente):

string x = "A" + "B" + "C";
string y = "ABC";

bool same = object.ReferenceEquals(x, y); // true

Vedrai che il risultato è true .

A parte, vedrai che la stringa è anche internata nel pool di stringhe del runtime:

bool interned = object.ReferenceEquals(x, string.Intern(x)); // true

Nessun compromesso sulle prestazioni. L'ottimizzazione del compilatore lo unirà in un'unica stringa (almeno in Java).

Per quanto posso ricordare, questo non creerà più stringhe, solo quella.

Il .NET IL equivalente da integrare la risposta di coobird :

Per il codice C #:

string s = "This is a really long long long long long" +
    " long long long long long long long long long long long long " +
    " long long long long long long long long long string for example.";
Console.WriteLine(s);

Una compilazione di debug produce:

.method public hidebysig static void Main(string[] args) cil managed
{
  .custom instance void [mscorlib]System.STAThreadAttribute::.ctor()
  .maxstack 1
  .locals init (
      [0] string str)
  L_0000: ldstr "This is a really long long long long long long long long long long long long long long long long long  long long long long long long long long long string for example."
  L_0005: stloc.0 
  L_0006: ldloc.0 
  L_0007: call void [mscorlib]System.Console::WriteLine(string)
  L_000c: ret 
}

Quindi, come puoi vedere, è una stringa.

Fintanto che tutte le stringhe sono costanti (come lo sono nel tuo esempio), in Java (e immagino C #) il compilatore converte questo in una singola stringa.

Si ottengono problemi di prestazioni con + solo se si concatenano molte stringhe dinamiche, ad esempio in un ciclo. In questo caso, utilizzare StringBuilder o StringBuffer.

Dichiarazione di non responsabilità: questo vale per Java. Suppongo che sia vero per c #

Non solo javac creerà una singola stringa, ma JVM utilizzerà una stringa per tutte le altre stringhe che contengono lo stesso testo.

String a = "He" + "llo th"+ "ere";
String b = "Hell" + "o the"+ "re";
String c = "Hello" +" "+"there";
assert a == b; // these are the same String object.
assert a == c; // these are the same String object.

Nota: saranno gli stessi oggetti String in fase di esecuzione anche se si trovano in classi diverse in JARS diversi, compilati da compilatori diversi.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top