2009-07-27 7 views
5

Jest to pytanie, które powstało głównie z czystej ciekawości (i zabicia czasu). Pytam konkretnie o Javę ze względu na konkretność.Co dzieje się podczas kompilowania i uruchamiania podczas łączenia pustego łańcucha w Javie?

Co dzieje się w pamięci, jeśli złączyć ciąg (dowolny ciąg) z pustym ciągiem znaków, np:

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

wiem, że potem, zawartość s nadal będzie „byle string” , ponieważ pusty ciąg ASCII jest przechowywany w pamięci jako tylko null ASCII (ponieważ, przynajmniej w Javie, łańcuchy znaków są zawsze zakończone znakiem NUL). Ale jestem ciekawy, czy Java (kompilator? VM?) Wykonuje wystarczającą optymalizację, aby wiedzieć, że s będzie niezmieniona, i może po prostu całkowicie pominąć tę instrukcję w bajtowym kodzie, lub jeśli coś się dzieje podczas kompilacji i pracy.

Odpowiedz

16

To jest kod bajtowy!

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 

} 

Widać, że += powoduje StringBuilder być tworzone niezależnie od tego, co to złączenie, więc nie mogą być optymalizowane przy starcie.

Z drugiej strony, jeśli można umieścić zarówno napisowych w tej samej wypowiedzi, są one łączone przez kompilator:

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 - dla greatjustice – Alex

+0

chłodnym . Dziękuję Ci! –

+1

@mmyers: powinieneś zauważyć, że 1) emitowane kody bajtowe są (teoretycznie) specyficzne dla Java i 2) kompilator JIT mógłby (teoretycznie) zoptymalizować dalej. –

2

Dostaniesz nowy łańcuch po wykonaniu linii

s += ""; 

Java przydziela nowy obiekt String i przypisuje go do s po konkatenacji strun. Jeśli masz zaćmienie pod ręką (i zakładam, że możesz zrobić to samo w NetBeans, ale używałem tylko zaćmienia), możesz przerwać linię i obserwować identyfikatory obiektów obiektu, które wskazuje przed i po wykonaniu. ta linia. W moim przypadku identyfikator obiektu s przed tym wierszem był id = 20, a potem był id = 24.