2009-07-27 6 views
5

Esta es una pregunta que surgió principalmente de pura curiosidad (y que mató un tiempo). Estoy preguntando específicamente sobre Java en aras de la concreción.¿Qué ocurre durante la compilación y el tiempo de ejecución al concatenar una cadena vacía en Java?

¿Qué ocurre, en la memoria, si concatenar una cadena (cualquier cadena) con una cadena vacía, por ejemplo:

String s = "any old string"; 
s += ""; 

Yo sé que aun después, el contenido de s seguirán siendo "cualquier cadena de edad" , ya que una cadena ASCII vacía se almacena en la memoria como un nulo ASCII (ya que, al menos en Java, las cadenas siempre terminan en nulo). Pero tengo curiosidad por saber si Java (¿el compilador? ¿La VM?) Realiza la optimización suficiente para saber que s no se modificará, y puede omitir completamente esa instrucción en el bytecode, o si ocurre algo diferente en los tiempos de compilación y ejecución.

Respuesta

16

¡Es tiempo de bytecode!

class EmptyString { 
    public static void main(String[] args) { 
     String s = "any old string"; 
     s += ""; 
    } 
} 

javap -c EmptyString:

 
Compiled from "EmptyString.java" 
class EmptyString extends java.lang.Object{ 
EmptyString(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String any old string 
    2: astore_1 
    3: new  #3; //class java/lang/StringBuilder 
    6: dup 
    7: invokespecial #4; //Method java/lang/StringBuilder."":()V 
    10: aload_1 
    11: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    14: ldc  #6; //String 
    16: invokevirtual #5; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 
    19: invokevirtual #7; //Method java/lang/StringBuilder.toString:()Ljava/lang/String; 
    22: astore_1 
    23: return 

} 

Se puede ver que += provoca una StringBuilder que se creará con independencia de lo que es la concatenación, por lo que no se puede optimizar en tiempo de ejecución.

Por otro lado, si se pone ambos literales de cadena en la misma expresión, que se concatenan por el compilador:

class EmptyString { 
    public static void main(String[] args) { 
     String s = "any old string" + ""; 
    } 
} 

javap -c EmptyString:

 
Compiled from "EmptyString.java" 
class EmptyString extends java.lang.Object{ 
EmptyString(); 
    Code: 
    0: aload_0 
    1: invokespecial #1; //Method java/lang/Object."":()V 
    4: return 

public static void main(java.lang.String[]); 
    Code: 
    0: ldc  #2; //String any old string 
    2: astore_1 
    3: return 

} 
+3

+1 - para greatjustice – Alex

+0

fresco . ¡gracias! –

+1

@mmyers: debe señalar que 1) los bytecode emitidos son (en teoría) específicos del compilador de Java, y 2) el compilador JIT podría (en teoría) optimizar aún más. –

2

que obtendrá una nueva cadena después de ejecutar la línea

s += ""; 

Java asigna un nuevo objeto String y lo asigna a s después de la concatenación de cadenas. Si tiene eclipse a mano (y supongo que puede hacer lo mismo en NetBeans, pero solo he usado eclipse) puede marcar esa línea y ver los ID de objeto del objeto al que apunta antes y después de ejecutar esa linea. En mi caso, el ID de objeto de s antes de esa línea de código era id = 20, y después era id = 24.

Cuestiones relacionadas