2012-06-25 6 views
14
public class Test2 { 

    public static void main(String[] args) { 
     Test2 obj=new Test2(); 
     String a=obj.go(); 

     System.out.print(a); 
    } 


    public String go() { 
     String q="hii"; 
     try { 
      return q; 
     } 
     finally { 
      q="hello"; 
      System.out.println("finally value of q is "+q); 
     } 
    } 

Perché questa stampa hii dopo il ritorno dalla funzione go(), il valore è cambiato in "ciao" nel blocco finally?Strano infine comportamento?

l'output del programma è

finally value of q is hello 
hii 
+1

Si potrebbe leggere questo: http://stackoverflow.com/questions/65035/in-java-does-return-trump-finally –

+2

Il valore della variabile locale 'q' è stato modificato in" ciao ", sì. Ma quello che hai restituito era "hii". – maksimov

+0

Per favore guarda la mia nuova risposta ... proviamo a perfezionare questo concetto di più .. – Ahmad

risposta

27

Questo perché si ha restituito un valore che è stato valutato da q prima che è stato modificato il valore della q nel blocco finally. Hai restituito q, che ne ha valutato il valore; poi hai cambiato q nel blocco finally, che non ha influenzato il valore caricato; quindi il reso completato, utilizzando il valore valutato.

Non scrivere codice complicato come questo. Se confonde il tizio che l'ha scritto, immagina i problemi che causerà il prossimo ragazzo, qualche anno lungo la pista quando sei da un'altra parte.

+0

ma il valore viene restituito dopo l'esecuzione del blocco finally .. so – Harinder

+1

@Dennis Il valore da restituire è stato caricato prima dell'esecuzione del blocco finally. L'ho già detto. – EJP

+1

@Dennis sì, ma in 'finally' sei già _past_ l'istruzione' return', non immediatamente prima. – maksimov

0

[Modificato dopo il commento dell'EJP, la mia prima risposta non ha risposto alla domanda ed era anche sbagliata.]
Ora la mia risposta dovrebbe essere corretta spiegando che come il blocco try e il blocco finally si completa normalmente viene restituito q. E il motivo per cui il valore "hii" viene restituito è spiegato nella risposta EJPs. Sto ancora cercando una spiegazione nel JLS.

Dai un'occhiata alla JLS 14.20.2 Execution of try-catch-finally

Un'istruzione try con un blocco finally viene eseguito dal primo l'esecuzione del blocco try. Poi v'è una scelta:

Se l'esecuzione del blocco try viene completato normalmente, quindi il blocco finally viene eseguito, e quindi v'è una scelta:
Se il blocco finally completa normalmente, quindi try completa normalmente.
[...]

e JLS 14.17 The return Statement

Una dichiarazione di ritorno con un'espressione tenta di trasferire il controllo al invoker del metodo che lo contiene; il valore dell'Espressione diventa il valore dell'invocazione del metodo. Più precisamente, l'esecuzione di tale dichiarazione di ritorno valuta innanzitutto l'espressione. Se la valutazione dell'espressione termina in modo brusco per qualche motivo, la dichiarazione di reso viene completata improvvisamente per tale motivo. Se valutazione dell'espressione termina normalmente, producendo un valore V, allora l'istruzione return completa bruscamente, il motivo è un ritorno con valore V

E:

Le descrizioni precedenti dire "tenta di trasferire control "piuttosto che solo" transfer control "perché se ci sono delle istruzioni try (§14.20) all'interno del metodo o costruttore i cui blocchi try contengono l'istruzione return, allora tutte le clausole finally di quelle try vengono eseguite, nell'ordine, più interno a più esterno, prima che il controllo sia trasferito all'invocatore del metodo o costruttore. Il completamento brusco di una clausola finally può interrompere il trasferimento del controllo avviato da una dichiarazione di ritorno.

+1

In che modo risponde esattamente la domanda? – EJP

+0

Ancora non risponde alla domanda. 'q' è * non * restituito. Il valore * di q quando è stata eseguita l'istruzione return * viene restituito. – EJP

4

return rendimenti valore non di riferimento. Quando return q; viene eseguito nel valore corrente catch di q, il riferimento viene memorizzato in cache in base al metodo. Quindi, anche se nel blocco finally riassegnerai q con un nuovo valore, questo non influisce sul valore già memorizzato nella cache in base al metodo.

Se si desidera aggiornare il valore che dovrebbe essere restituito si dovrà utilizzare un altro return nella vostra finally blocco come

} finally { 
    q = "hello"; 
    System.out.println("finally value of q is " + q); 

    return q;//here you set other value in return 
} 

altro modo di influenzare valore restituito è cambiando stato di oggetto in cache. Ad esempio, se q era un List, potremmo aggiungere un nuovo elemento (ma notare che cambiare lo stato non equivale a riassegnare una nuova istanza, proprio come possiamo cambiare lo stato della variabile final, ma non possiamo riassegnarlo).

} finally { 
    q.add(new Element); //this will place new element (update) in List 
    //object stored by return because it is same object from q reference 
    System.out.println("finally value of q is " + q); 
} 
+0

'Valore (oggetto) + da + riferimento, non riferimento esatto', 'leggi/salva oggetto da riferimento' e 'oggetto memorizzato in risposta' non hanno significato. Non una risposta Probabilmente c'è una risposta qui dentro che lotta per uscire, ma la terminologia è talmente confusa che non viene trasmesso alcun significato. – EJP

2

Infine, viene eseguito dopo il ritorno ma prima che il metodo ritorni effettivamente al chiamante. Questo è analogo al lancio. Succede dopo il lancio e prima di uscire dal blocco. Il valore di ritorno è già impostato in alcuni registri leggendo la variabile q. Se q fosse mutabile, potresti finalmente mutarlo e vedresti quel cambiamento nel chiamante. Perché funziona in questo modo? Per uno, è probabilmente il meno complicato da implementare. Due, ti dà la massima flessibilità. È possibile sovrascrivere il valore restituito in infine con un ritorno esplicito. La sua conservazione per impostazione predefinita ti consente di scegliere un comportamento.

0

Provare a utilizzare StringBuffer anziché String e si vedrà la modifica .... sembra che l'istruzione return blocchi l'oggetto che deve essere restituito e non il riferimento. Si potrebbe anche provare a verificare questo stampando il codice hash di:

  • oggetto che viene restituito da go()
  • oggetto in fine
  • oggetto stampato da main()

    public static void Main (string [] args) {

    Test obj=new Test(); 
         StringBuffer a=obj.go(); 
         System.out.print(a); 
        } 
        public StringBuffer go() { 
         StringBuffer q=new StringBuffer("hii"); 
         try { 
          return q; 
         } 
         finally { 
          q=q.append("hello"); 
          System.out.println("finally value of q is "+q); 
         } 
        } 
    
+0

'Blocca l'oggetto che deve essere restituito' non ha significato. Non una risposta – EJP

-1

Beh, quello che ho trovato è come segue,

Return restituisce effettivamente un valore e viene copiato in String a=obj.go();, prima che l'esecuzione passi a Finally.

Consente di verificarlo seguendo gli esperimenti.

public class Test2 { 

    public static void main(String[] args) { 
    Test2 obj=new Test2(); 
    String a=obj.go(); 

    System.out.print(a); 
    } 


    public String go() { 
    String q="hii"; 
    try { 
     return q; 
    } 
    finally { 
     q="hello"; 
     System.out.println("finally value of q is "+q); 
    } 
} 

l'output del programma è

infine valore di q è ciao

hii

e se prendiamo StringBuffer invece di stringa come segue,

public class Test2 { 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 

     Test2 obj=new Test2(); 
     StringBuffer a=obj.go(); 

     System.out.print(a); 
    } 


    public StringBuffer go(){ 
     StringBuffer q=new StringBuffer("hii"); 
     try{ 

      return q; 
     } 
     finally{ 

      q.replace(0, q.length(), "hello"); 
      System.out.println("finally value of q is "+q); 
      /*return q1;*/ 

     } 

    } 
} 

L'comesout uscita sia,

infine valore di q è ciao

ciao

ed infine se prendiamo int invece di stringa come segue,

public class Test2 { 

    public static void main(String[] args) { 
     // TODO Auto-generated method stub 

     Test2 obj=new Test2(); 
     int a=obj.go(); 

     System.out.print(a); 
    } 


    public int go(){ 
     int q=1; 
     try{ 

      return q; 
     } 
     finally{ 

      q=2; 
      System.out.println("finally value of q is "+q); 
      /*return q1;*/ 

     } 

    } 
} 

l'uscita è

infine valore di q è 2

       **Ananlysis** 

1.In primo caso, restituire indirizzo copiato di stringa in variabile un, poi excecution passa a Finally dove viene modificato String. Ma dal momento che in caso di stringhe non possiamo manipolare alcuna stringa, viene costruita una nuova stringa. Quindi nella variabile viene salvato un indirizzo della stringa originale, che viene stampato.

2.In secondo caso, restituire l'indirizzo copiato di StringBuffer nella variabile a e infine questo oggetto StringBuffer viene manipolato, piuttosto che ne viene creato uno nuovo. quindi il valore che è stato memorizzato nella variabile a viene manipolato, come mostrato nell'istruzione di stampa.

3. Nel terzo caso, il valore di int viene copiato nella variabile a, prima che l'esecuzione vada definitivamente. e quindi un ottiene il valore di 1. e quindi in definitiva abbiamo modificato il valore di q che non cambia comunque il valore di a.

+0

giustamente.non hai letto la tua risposta ... – Ahmad

+0

I tuoi primi due esempi sono entrambi irrilevanti. Il primo è semplicemente un codice errato, poiché String.repace() non modifica il valore, ne restituisce uno nuovo che stai buttando via. Il secondo fa mutare il valore, ma poiché questo non è ciò che l'OP sta facendo, non riesco a vedere il punto. Il terzo ripete semplicemente ciò che l'OP sta chiedendo, e ripete la risposta che era già stata data. – EJP

0

Che cos'è il blocco?

-By definition from Java "Il blocco finally viene eseguito sempre all'uscita del blocco try, in modo da garantire che il blocco finally venga eseguito anche se si verifica un'eccezione imprevista."

Quindi, stampa "il valore finale di q è ciao" non appena esiste il blocco try e va alla riga System.out.print (a); e stampa il valore restituito dal metodo go().

Se si dispone di un debugger come netbeans o eclipse, può essere analizzato mantenendo il punto di interruzione e risvegliando il codice.