2009-03-02 5 views
11

A menudo me he preguntado esto, hay un costo de rendimiento de dividir una cadena en varias líneas para aumentar la legibilidad al asignar inicialmente un valor a una cadena. Sé que las cadenas son inmutables y, por lo tanto, se necesita crear una nueva cadena cada vez. Además, el costo de rendimiento es realmente irrelevante gracias al hardware realmente rápido de hoy (a menos que esté en un ciclo diabólico). Por ejemplo:¿Cuál es el costo de rendimiento de asignar un único valor de cadena usando + '

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."; 

¿Cómo maneja esto el compilador de JVM o .Net y otras optimizaciones? ¿Creará una sola cadena? ¿O creará 1 cadena y luego una nueva concatenación del valor y luego otra concatenando nuevamente los valores?

Esto es por mi propia curiosidad.

Respuesta

28

Esto es garantizado por la especificación de C# para ser idéntico a la creación de la cadena en un solo literal, porque es una constante en tiempo de compilación. Desde la sección 7.18 de la especificación C# 3:

Siempre que una expresión cumple los requisitos enumerados anteriormente, la expresión se evalúa en tiempo de compilación. Esto es cierto incluso si la expresión es una sub-expresión de una expresión más grande que contiene construcciones no constantes.

(Ver la especificación de los detalles exactos de "los requisitos enumerados anteriormente" :)

La especificación del lenguaje Java especifica que la parte inferior de section 3.10.5:

cadenas constantes calculadas por las expresiones (§15.28) se calculan en tiempo de compilación y luego se tratan como si fueran literales.

+0

Gracias Jon. Pensé mucho y mi curiosidad se despertó. Gracias de nuevo. – uriDium

3

Por lo que puedo recordar, esto no creará múltiples cadenas, solo una.

5

Sin compensación de rendimiento. La optimización del compilador combinará eso con una sola cadena (al menos en Java).

+0

Lo mismo para el compilador de C#. –

2

Siempre que todas las cadenas sean constantes (como lo son en su ejemplo), en Java (e imagino C#) el compilador lo convierte en una sola cadena.

Solo obtiene problemas de rendimiento con + si concatena muchas cadenas dinámicas, como en un bucle. En este caso use StringBuilder o StringBuffer.

14

De hecho, en Java, el compilador convertirá el String en una constante.

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

se compila en:

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 

} 

Como se puede ver, una sola línea está cargado en en la línea 4, en lugar de múltiples String casos están cargando en

Editar:. El archivo fuente se compiló usando javac versión 1.6.0_06.Mirando The Java Language Specification, Third Edition, (y la misma sección mencionada en Jon Skeet's answer), no pude encontrar ninguna referencia sobre si un compilador debe concatenar una línea múltiple String en un solo String, por lo que este comportamiento probablemente sea el compilador específico de la implementación.

+0

Puede ver lo que hace una versión particular de un compilador, pero ¿qué pasa con la especificación? Cómo puedo saber*? –

6

Pruébelo usted mismo. En código C# (equivalente en Java podría funcionar también):

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

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

verá que el resultado es true.

Como acotación al margen, se verá que la cadena también está internado en grupo de cadena del tiempo de ejecución:

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

Puede probar, pero ¿qué pasa con la especificación? Cómo puedo saber*? –

+0

La primera parte (igualdad de referencia de cadena) se rige por el compilador de C# y se especifica el comportamiento. Sin embargo, la segunda parte (literal de cadena interna) está controlada por CLR y no se garantiza el comportamiento en todas las implementaciones y plataformas. –

3

El equivalente .NET IL para complementar coobird's answer:

Para el código 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 compilación de depuración 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 
} 

Así que, como pueden ver, es una cadena.

+0

Puedo verlo, pero ¿siempre sé que va a suceder? (Bueno, lo hago si miro la respuesta de otra persona). –

+0

Punto justo. Sin embargo, en este caso, este es el comportamiento especificado, por lo que todas las implementaciones del compilador de C# son * supposed * para funcionar de esta manera. –

0

Descargo de responsabilidad: Esto es cierto para Java. Supongo que es cierto para C#

No solo javac creará una sola cadena sino que la JVM usará una cadena para todas las demás cadenas que contengan el mismo texto.

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: serán el mismo objeto String en tiempo de ejecución, incluso si son de diferentes clases en diferentes frascos, compilados por diferentes compiladores.

Cuestiones relacionadas