Differenze tra Final, Finalmente e Finalize in Java

1. Panoramica

In questo tutorial, faremo una panoramica di tre parole chiave Java: final, infine e finalize.

Sebbene queste parole chiave si assomiglino tra loro, ognuna ha un significato molto diverso in Java. Impareremo lo scopo di ciascuno di essi e vedremo alcuni esempi attraverso un po 'di codice.

2. Parola chiave finale

Diamo prima un'occhiata alla parola chiave finale , dove usarla e perché. Possiamo applicare la parola chiave finale a dichiarazioni di parametri di classe, metodo, campo, variabile e metodo.

Tuttavia, non ha lo stesso effetto su ciascuno di essi :

  • Fare una classe finale significa che non sarà possibile estendere quella classe
  • L'aggiunta di final a un metodo significa che non sarà possibile sovrascrivere quel metodo
  • Infine, mettere final davanti a un campo, una variabile o un parametro significa che una volta assegnato il riferimento non può essere modificato (tuttavia, se il riferimento è a un oggetto modificabile, il suo stato interno potrebbe cambiare nonostante sia finale)

Un articolo dettagliato sulla parola chiave finale può essere trovato qui.

Vediamo come funziona la parola chiave finale attraverso alcuni esempi.

2.1. Campi, parametri e variabili finali

Creiamo una classe Parent con due campi int , uno finale e uno regolare non finale:

public class Parent { int field1 = 1; final int field2 = 2; Parent() { field1 = 2; // OK field2 = 3; // Compilation error } }

Come possiamo vedere, il compilatore ci vieta di assegnare un nuovo valore a field2 .

Aggiungiamo ora un metodo con un argomento regolare e uno finale:

 void method1(int arg1, final int arg2) { arg1 = 2; // OK arg2 = 3; // Compilation error }

Analogamente ai campi, non è possibile assegnare qualcosa a arg2 poiché è dichiarato final.

Possiamo ora aggiungere un secondo metodo per illustrare come funziona con le variabili locali:

 void method2() { final int localVar = 2; // OK localVar = 3; // Compilation error }

Non accade nulla di sorprendente, il compilatore non ci permette di assegnare un nuovo valore a localVar dopo la sua prima assegnazione.

2.2. Metodo finale

Supponiamo ora di rendere definitivo il metodo2 e di creare una sottoclasse di Parent , diciamo Child , in cui proviamo a sovrascrivere entrambi i suoi metodi di superclasse:

public class Child extends Parent { @Override void method1(int arg1, int arg2) { // OK } @Override final void method2() { // Compilation error } }

Come possiamo vedere, non ci sono problemi con l'override di method1 () , ma otteniamo un errore di compilazione quando proviamo a sovrascrivere method2 () .

2.3. classe finale

Infine, rendiamo finale la classe Child e proviamo a crearne una sottoclasse, GrandChild :

public final class Child extends Parent { // ... }
public class GrandChild extends Child { // Compilation error }

Ancora una volta, il compilatore si lamenta. La classe Child è definitiva e quindi impossibile da estendere.

3. infine Blocca

Il blocco finalmente è un blocco opzionale da utilizzare con un'istruzione try / catch . In questo blocco, includiamo il codice da eseguire dopo la struttura try / catch , indipendentemente dal fatto che venga generata un'eccezione o meno .

È anche possibile usarlo con il blocco try senza alcun blocco catch a condizione di includere un blocco finalmente . Il codice verrà quindi eseguito dopo il tentativo o dopo che è stata generata un'eccezione.

Abbiamo un articolo approfondito sulla gestione delle eccezioni in Java qui.

Ora dimostriamo un blocco finalmente in un breve esempio. Creeremo un metodo fittizio main () con una struttura try / catch / latest :

public static void main(String args[]) { try { System.out.println("Execute try block"); throw new Exception(); } catch (Exception e) { System.out.println("Execute catch block"); } finally { System.out.println("Execute finally block"); } }

Se eseguiamo questo codice, verrà visualizzato quanto segue:

Execute try block Execute catch block Execute finally block

Modifichiamo ora il metodo rimuovendo il blocco catch (e aggiungiamo lanci Eccezione alla firma):

public static void main(String args[]) throws Exception { try { System.out.println("Execute try block"); throw new Exception(); } finally { System.out.println("Execute finally block"); } }

L'output è ora:

Execute try block Execute finally block

Se ora rimuoviamo l' istruzione throw new Exception () , possiamo osservare che l'output rimane lo stesso. Il nostro fine esecuzione del blocco si verifica ogni volta.

4. finalizzare il metodo

Infine, il metodo finalize è un metodo protetto, definito nella classe Object. Viene chiamato dal garbage collector sugli oggetti a cui non si fa più riferimento e che sono stati selezionati per la garbage collection .

Come ogni altro metodo non finale, possiamo sovrascrivere questo metodo per definire il comportamento che un oggetto deve avere quando viene raccolto dal garbage collector .

Di nuovo, un articolo dettagliato sul metodo finalize può essere trovato qui.

Vediamo un esempio di come funziona. Useremo System.gc () per suggerire alla JVM di attivare la garbage collection :

 @Override protected void finalize() throws Throwable { System.out.println("Execute finalize method"); super.finalize(); }
 public static void main(String[] args) throws Exception { FinalizeObject object = new FinalizeObject(); object = null; System.gc(); Thread.sleep(1000); }

In questo esempio, sovrascriviamo il metodo finalize () nel nostro oggetto e creiamo un metodo main () che istanzia il nostro oggetto e rilascia immediatamente il riferimento impostando la variabile creata su null .

After that, we call System.gc() to run the garbage collector (at least we expect it to run) and wait for a second (just to ensure that the JVM doesn't shut down before garbage collector has the chance to call finalize() method).

The output of this code execution should be:

Execute finalize method

Note that it's considered bad practice to override finalize() method as its execution depends on garbage collection which is in the hand of the JVM. Plus, this method has been deprecated since Java 9.

5. Conclusion

In questo articolo, abbiamo discusso brevemente le differenze tra le tre parole chiave simili a Java: final, infine e finalize .

Il codice completo dell'articolo può essere trovato su GitHub.