Domanda

Quali sono i buoni motivi per proibire l'ereditarietà in Java, ad esempio usando le classi finali o le classi usando un unico costruttore privato senza parametri? Quali sono i buoni motivi per rendere definitivo un metodo?

È stato utile?

Soluzione

Il tuo miglior riferimento qui è l'articolo 19 dell'eccellente libro di Joshua Bloch "L'efficace Java", chiamato "Progettazione e documento per ereditarietà o altrimenti vietalo". (È l'articolo 17 nella seconda edizione e l'articolo 15 nella prima edizione.) Dovresti davvero leggerlo, ma lo riassumerò.

L'interazione delle classi ereditate con i loro genitori può essere sorprendente e imprevedibile se l'antenato non è stato progettato per essere ereditato.

Le classi dovrebbero quindi venire in due tipi:

  1. Classi progettate per essere estese e con una documentazione sufficiente per descrivere come dovrebbe essere fatto

  2. Classi contrassegnate final

Se stai scrivendo un codice puramente interno, questo potrebbe essere un po 'eccessivo. Tuttavia, lo sforzo aggiuntivo necessario per aggiungere cinque caratteri a un file di classe è molto ridotto. Se stai scrivendo solo per un consumo interno, un programmatore futuro può sempre rimuovere il "finale" - puoi pensarlo come un avvertimento che dice "questa classe non è stata progettata pensando all'eredità".

Altri suggerimenti

Potresti voler rendere definitivo un metodo in modo che le classi di override non possano cambiare il comportamento che viene contato in altri metodi. I metodi chiamati nei costruttori sono spesso dichiarati finali in modo da non avere spiacevoli sorprese durante la creazione di oggetti.

Un motivo per rendere finale una classe sarebbe se volevi forzare la composizione sull'ereditarietà. Ciò è generalmente auspicabile per evitare l'accoppiamento stretto tra le classi.

Esistono 3 casi d'uso in cui è possibile scegliere i metodi finali.

  1. Per evitare che la classe derivata sovrascriva una particolare funzionalità della classe base.
  2. Questo è per motivi di sicurezza, in cui la classe base fornisce alcune importanti funzionalità di base del framework in cui la classe derivata non dovrebbe modificarla.
  3. I metodi finali sono più veloci dei metodi di istanza, in quanto non viene utilizzato il concetto di tabella virtuale per i metodi finali e privati. Quindi, ovunque ci sia una possibilità, prova ad usare i metodi finali.

Scopo per la conclusione di una lezione:

In modo che nessun organismo possa estendere tali classi e modificarne il comportamento.

Ad esempio: la classe wrapper Integer è una classe finale. Se quella classe non è definitiva, chiunque può estendere Integer nella propria classe e modificare il comportamento di base della classe intera. Per evitare ciò, java ha creato tutte le classi wrapper come classi finali.

potresti voler creare oggetti immutabili ( http://en.wikipedia.org/wiki/Immutable_object ), potresti voler creare un singleton ( http://en.wikipedia.org/wiki/ Singleton_pattern ) o potresti voler impedire a qualcuno di ignorare il metodo per motivi di efficienza, sicurezza o protezione.

L'ereditarietà è come una motosega: molto potente, ma terribile nelle mani sbagliate. O progetti una classe da cui ereditare (che può limitare la flessibilità e impiegare molto più tempo) o dovresti proibirla.

Vedi gli effettivi articoli 16 e 17 della seconda edizione di Java o il mio post sul blog " ; Imposta sulle successioni " .

Hmmm ... posso pensare a due cose:

Potresti avere una classe che si occupa di determinati problemi di sicurezza. Sottoclassandolo e alimentando il sistema con la sua sottoclasse, un utente malintenzionato può eludere le restrizioni di sicurezza. Per esempio. la tua applicazione potrebbe supportare plug-in e se un plug-in può semplicemente sottoclassare le tue classi rilevanti di sicurezza, può usare questo trucco per far entrare in qualche modo una versione della sua sottoclasse. Tuttavia, questo è piuttosto qualcosa che Sun deve affrontare per quanto riguarda le applet e simili, forse non un caso così realistico.

Uno molto più realistico è evitare che un oggetto diventi mutevole. Per esempio. poiché le stringhe sono immutabili, il tuo codice può conservare in modo sicuro riferimenti ad esso

 String blah = someOtherString;

invece di copiare prima la stringa. Tuttavia, se puoi sottoclassare String, puoi aggiungere dei metodi che consentano di modificare il valore della stringa, ora nessun codice può fare più affidamento sul fatto che la stringa rimarrà la stessa se copia la stringa come sopra, invece deve duplicare il stringa.

Impedire alle persone di fare cose che potrebbero confondere se stesse e gli altri. Immagina una libreria di fisica in cui hai alcune costanti o calcoli definiti. Senza usare la parola chiave finale, qualcuno potrebbe venire e ridefinire i calcoli di base o le costanti che non dovrebbero MAI cambiare.

Inoltre, se stai scrivendo una classe commerciale a codice chiuso, potresti non voler che le persone siano in grado di cambiare la funzionalità in linea, specialmente se hai bisogno di fornirti supporto e le persone hanno scavalcato il tuo metodo e si lamentano che chiamandolo si ottengono risultati inaspettati.

Se contrassegni le classi e i metodi come finali, potresti notare un piccolo guadagno in termini di prestazioni, poiché il runtime non deve cercare il metodo di classe giusto per invocare un determinato oggetto. I metodi non finali sono contrassegnati come virtuali in modo che possano essere correttamente estesi se necessario, i metodi finali possono essere direttamente collegati o compilati in linea nella classe.

Desideri rendere definitivo un metodo in modo che le classi di override non cambino il suo comportamento. Quando vuoi essere in grado di cambiare il comportamento, rendi pubblico il metodo. Quando si esegue l'override di un metodo pubblico, è possibile modificarlo.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top