2013-08-04 21 views
6

Warum String druckt nicht, was es in einem kleinen CodeWarum StringBuilder nicht druckt?

public final class Test1 { 

    public void test() { 
     System.out.println(setFin().toString()); 
    } 

    protected StringBuilder setFin() { 
     StringBuilder builder = new StringBuilder(); 
     try { 
      builder.append("John"); 
      return builder.append("Ibrahim"); 
     } finally { 
      System.out.println("In finaly"); // builder.append("-DarElBeida"); 
      builder = null; 
     } 
    }  

    public static void main(String args[]){ 
     new Test1().test(); 
    } 
} 

In der letzten Anweisung ausgeführt in setFin() (im finally Block) Ich null zu builder, aber mein Code druckt "In finally" und dann "JohnIbrahim" habe zugewiesen gedruckt werden soll . Kann mir jemand erklären, was hier vor sich geht?

+1

Dies ist grausamer Code. Wahrscheinlich möchten Sie nur lesen http://docs.oracle.com/javase/tutorial/essential/exceptions/finally.html – nes1983

Antwort

5

Wenn es eine return Anweisung innerhalb des try Blocks gibt, führt es den finally Block aus, bevor es tatsächlich zurückkehrt.

Und die Methode nicht null zurückkehrt, weil die return Anweisung einen Hinweis auf die tatsächliche Objekt String hält, nicht auf die Variable builder.

builder == null Einstellung nicht löschen Sie die String selbst, es fällt nur builder ‚s Verweis darauf.

Dieses Verhalten kann verwirrend sein. Um die Dinge klar könnte es hilfreich sein, zurückzukehren, von außerhalb des try/catch/finally-Block:

StringBuilder builder = new StringBuilder(); 

try { 
    builder.append("John"); 
    builder.append("Ibrahim"); 
} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    builder = null; 
} 

return builder; 
+1

Ich denke, dass die OP ist verwirrt, warum es nicht "null" druckt. –

+0

Nein, er erwartet, dass der Name ohne "in finally" gedruckt wird. – duffymo

+0

Ich denke, die Verwirrung geht darum, warum das nicht 'null' druckt (was Ihre Aussage nicht wirklich erklärt - es wird 'Builder = null' vor der Rückgabe ausgewertet, dann sollte es "null zurückgeben") – Mat

3

Sie kehren zurück builder. Danach setzen Sie builder auf null. Aber es wurde bereits zurückgegeben. Es spielt keine Rolle, was Sie danach mit der Variable machen. Der Rückgabewert ist bereits "gesperrt". Was Sie tun könnten, ist mit dem Objekt, das zurückgegeben wird, zu verwirren. Zum Beispiel wird builder.setLength(0) den gesamten Text entfernen.

In der Theorie könnten Sie auch return null aus dem finally-Block, aber das (Änderung des Rückgabewerts) wird dringend abgeraten.

3

Zurück Wert wird ausgewertet und auf dem Stapel gespeichert vor dem finally Block läuft. Beachten Sie, dass der Wert auf dem Stapel tatsächlich der Wert der StringBuilder Referenz ist. Selbst wenn Sie also builder auf null setzen, ändert sich der ausgewertete return Wert nicht bereits auf dem Stack. Wenn der Rückgabewert jedoch ein Verweis auf ein veränderbares Objekt ist, können Sie das Objekt mutieren, und die Änderungen werden im return-Wert angezeigt.

Für Beispiel, wenn Sie die unten Anweisung im finally Block statt nullifying den Verweis hinzuzufügen:

builder.append("Hrithik Roshan"); 

dann werden Sie, dass der Inhalt in dem Rückgabewert sehen.

Wenn Sie jedoch return die builder wieder aus finally Block, wird die vorherige ausgewertet return Aussage overright. Aber Vorsicht, es ist keine gute Idee.

2

finally wird immer ausgeführt, es sei denn, die JVM stürzt ab oder wird beendet, bevor der try Block beendet wird.

Wenn der try Block aufgrund einer return Anweisung abgeschlossen ist, die Expression des return in einen einzelnen Wert ausgewertet vor den finally Block ausgeführt. Dieser Wert wird gespeichert und zurückgegeben, wenn der finally-Block abgeschlossen ist.

Somit hat die Zuordnung builder = null keine Auswirkung, da die Auswertung builder.append("Ibrahim") bereits beendet ist, wenn die finally ausgeführt wird.

1

builder enthält einen Verweis auf den StringBuilder, den Sie erstellt haben. Wenn Sie builder = null tun, setzen Sie builder, um diese Referenz nicht mehr zu halten. Der StringBuilder selbst existiert noch (zumindest bis zur Speicherbereinigung).

Was passiert, ist, dass Ihre return-Anweisung einen Verweis auf den StringBuilder zurückgibt. Es ist nicht Rückgabe der Variablen builder; es gibt einen Verweis auf die Sache, die builder bezieht sich auf. Auch wenn Sie die Variable löschen, hat die return-Anweisung bereits einen Verweis auf das erstellte Objekt.

Wenn Sie builder in Ihrem finally Block gedruckt haben, wäre es dort Null.

0

Zuerst ausgeführt return Anweisung, die builder.append("Ibrahim") ausführen, die die Referenz StringBuilder zurückgibt. Die Referenz wird auf dem Stapel gespeichert. Dann wurde der finally Block ausgeführt. Sie haben die lokale Variable auf Null gesetzt, aber der Verweis auf StringBuilder Objekt wurde an den Aufrufer übergeben, nachdem die Methode tatsächlich zurückgegeben wurde. Deshalb haben wir alle Werte gedruckt. Der Fehler ist, dass Sie dem builder in finally Block, der nie verwendet wird, einen Wert zuweisen. Der Stapel behält den Wert des Anweisungsoperanden return, bevor er tatsächlich zurückgegeben wurde, d. H. Nach dem Block finally. Wenn Sie keine Referenz von der Methode return null im Block finally zurückgeben möchten, wird der Wert im Stack überschrieben.

} finally { 
    System.out.println("In finaly"); // builder.append("-DarElBeida"); 
    return null; 

} 
Verwandte Themen