Strano infine il comportamento?

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é questo hii stampa dopo essere ritornato dalla funzione go() , il valore è cambiato in “ciao” nel blocco finally?

l’output del programma è

 finally value of q is hello hii 

Questo perché hai restituito un valore che è stato valutato da q prima di aver modificato il valore di 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.

restituisce il valore restituito senza riferimento. Quando return q; viene eseguito in catch valore corrente di q riferimento viene memorizzato nella cache con il metodo come risultato. Quindi, anche se alla finally blocco riassegnerai q con un nuovo valore, non inciderà sul valore già memorizzato dal metodo.

Se vuoi aggiornare il valore che deve essere restituito dovrai usare un altro return nel tuo blocco finally come

 } finally { q = "hello"; System.out.println("finally value of q is " + q); return q;//here you set other value in return } 

Un altro modo per influenzare il valore restituito è cambiando lo stato dell’object memorizzato nella cache. Ad esempio, se q fosse una List , potremmo aggiungere un nuovo elemento (ma noterai che cambiare 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); } 

Finalmente 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à. È ansible sovrascrivere il valore restituito in infine con un ritorno esplicito. La sua conservazione per impostazione predefinita ti consente di scegliere un comportamento.

[ Modificato dopo i commenti 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 a JLS 14.20.2 Esecuzione di try-catch-finally

Un’istruzione try con un blocco finally viene eseguita eseguendo prima il blocco try. Quindi c’è una scelta:

Se l’esecuzione del blocco try viene completata normalmente, viene eseguito il blocco finally e quindi è disponibile una scelta:
Se il blocco finally viene completato normalmente, l’istruzione try viene completata normalmente.
[…]

e JLS 14.17 Dichiarazione di reso

Una dichiarazione di ritorno con un’espressione tenta di trasferire il controllo all’invocatore 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 la valutazione dell’Espressione viene completata normalmente, producendo un valore V, l’istruzione return viene completata bruscamente, il motivo è un ritorno con valore V

E:

Le descrizioni precedenti dicono “tentativi di trasferire il controllo” piuttosto che “controlli di trasferimento” 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 provano essere eseguito, nell’ordine, più a fondo, più esterno, prima che il controllo venga 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.

Prova a usare StringBuffer invece di String e vedrai la modifica …. sembra che l’istruzione return blocchi l’object che deve essere restituito e non il riferimento. Puoi anche provare a verificarlo stampando l’hashcode di:

  • object che viene restituito da go ()
  • object infine
  • object 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); } } 

Cos’è finalmente il blocco?

-Da definizione da Java “Il blocco finally viene eseguito sempre quando il blocco try viene eseguito, 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 hai un debugger come netbeans o eclipse, puoi analizzarlo mantenendo il punto di interruzione e risvegliando il codice.

Bene, quello che ho trovato è il seguente,

Return restituisce effettivamente un valore e viene copiato in String a=obj.go(); , prima che l’esecuzione vada a Finalmente .

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 è

finalmente il valore di q è ciao

hii

e se prendiamo StringBuffer invece di String 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’output è come essere,

finalmente il valore di q è ciao

Ciao

e infine se prendiamo int invece di String 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’output è

infine il valore di q è 2

1

  **Ananlysis** 

1.In primo caso, restituire l’indirizzo copiato di String nella variabile a , quindi l’escetion va 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, restituisce l’indirizzo copiato di StringBuffer nella variabile a , e infine questo object StringBuffer viene manipolato, piuttosto che ne viene creato uno nuovo. quindi il valore che è stato memorizzato nella variabile a viene anche manipolato, come mostrato nell’istruzione print.

3. Nel terzo caso, il valore di int viene copiato nella variabile a , prima che l’esecuzione vada a finire. e quindi ottiene un valore di 1. e poi finalmente abbiamo cambiato il valore di q che non cambia in ogni caso il valore di a .