Metodo Java `final`: cosa promette?

In una class Java può essere definito un metodo final , per segnalare che questo metodo non può essere sovrascritto:

 public class Thingy { public Thingy() { ... } public int operationA() {...} /** this method does @return That and is final. */ public final int getThat() { ...} } 

Questo è chiaro, e potrebbe essere di qualche utilità proteggerlo da una sovrascrittura accidentale, o forse dalle prestazioni, ma non è questa la mia domanda.

La mia domanda è: da un punto di vista OOP ho capito che, definendo un metodo final il progettista di class promette che questo metodo funzionerà sempre come descritto, o implicito. Ma spesso questo può essere al di fuori dell’influenza dell’autore della class, se ciò che il metodo sta facendo è più complicato di una semplice proprietà .

Il vincolo sintattico mi è chiaro, ma qual è l’implicazione nel senso OOP? La final è usata correttamente in questo senso dalla maggior parte degli autori di class?

Che tipo di “contratto” promette un metodo final ?

Come accennato, final viene utilizzato con un metodo Java per indicare che il metodo non può essere sovrascritto (per l’ambito dell’object) o nascosto (per statico). Ciò consente allo sviluppatore originale di creare funzionalità che non possono essere modificate da sottoclassi e questa è la garanzia che fornisce.

Ciò significa che se il metodo si basa su altri componenti personalizzabili come campi / metodi non pubblici, la funzionalità del metodo finale potrebbe essere ancora personalizzabile. Questo è buono anche se come (con polimorfismo) consente la personalizzazione parziale.

Ci sono una serie di motivi per impedire che qualcosa sia personalizzabile, tra cui:

  • Prestazioni : alcuni compilatori possono analizzare e ottimizzare l’operazione, specialmente quella senza effetti collaterali.

  • Ottieni dati incapsulati : guarda gli oggetti immutabili dove i loro attributi sono impostati al momento della costruzione e non dovrebbero mai essere modificati. O un valore calcolato derivato da quegli attributi. Un buon esempio è la class String Java.

  • Affidabilità e contratto – Gli oggetti sono composti da primitive ( int , char , double , ecc.) E / o altri oggetti. Non tutte le operazioni applicabili a quei componenti dovrebbero essere applicabili o anche logiche quando vengono utilizzate nell’object più grande. I metodi con il modificatore final possono essere utilizzati per garantire che. La class Counter è un buon esempio.


 public class Counter { private int counter = 0; public final int count() { return counter++; } public final int reset() { return (counter = 0); } } 

Se il metodo public final int count() non è final , possiamo fare qualcosa del genere:

 Counter c = new Counter() { public int count() { super.count(); return super.count(); } } c.count(); // now count 2 

O qualcosa del genere:

 Counter c = new Counter() { public int count() { int lastCount = 0; for (int i = super.count(); --i >= 0; ) { lastCount = super.count(); } return lastCount; } } c.count(); // Now double count 

Che tipo di “contratto” promette un metodo finale?

Guardalo dall’altra parte, qualsiasi metodo non finale fornisce l’ implicita garanzia che puoi sovrascriverlo con la tua implementazione e la class funzionerà come previsto. Quando non puoi garantire che la tua class supporti la sovrascrittura di un metodo, dovresti renderlo definitivo.

Prima di tutto, puoi contrassegnare le classi non astratte come anche i campi e i metodi. In questo modo tutta la class non può essere sottoclassata. Quindi, il comportamento della class sarà risolto.

Sono d’accordo che i metodi di marcatura final non garantiscono che il loro comportamento sarà lo stesso nelle sottoclassi se questi metodi chiamano metodi non definitivi. Se il comportamento deve effettivamente essere risolto, questo deve essere ottenuto per convenzione e attenta progettazione. E non dimenticare di farlo notare in javadoc! (Documentazione java)

Ultimo ma non meno importante, la parola chiave final ha un ruolo molto importante in Java Memory Model (JMM). È garantito da JMM che per ottenere la visibilità dei campi final non è necessaria la sincronizzazione corretta. Per esempio:

 class A implements Runnable { final String caption = "Some caption"; void run() { // no need to synchronize here to see proper value of final field.. System.out.println(caption); } } 

Non sono sicuro che tu possa fare affermazioni sull’uso del “finale” e su come questo influenzi il contratto di progettazione generale del software. È garantito che nessuno sviluppatore può ignorare questo metodo e invalidare il suo contratto in questo modo. D’altro canto, il metodo finale può basarsi su variabili di class o istanza i cui valori sono impostati da sottoclassi e possono chiamare altri metodi di class che sono sovrascritti. Quindi la finale è al massimo una garanzia molto debole.

No, non è al di fuori dell’influenza dell’autore della class. Non è ansible sovrascriverlo nella class derivata, quindi farà ciò che l’autore della class base ha inteso.

http://download.oracle.com/javase/tutorial/java/IandI/final.html

Vale la pena notare la parte in cui suggerisce che i metodi chiamati dai costruttori dovrebbero essere final .